Time is an illusion but TimeZones are not.

Recently I have been working on handling timezones on a client project. Front end is AngularJs 1.3 and backend api is Rails api.

It is a very common scenario. User chooses what timezone the data should be displayed in. Api saves and returns all the dates in UTC format.

There are also a lot many client side validations comparing saved time with local time (in all permutation and combinations possible).

Tools used:

  1. Javascript Date object:
    new Date();

    While working with timezones, it is always good to know that Javascript Date object is always in local time zone. There is no direct option to set the timezone. You can change time by adding/subtracting timezone offset.

  2. moment.js: moment is a javascript library which provides pretty options to format the moment date object which is not possible with javascript Date object.
  3. moment-timezone.js: This library allows you to convert moment time object in different timezones.
    moment.tz("2015-12-23 20:30:00", "US/Central")

 

My approach:

  • Keep all the times in local timezone, whatever that may be .. the browser figures that out and by default all the times are in local timezone.
  • All the comparison of different time objects should be done when all the objects are in same time zone and preferably in local time zone.
  • When submitting the form, change the time zone of the time objects from local timezone to desired timezone. Will explain in more detail later.
  • When doing a get request of the resource(i.e the edit page of lets say business profile), change all the time objects to time in local timezone.

Reasons for the approach:

There are 2 main things that I am doing. First I am changing all time objects to time objects in desired timezone. And second, I am converting all the time objects in local timezone.

These are 2 different things.

In first case, I am doing this:

make_double_digit = function(num) {
  if(num < 10) {
    return ("0" + String(num));
  }else{
    return String(num);
  }
}

var start_time = new Date();
var year = String(start_time.getFullYear());
var month = make_double_digit(start_time.getMonth() + 1);
var day = make_double_digit(start_time.getDate());
var time_hour = make_double_digit(start_time.getHours());
var time_min = make_double_digit(start_time.getMinutes());
var time_sec = make_double_digit(start_time.getSeconds());

var new_date_format = [year, month, day].join('-') + " " + [time_hour, time_min, time_seconds].join(':');

return moment.tz(new_date_format, zone_name);

For ex: let start_time be 2015-dec-21 8:30:00 IST. So I am extracting year, month etc  from this date object and asking moment to return moment object for this string “2015-12-21 08:30:00” in US/Central timezone. It is not converting start_time to US/Central timezone but rather building time object in US/Central timezone.

In second case, I am doing this:

var timezoned_start_date = moment(vm.info.start_date).tz('US/Central');

var start_date = new Date();
start_date.setYear(timezoned_start_date.format('YYYY'));
start_date.setMonth(timezoned_start_date.format('MM') - 1);
start_date.setDate(timezoned_start_date.format('DD'));
start_date.setHours(timezoned_start_date.format('hh'));
start_date.setMinutes(timezoned_start_date.format('mm'));
start_date.setSeconds(timezoned_start_date.format('ss'));

I am converting the time object obtained in response which is in UTC format to US/Central time zone. and then building a javascript Date object from it.

Now start_date object is in local time zone and we can use this to compare it with Date objects as needed.

Conclusion:

Dealing with timezones is not very straight forward. And this is not the only way to do it. A lot of people(read StackOverflow) suggested that I convert timezones by adding/subtracting timezone offsets. I found this to be more easy to manage in future and for other team mates to understand.