33

I'm working on an offline capabable Javascript site that targets mobile devices. One such mobile device is the IPhone.

I'm trying to parse a date from our REST API (a member of JSON object). I'm using

Date.parse("2010-03-15 10:30:00");

This works on Android devices, however on IPhone it just gives an invalid date.

How do I need to format my date string so it can be parsed by the IPhone?

Morten
  • 4,507
  • 7
  • 29
  • 31

6 Answers6

102

Not all browsers support the same date formats. The best approach is to split the string on the separator characters (-,   and :) instead, and pass each of the resulting array items to the Date constructor:

var arr = "2010-03-15 10:30:00".split(/[- :]/),
    date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);

console.log(date);
//-> Mon Mar 15 2010 10:30:00 GMT+0000 (GMT Standard Time)

This will work the same in all browsers.

Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 8
    Might be nice to add `T` to your regex to support ISO 8601 – Tomas May 24 '11 at 11:57
  • 1
    Just to clarify, the date will be created in the timezone you exist in, right? E.G. I'm in California and this example gets me: var arr = "2010-03-15 10:30:00".split(/[- :]/), date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]); undefined date Mon Mar 15 2010 10:30:00 GMT-0700 (PDT)... So, I needed to get the timezoneOffset and subtract those minutes from the date returned to get a UTC date. Or am I missing something? – jottos Feb 14 '12 at 00:42
  • @jottos: yes, that's right – there's no time zone information in the string. Note that -0700 isn't 700 minutes, it's 7 hours. So make sure you do that -700 / 100 * 60 = 420 minutes. Then you need to turn that into milliseconds – 420 * 60 * 1000 – before performing the date calculations. – Andy E Feb 14 '12 at 10:10
  • 2
    TY for this, big help. Couldn't get safari on iOS to parse iso8601. This works everywhere. – James Hollister May 27 '12 at 04:25
  • it seems `Date.parse("2010/03/15 10:30:00");` works, says replacing '-' with '/'. – Kinka Apr 28 '13 at 12:18
  • @Kinka: perhaps, but it's not guaranteed to work in all browsers as the formats they accept are implementation dependent (though ES5 compliance requires the ability to format ISO date strings). – Andy E Apr 28 '13 at 13:29
  • 1
    iOS seems to parse ISO8601 fine these days, but it assumes that the provided time is UTC, whereas other browsers don't. Yay. – dmkc Nov 20 '13 at 21:18
  • Updated `/[- :]/` to `/[- :\/]/` – bhagyas Dec 16 '13 at 21:11
  • A better split regular expression is `\D` so it splits on any non–digit character. – RobG May 08 '20 at 22:49
  • on `iOS` - `Safari` and `Chrome` doesn't like `new Date('0001-01-01' + '15:38');` but works fine on every other device. Using the date constructor as stated `new Date(1,0,1,15,38,0,0);` resolved `iOS` issues – Pierre Aug 14 '22 at 17:55
7

For UTC/GMT time, you can try:

    var arr = "2014-10-27T16:05:44+0000".split(/[\-\+ :T]/);

    var date = new Date();
    date.setUTCFullYear(arr[0]);
    date.setUTCMonth(arr[1] - 1);
    date.setUTCDate(arr[2]);
    date.setUTCHours(arr[3]);
    date.setUTCMinutes(arr[4]);
    date.setUTCSeconds(arr[5]);

The date object will display in the proper local timezone when used.

Henry
  • 2,870
  • 1
  • 25
  • 17
  • `-` doesn't need to be escaped at the beginning or end of character classes and `+` doesn't need to be escaped anywhere in character classes. The same as: `/[-+ :T]/` – Sam Nov 23 '15 at 19:26
  • for dates that end in Z: `const arr = isoFormattedString.split(/[\-\+ :TZ]/);` – Elijah Mock Jul 07 '21 at 22:50
3

You might have better luck if you stick to ISO 8601 format:

Date.parse("2010-03-15T10:30:00");

// e.g.
var d = new Date( Date.parse("2010-03-15T10:30:00") );
console.log( d.toString() ); //Mon Mar 15 2010 10:30:00 GMT+0000 (BST)
meouw
  • 41,754
  • 10
  • 52
  • 69
1

Update 2019-07-29: Not removing existing content below, but I highly suggest you don't use this method. I learned from my mistakes. Do not override JavaScript's existing methods. Becomes bad for your code's portability and performance. If you can't get ISO 8601 (which is standard practice in JS and most API's) - then change that system instead. Alternatively, write your own function, which always has to be called to generate a Date object.


If you can correct your REST API to send down proper ISO 8601 date times, the proper way to handle this is to use a regex shim that allows all browsers to process ISO 8601 dates. Sure it might be slower, but handling dates with Javascript is like trying to get a cat into a tub of water.

Keep in mind the following method overrides the original Date.parse method. This could be problematic in larger projects or with many developers with different expectations. Use only if you're aware of what you're doing.

/**
 * Date.parse with progressive enhancement for ISO 8601 <https://github.com/csnover/js-iso8601>
 * © 2011 Colin Snover <http://zetafleet.com>
 * Released under MIT license.
 */
(function (Date, undefined) {
    var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
    Date.parse = function (date) {
        var timestamp, struct, minutesOffset = 0;

        // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
        // before falling back to any implementation-specific date parsing, so that’s what we do, even if native
        // implementations could be faster
        //              1 YYYY                2 MM       3 DD           4 HH    5 mm       6 ss        7 msec        8 Z 9 ±    10 tzHH    11 tzmm
        if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
            // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
            for (var i = 0, k; (k = numericKeys[i]); ++i) {
                struct[k] = +struct[k] || 0;
            }

            // allow undefined days and months
            struct[2] = (+struct[2] || 1) - 1;
            struct[3] = +struct[3] || 1;

            if (struct[8] !== 'Z' && struct[9] !== undefined) {
                minutesOffset = struct[10] * 60 + struct[11];

                if (struct[9] === '+') {
                    minutesOffset = 0 - minutesOffset;
                }
            }

            timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
        }
        else {
            timestamp = origParse ? origParse(date) : NaN;
        }

        return timestamp;
    };
}(Date));

https://github.com/csnover/js-iso8601

MikeMurko
  • 2,214
  • 1
  • 27
  • 56
0

There is bug in the

var date = new Date();
date.setUTCFullYear(arr[0]);
date.setUTCMonth(arr[1] - 1);
date.setUTCDate(arr[2]);
date.setUTCHours(arr[3]);
date.setUTCMinutes(arr[4]);
date.setUTCSeconds(arr[5]);

approach. If Date() is the end of month and the month set has less days then the result is one month out.

-1

Wrapping Up with the string will do the magic. Since the safari has some unique way of parsing and formatting date

Date.parse(String("2010-03-15 10:30:00"));

Still facing issue use the Moment.js

Happy to help. :-)