Datetime Timezone Handling in Lucee CFML

Today I came across an issue which I’m sure I’ve had previously, many years ago, but I couldn’t remember how to solve it and what the correct way to handle it was.

The issue was I had a datetime string, from a third party source, which I know they where giving in a particular timezone, but as it is just a string, it doesn’t specify the timezone, just the date and time, for example:

2019-05-24 13:00:00

Now, without knowing the timezone of the string, wherever you are in the world this is 1pm on the 24th May 2019, but without the context of the timezone, it is not possible to say what this means for people in different timezones, e.g. someone in London, UK compared to someone in New York, USA. However, if you know the timezone for the time string you would be able to convert it from one to another.

The timezone of the datetime in question, in this case, was PST, Pacific Standard Time, or West Coast USA as many of us might understand it and I needed to output in as GMT/BST so it was the time for someone in the UK, altered for daylight saving as appropriate.

I wasn’t really sure how to do this so I took a quick look at the Lucee Docs and found a few date functions that I thought might help, mainly lsDateTimeFormat(), lsDateFormat() and lsTimeFormat(), which all have attributes for locale and timezone, but I couldn’t see how you would make use of these to convert the datetime string I had from PST to GMT/BST.

I then noticed the dateConvert() function and thought I was on to something, given its name, but upon looking at the documentation page for the function there is a warning, essentially not to use it, plus it only converts from UTC to server local, so not really any help.

What I needed was something where I can give it a datetime string, the timezone that string is from and the timezone I wanted the output to be in, but I seemed to be out of luck as that function doesn’t exist.

I hit up Lucee core developer Michael Offner and explained my issue and what I was trying to do and he explained all and it really is pretty simple.

If you use the lsDateTimeFormat(), lsDateFormat() and lsTimeFormat() functions with the timezone attribute and that timezone attribute is different from the timezone your server is in, then Lucee will assume the timezone your server is in is the timezone of the datetime passed and convert away.

That wasn’t very helpful in my situation, as the timezone of the server was not PST, however, if you create a Lucee datetime object using the lsParseDateTime() function and use the timezone attribute to specify the timezone of the string and then use the lsDateFormat() and lsTimeFormat() function, Lucee will use the timezone passed in the lsParseDateTime() function as the base timezone for that datetime string and convert from there, like this:

<cfscript>
pst_date = lsParseDateTime(date: '2019-05-24 13:00:00' , timezone: 'PST');
gmt_date = lsDateTimeFormat(date: pst_date , timezone: 'GMT'));
</cfscript>

The resulting datetime from the lsDateTimeFormat() function is then:

24-May-2019 20:00:00

However, this is incorrect as in May, the UK is no longer in GMT but in BST (British Summer Time), so this conversion is one hour out, but there is an easy solution, you can specify the timezone as a TZ database name instead and it will automatically know if daylight saving needs to be applied, like this:

<cfscript>
pst_date = lsParseDateTime(date: '2019-05-24 13:00:00' , timezone: 'PST');
gmt_date = lsDateTimeFormat(date: pst_date , timezone: 'Europe/London'));
</cfscript>

The resulting datetime from the lsDateTimeFormat() function is then:

24-May-2019 21:00:00

Which is the correct result, no matter whether or not it is during daylight saving.

Going back to the lsDateTimeFormat(), lsDateFormat() and lsTimeFormat() and the locale attribute they have, what is the use of that? Well, that tells Lucee to convert something in the string to a local representation of it, so for example if you set the locale attribute to “de_ch”, instead of getting “May” in the output string, you will get “Mai” instead, e.g.:

lsParseDateTime(date: '2019-05-24 13:00:00' , locale: 'de_ch');

Gives the output:

24-Mai-2019 13:00:00

Which of course is very useful for any sites supporting local languages.

After speaking with Michael, he pointed me at a video he made all about this, so if you want more details I would suggest giving it a watch:

Thanks to Michael for taking his time to explain this all to me, he really could have just sent me the link to the video, but he instead spent some time to explain it to me personally, which I’m extremely grateful for. I will also try to give a little back by updating the docs to explain this all a little better.

3 Replies to “Datetime Timezone Handling in Lucee CFML”

  1. This stuff is complicated; and, for some reason, it’s one of those things that never seems to get easier in my head 😀 Thanks for linking to the TimeZone video, I’ll give that a watch.

    Reply

  2. And very nice is also a bug, which shows in a used thread a different timezone than server defaults…
    => server is Europe/Berlin
    and when you use a thread in a request, from that point on the whole request is using UTC.

    Quite nice and buggy…

    Reply

    1. Do you mean inside a <cfthread> the timezone defaults to UTC?

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *