Angularjs display timestamp date in different timezones

I can properly display a selected timestamp to the local time for that timestamp by just using date:'medium'.

What I want to achieve though is displaying this timestamp in a certain timezone, for example UTC+03:00 or GMT+03:00 just to give an example.

I have tried to use

  • date:'medium':'UTC+03:00'
  • date:'medium':'UTC+0300'
  • date:'medium':'GMT+03:00'
  • date:'medium':'GMT+0300'
  • date:'medium':'+03:00'
  • date:'medium':'+0300'

None of these seem to change the timestamp time to the time it would be in that timezone.

Reason: displaying the time to the user's preferred timezone setting, even if they are currently in a country with another timezone.

Does anyone know how I can properly display the timestamp to a specified timezone?

The important thing to know about Javascript is that all the references to timezones refer to the timezone on the system where the code is being executed, of which you have no control. You can't even trust the client machine to have the correct timezone set. So when you select an option to display a timezone, all that can be done is give you the client's timezone.

Timezones in JavaScript can get complicated, here a blog post that goes into quite some detail and provides solutions.

One simple way to handle timezones is to store all my dates in UTC, and then format them using the moment.JS library when it comes time to display them. Assuming all your times are stored in UTC, you could use a filter like the one I've written in this plunker to format your dates and manipulate them to the user's preferred timezone. Here is just the sample filter code:

// filter to set the timezone, assumes incoming time is in UTC
angular
  .module('plunker')
  .filter('toUserTimezone', function() {
    return function(input, format, offset) {

      var output, timezoneText, inputCopy;

      // we need to copy the object so we don't cause any side-effects
      inputCopy = angular.copy(input);

      // check to make sure a moment object was passed
      if (!moment.isMoment(inputCopy)) {
        // do nothing
        return input;

      } else {
        // set default offset change to 0
        offset = offset || 0;

        // change the time by the offet  
        inputCopy.add(offset, 'hours');

        // this will need to be improved so the added text is in the format +hh:mm
        offset >= 0 ? timezoneText = '+' + offset : timezoneText = offset;

        // format the output to the requested format and add the timezone 
        output = inputCopy.format(format) + ' ' + timezoneText;

        return output;
      }
    };
  });

The moment library is quite nice, anytime I have to work with dates I'll include it, as it is small. It also has some quite powerful timezone tools. You could expand the filter above using the timezone tools to make it work with DST and timezones with offsets that aren't exactly one hour, such as India.

UPDATE: After looking at the moment timezone library, we can actually simplify the filter code. The first solution was more of a hack, this solution is much more robust as we will keep the orginal timezone data. Also, I've broken the formatting and timezone conversion into two separate filters. You can see a demo in this plunker.

Here is a filter to convert timezones:

angular
  .module('plunker')
  .filter('convertTimezone', function() {
    return function(input, timezone) {
      var output;

      // use clone to prevent side-effects
      output = input.clone().tz(timezone);

      // if the timezone was not valid, moment will not do anything, you may
      // want this to log if there was an issue
      if (moment.isMoment(output)) {
        return output;
      } else {
        // log error...    
        return input;
      }
    };
  });

The timezone library allows you to pass a string to the moment.tz() method, if that string is known the conversion will happen, if not no change will be made. The clone() method is a better way of preventing side-effects then using angular.copy as I did before.

Now here is the new format filter, similar to before:

angular
  .module('plunker')
  .filter('formatTime', function() {
    return function(input, format) {

      // check to make sure a moment object was passed
      if (!moment.isMoment(input)) {
        // do nothing
        return input;
      } else {
        return input.format(format);
      }
    };
  });

In summary, the moment timezone library is quite useful!

According to the Angular Docs:

Timezones

The Angular datetime filter uses the time zone settings of the browser. The same application will show different time information depending on the time zone settings of the computer that the application is running on. Neither JavaScript nor Angular currently supports displaying the date with a timezone specified by the developer.

Did you take a look at momentjs and/or angular-moment?