The sample code used in this post can be found here.
TimeZoneInfo
.NET Standard, .NET Framework and .NET Core have the TimeZoneInfo
class that represents any time zone in the world. Here are the list of available time zones:
Each time zone has its own offset value. For example, AUS Eastern Standard Time
(AEST) has +10 hours offset value. This TimeZoneInfo
instance also contains daylight saving information, so we don’t have to worry too much about calculating it. Therefore, we can simply use this and easily convert UTC to a designated local time like:
Now, we know how to apply the time zone value. Let’s write Azure Functions code for it.
Azure Functions Core 2.0
Azure Functions now supports .NET Core 2.0 as public preview. Why not using this feature? Basically, it’s the same as the previous version, so there’s no reason not to use, unless we have a specific reason against it. When we create a new Azure Functions project in Visual Studio, nothing has been changed except choosing the .NET framework version:
Choose .NET Core then HTTP trigger, and write the conversion code like:
This code doesn’t make differences from the one above, except the JSON deserialisation part. Azure Functions uses Json.NET library for JSON objects serialisation/deserialisation, and Json.NET has a default behaviour that converts ISO8601 date/time string into DateTime
instance. Therefore, in order to avoid automatic conversion from date/time formatted string to DateTime
instance, we should explicitly pass the DateParsHandling.None
option during the deserialisation like that. Once deployed, it passes a JSON input and output like:
If we want to use the GET
method, instead of POST
, then we should pass the date/time string through its querystring. In this case, the date/time string, 2018-02-01T02:26:02.727Z
for example, MUST be URL encoded, which will be 2018-02-01T02%3a26%3a02.727Z
.
Logic Apps Integration
There’s no action in Logic Apps for this time zone conversion at the time of this writing. In other words, we need to implement a custom action, which can be an Azure Function like above. By the way, we need to know this interesting fact. Logic Apps supports Azure Functions out-of-the-box but webhook triggers only. Azure Functions Core 2 has dependencies onto ASP.NET Core 2 that hasn’t implemented webhooks migration yet. This implies:
- If you want to use OOTB Logic App’s action for Azure Functions, you MUST write the Azure Functions app using .NET Framework, instead of .NET Core.
- If you want to use .NET Core based Azure Functions, you MUST use a normal HTTP action in Logic App to call Azure Functions.
If I am asked to write a custom Logic App action using Azure Functions, I will choose a normal HTTP trigger, because:
- I can write the code on both .NET Framework and .NET Core, and
- I can parameterise the Function endpoint in Logic App. If I use Logic App’s Function action, the endpoint can’t be parameterised at the time of writing.
With having this in mind, the completed Logic App workflow might look like:
As mentioned above, we just use an HTTP action to call Azure Functions.
So far, we have walked through how UTC can be converted to local time zone using Azure Functions and Logic Apps. Especially, in the integration world, keeping the time zone from one source to another is somewhat critical, so I hope this small tip would help.
UPDATE
Kevin Lam from Microsoft pointed me out that there are WDL functions to convert time zone.
While these WDL functions are not documented at this time of writing, it’s worth trying and comparing to the result from the Function app. Update the Logic App workflow by adding a Compose
action right after the HTTP action like:
And the code around the Compose
action might look like:
After running this updated Logic App, we can get converted value from both Logic App and Function App.
Did you find any difference between the outputs from Logic Apps and Functions? Logic App returns DateTime
value, while Function returns DateTimeOffset
value. If we change the output format from 'o'
to 'yyyy-MM-ddTHH:mm:ss.fffzzz'
to resemble the DateTimeOffset
format, then it returns:
That doesn’t make sense to me, because the conversion has lost the time zone offset information, which DateTimeOffset
keeps it. Therefore, if we want to get a correct local date/time value including time zone offset information, using Azure Functions is still the only way for now. This seems to be a bug and hopefully Microsoft has already identified this issue and fix it sooner rather than later.
This has been cross-posted to Dev Kimchi