Eric Lu

AngularUI - UI Bootstrap Datepicker and Timepicker Neutral Timezone

November 06, 2015 | 4 Minute Read

It's really disappointing that despite with the latest version of UI Bootstrap (0.14.x), the datepicker and timepicker widgets remain having no timezone support. This post relates to AngularJS and Angular UI Bootstrap (0.14.x), and provides a simple solution to using and storing dates or timings in a timezone-neutral manner.

Why do we need timezone support for datepicker and timepicker?

The datepicker and timepicker widgets inherently use the localized timezones, and if you are merely using them to actually just capture the date or time portion, then you would realize that you are going to have a problem if you are catering to an international audience.

Just for an example, we can have an event in Singapore that is happening on the 25th of December 2015. The event page details are entered in Singapore using the datepicker widget for the event date. The event date that is generated by the datepicker widget is actually 2015-12-24T16:00:00.000Z. Note that the date generated is actually 2015-12-25 in the timezone of Singapore (GMT+8). But if you were in UK, London looking at the event page online, you would see the event date as the 24th of December (2015-12-24) instead, if the date was formatted according to local time.

Of course, there are a few ways of solving this tricky issue. One, you can simply store the localized timezone when the datepicker input was entered such that we can do some timezone conversions when the date is displayed, but you will notice that timezone conversions are not going to be that easy and elegant in AngularJS. Two, why don’t we just convert the generated date by the datepicker input to the exact date in the neutral UTC/GMT timezone before storing it? This would mean that we could store the timings or dates as themselves without needing to worry about timezones, and this is by far a very popular method adopted by many frameworks. Sure, we can add some $scope.$watch code to do that whenever the model of the date changes, but still I’m quite uncomfortable with some unelegant code lying around.

Or even better, it would simply have been awesome if the datepicker and timepicker widgets could just support different timezones out of the box, especially the neutral UTC timezone. But not to worry, here I present a very simple AngularJS directive to patch them up so that the widgets will automatically store dates or timings that are timezone-neutral (UTC).

angular.module('app')
  .directive('datetimepickerNeutralTimezone', function() {
    return {
      restrict: 'A',
      priority: 1,
      require: 'ngModel',
      link: function (scope, element, attrs, ctrl) {
        ctrl.$formatters.push(function (value) {
          var date = new Date(Date.parse(value));
          date = new Date(date.getTime() + (60000 * date.getTimezoneOffset()));
          return date;
        });

        ctrl.$parsers.push(function (value) {
          var date = new Date(value.getTime() - (60000 * value.getTimezoneOffset()));
          return date;
        });
      }
    };
  });

You would need to use the directive on the same HTML elements with the ng-model attributes by adding the datetimepicker-neutral-timezone attribute, something like this:

<input type="text" class="form-control" uib-datepicker-popup="dd-MMMM-yyyy" ng-model="date" is-open="opened" min-date="minDate" close-text="Close" datetimepicker-neutral-timezone />

And for the timepicker:

<uib-timepicker ng-model="time" hour-step="1" minute-step="15" datetimepicker-neutral-timezone></uib-timepicker>

And then to display the date with the AngularJS date filter according to our neutral timezone (UTC):

{{ date | date:null:'UTC' }}

That’s it, you can throw timezone issues to the back of your head.