Javascript date parsing on Iphone
Asked Answered
K

6

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?

Kindliness answered 16/3, 2011 at 10:47 Comment(1)
Try this solution, it worked for me: https://mcmap.net/q/36919/-safari-js-cannot-parse-yyyy-mm-dd-date-formatCircuitry
I
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.

Italy answered 16/3, 2011 at 10:54 Comment(10)
Might be nice to add T to your regex to support ISO 8601Quite
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?Selmner
@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.Italy
TY for this, big help. Couldn't get safari on iOS to parse iso8601. This works everywhere.Adjudicate
it seems Date.parse("2010/03/15 10:30:00"); works, says replacing '-' with '/'.Berbera
@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).Italy
iOS seems to parse ISO8601 fine these days, but it assumes that the provided time is UTC, whereas other browsers don't. Yay.Kopje
Updated /[- :]/ to /[- :\/]/Corrigendum
A better split regular expression is \D so it splits on any non–digit character.Wieche
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 issuesGerminate
K
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.

Kali answered 27/10, 2014 at 21:19 Comment(2)
- 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]/Ferminafermion
for dates that end in Z: const arr = isoFormattedString.split(/[\-\+ :TZ]/);Work
A
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)
Aniline answered 16/3, 2011 at 10:57 Comment(5)
If you want it to work in desktop browsers, most versions of IE won't parse that date.Italy
Neither will Android or IPhone mobile-Webkit browsers.Kindliness
Works on Android 2.3 and up (but no luck on iOS 5 and 6)Superannuate
Additionally, in ES5 this parsing method assume UTC timezone. In ES6 it will be local timezone. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Ent
This works in 2022, unbelievable!Honeyhoneybee
B
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

Broken answered 20/8, 2012 at 3:38 Comment(0)
C
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.

Clay answered 1/8, 2021 at 7:23 Comment(0)
G
-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. :-)

Gorlicki answered 30/9, 2020 at 16:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.