Converting Dates Across Time Zones Using ColdFusion And Java

This week has been a very immersive week in world clocks, time zones, and the absurdly inconsistent rules of Daylight Saving Time (DST). After several days of complete befuddlement, I was finally able to gain some understanding of how all this timezone logic fits together. Yesterday, I talked about using Java's java.util.TimeZone and java.util.GregorianCalendar classes to help navigate through dates and time without having to worry about local timezone and daylight saving time (DST) rules. Today, I wondered if I could use the java.util.GregorianCalendar class in order to easily convert date and times between time zones.

As I was looking at the calendar class, I noticed two functions that might be really helpful:

getTimeInMillis() :: long

setTimeInMillis( long )

In both of these functions, the "long" data type is the number of UTC milliseconds from Epoch. While I haven't yet fully wrapped my head around the concepts of UTC and Epoch, what I have gathered is that this value is always the same, all around the world, regardless of any particular local time. In ColdFusion, this "long" value can be easily obtained from the method:

getTickCount()

Given the fact that I can both Get and Set the date of a Java calendar using this normalized Epoch offset, I wondered if I could set the date of one calendar using the date of another calendar. To test this, I created a calendar in the Eastern Standard Time (EST) timezone (where my server is located). Then, I created two additional calendars for Pacific Standard Time (PST) and Arizona Time. While Pacific Standard Time is three hours less than Eastern Standard Time, it should be the same as Arizona time since Arizona does not adhere to Daylight Saving Time (DST) rules.

In other words, if it's 12PM on the east coast, it should be 9AM in both California and Arizona.

Once I have my EST calendar, I then use its "time in milliseconds" to set the date for the PST and Arizona calendars:

<cffunction

name="calendarToString"

access="public"

returntype="string"

output="false"

hint="I take a given instance of java.util.GregorianCalendar and return a readable date/time string.">

<!--- Define arguments. --->

<cfargument

name="calendar"

type="any"

required="true"

hint="I am the Java calendar for which we are creating a user-friendly date string."

At the top of this code, you'll notice that I have a function for formatting the date/time of a particular calendar. I need to do this because any attempt to use ColdFusion's dateFormat() or timeFormat() functions will end up formatting the date in the server's timezone (EST), not the given calendar's timezone.

Once I have the Eastern Standard Time (EST) calendar created, you can see that I am feeding the getTimeInMillis() return value of the EST calendar directly into the setTimeInMillis() method of the other two calendars. Doing this results in the following three date/time values:

As you can see, using the UTC-normalized Epoch offset, I was able to translate date/time values across time zones without having to worry about any of the GMT offsets and Daylight Saving Time (DST) rules! That's pretty awesome!

As you can see, we first convert the true Epoch to our server's Epoch using dateConvert(). Then, we simply add the number of milliseconds as defined by the Arizona calendar's getTimeInMillis() to the localized Epoch. Running the above code gives us the following date/time output:

Server Date: 09/23/2011 at 10:41 AM

As you can see, we got the same date/time as the Eastern Standard Time (EST) calendar from above.

Slowly, I'm starting to make heads and tails of all this timezone stuff. And, being able to dip into the Java layer definitely makes this a world easier than it would be otherwise. Now that I have a better understanding of how all the Epoch offset stuff works, I should be able to start fooling around with some database integration.

Reader Comments

Why not just use the LSParseDateTime format to get the date/time in the format of the current locale? I then take that date/time and set it to GMT and then make tweaks based on the current person's locale using LSDateFormat and LSTimeFormat.

This gives you the output that you need based on the locale of the person inputting the data and allows you to save it to the server in the server's locale.

When displaying to new users it will display in their locale.

We had a system that was multi-lingual and had to work across the globe and this is the route that we went with.

I've never actually used any of the LS* functions. In fact, other than UTF-8 encoding for characters, this timezone exploration is really the first time I've looked at any of the globalization or localization functions. I'll definitely be taking at look at this LS* functions if you say they are valuable. Thanks!!

