Search code examples
javascripttimezonetimestampmicroformats

How can I convert datetime microformat to local time in javascript?


I have a page that is currently using the datetime microformat to display a timestamp, but I have only been showing the human-readable time for my own time zone:

<abbr class="published" title="2009-01-09T09:16:00-05:00">
Friday, January 9, 2009 at 9:16 am (EST)</abbr>

What I'd like to do is rewrite the innerHTML for the abbr tag to be the same format, but in the user's local timezone. So for a reader in Seattle, the above should be converted to:

<abbr class="published" title="2009-01-09T09:16:00-05:00">
Friday, January 9, 2009 at 6:16 am (PST)</abbr>

I've looked at the Javascript Date object, which allows me to get the local timezone offset. But I have a few problems:

  1. I don't see an easy way to create a new Date object from an ISO-8601 timestamp. (I suppose I could parse with substrings or regex if there's no faster way.)

  2. I don't see a way to get the named abbreviation for the timezone. For example, for a reader in Seattle, I'd want the time to have "(PST)" appended to the end, otherwise it is not clear to that user that the timestamp has been converted (especially if he is a frequent visitor and has become accustomed to the fact that my times are in EST).


Solution

  • Here is code of mine that parses an ISO timestamp:

    function isoDateStringToDate (datestr) {
      if (! this.re) {
        // The date in YYYY-MM-DD or YYYYMMDD format
        var datere = "(\\d{4})-?(\\d{2})-?(\\d{2})";
        // The time in HH:MM:SS[.uuuu] or HHMMSS[.uuuu] format
        var timere = "(\\d{2}):?(\\d{2}):?(\\d{2}(?:\\.\\d+)?)";
        // The timezone as Z or in +HH[:MM] or -HH[:MM] format
        var tzre = "(Z|(?:\\+|-)\\d{2}(?:\\:\\d{2})?)?";
        this.re = new RegExp("^" + datere + "[ T]" + timere + tzre + "$");
      }
    
      var matches = this.re.exec(datestr);
      if (! matches)
        return null;
    
      var year = matches[1];
      var month = matches[2] - 1;
      var day = matches[3];
      var hour = matches[4];
      var minute = matches[5];
      var second = Math.floor(matches[6]);
      var ms = matches[6] - second;
      var tz = matches[7];
      var ms = 0;
      var offset = 0;
    
      if (tz && tz != "Z") {
        var tzmatches = tz.match(/^(\+|-)(\d{2})(\:(\d{2}))$/);
        if (tzmatches) {
          offset = Number(tzmatches[2]) * 60 + Number(tzmatches[4]);
          if (tzmatches[1] == "-")
            offset = -offset;
        }
      }
    
      offset *= 60 * 1000;
      var dateval = Date.UTC(year, month, day, hour, minute, second, ms) - offset;
    
      return new Date(dateval);
    }
    

    Unfortunately, it doesn't handle timezone abbreviations either. You would have to modify the "tzre" expression to accept letters, and the only solution I know of to deal with timezone abbreviations in Javascript is to have a look-up table which you keep up to date manually in the event of changes to regional daylight savings times.