4 min read

Converting UTC to Local Time via Azure Functions and Logic Apps

Justin Yoo

In many information system development scenarios, including integration scenarios, handling date/time value is always problematic. If your information systems reside in your office or data centre located in your area, that won't bring about too much trouble. However, if your organisation runs applications in several different regions, which implies different time zones, date/time values when exchanging data result in a lot of headaches. Applications running on cloud, in order to figure out this issue, usually uses UTC, which is fine. However, let's think about a scenario that cloud applications need to exchange data with on-prem legacy applications that only takes local date/time values. In this case there must be some conversion logic around. In this post, we're going to write a sample Azure Functions code and Logic Apps for those conversions.

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:

https://gist.github.com/justinyoo/39e18fac1ecedf2cf776e85d730e6633

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:

https://gist.github.com/justinyoo/cac53708da40e1c8535b9d4237fee605

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.

ACKNOWLEDGEMENT: This post has originally been posted at Mexia blog.