@Ben, I am glad you are making some Java posts since my company will soon be integrating and changing to Java, so there's another language I will be using your site for...I already use it for JQuery, css, ajax, database stuff, and ColdFusion. Why not Java, too? Love your Java stuff. Keep it coming. :-)

Thanks for sharing this approach. I will be looking into doing some heavy-duty localization efforts, and date/time stuff is a big piece that I am dreading. Looking forward to anything else that you'll write up, especially with the database stuff!

@Ben, because of course it is all about me. :-D haha. But seriously, hopefully, by the time we change our code over to Java, there will be enough stuff on here to float me on through. I have to admit, I'm a little nervous about it. But it's not like I have never had Java education before, so I am hoping I can lean on that, besides your site of course. :-) And I am a little excited about it, just a little anxious, too.

This all go started because I wanted to schedule some time-based SMS integration :) That quickly lead down the rabbit hole. Been banging my head against this all week! Just happy to be making *some* headway. I'll be posting anything I find.

@Anna,

Just remember, ColdFusion sits on top of Java... so if you can do it in CF, you can do it in Java ... with 100x more code :P

@Danyal,

Yeah, the concept of thread-safe objects definitely is beyond my understanding of programming, at least at any real concrete level. I'll take a look at that link - thanks!

Thanks for that little piece of advice. I just wish some action would be taken. I am quite frankly kind of sick of listening to them bicker on the phone about whether ColdFusion could do this or that. The Java guys are pushing us to go to Java, because they claim that ColdFusion wasn't shipped with the latest version of Java, and so they are determined that we will be doing Java, so Java it is. They are saying that there are certain things that need to be done that can't be done using ColdFusion. Whatever. I'm just sick of all of the arguing. This is what made me sick of politics. lol. I guess it is just a different kind of politics now -- office politics.

When you have a rep (an object) that can't do everything in one shot, then you have to make sure that you don't let the rep get interrupted. He doesn't know the difference between customers(threads) because he can only ask one question at a time, so you have to wall off each thread.

So OK, minor Java explanation aside, what does it mean for CF people? Well ... um ... we don't write Java to call DateFormat, so we don't have a direct way to address that. My recommendation would be this: until you have a problem with DateFormat not returning the right date, don't worry about it. YAGNI. If it happens, you might be able to wrap that formatting code in a cflock to resolve the problem. (In an environment where concurrency is important, but order is also important, you might have to implement some sort of queue into which requests are placed, wrap the queue in a lock, and then process requests only from the queue.)

Ahh, I see what you're saying. Yeah, since it appears to be one call on our end, it's not entirely apparent that behind the scenes it's making several calls to the same object for various points of data.

To be safe, I suppose I would just create a new DateFormatter and Date for each instance that I might need to use it. Probably, in a top-down page, I wouldn't see this being too much of a problem, though.

Right ... your example certainly doesn't need it, and people who want to adapt it to what they're using can always look at how it works to see if they might need some kind of locking mechanism.

I think this is another one of those things like you've said before: here's one way you can do something, a proof-of-concept type page. If you want to use it in a production environment, look it over carefully like you would any other existing code and adapt it to your needs.

@Ben, In case you don't know yet, gmt = Greenwich Mean Time which is the international date line or UTC or Zulu time. All those terms equate to UTC 0 and EST (Eastern standard time) is -6, EDT (daylight) is -5 if I recall correctly.

The Timezone.cfc came up in my first few Google queries; but, I didn't really have a solid enough understanding of how time zones worked in general (and the massive diversity of them). I think I just needed to get a formal understanding of how world time was implemented before I started to look at any form of encapsulation.

Now that I've had a week of digging and some blog posts on top of it, I might try my own hand at some encapsulation.

@Randall,

I'm starting to wrap my head around all of this :) Slowly, steadily, the insanity is starting to make more sense.

I am using this and it is working great locally but when i post it to my production server it is not working. I am using osx locally and centos in production. any idea why this is not working? I'm betting my head against the wall :(:(