275
 alert(new Date('2010-11-29'));

chrome, ff doesn't have problems with this, but safari cries "invalid date". Why ?

edit : ok, as per the comments below, I used string parsing and tried this :

alert(new Date('11-29-2010')); //doesn't work in safari
alert(new Date('29-11-2010')); //doesn't work in safari
alert(new Date('2010-29-11')); //doesn't work in safari

edit Mar 22 2018 : Seems like people are still landing here - Today, I would use moment or date-fns and be done with it. Date-fns is very much pain free and light as well.

Shrinath
  • 7,888
  • 13
  • 48
  • 85
  • Just for other looking at same problem : I ended up using DateJS, which solved my problem overall.. See accepted answer for details. – Shrinath Dec 29 '10 at 05:24
  • 3
    use [moment.js](http://momentjs.com/docs/) to parse the timestamp. Especially when dealing with cross platform web – Ming Yuen Aug 07 '13 at 05:52
  • 2
    This is an old question. As of ECMAScript 2015, ISO 8601 date-only strings are parsed as UTC. However, there may still be older browsers around that will either not parse it at all or treat it as local. – RobG Mar 14 '17 at 06:07
  • [What are valid Date Time Strings in JavaScript?](https://stackoverflow.com/questions/51715259/what-are-valid-date-time-strings-in-javascript) – str Oct 18 '19 at 08:28
  • 1
    As mentioned in the question "alert(new Date('29-11-2010')); alert(new Date('2010-29-11'));" These two format does not work in Firefox/Chrome either. So these two formats are completely wrong I think and should not be used at all. – Sandeep Agrawal Oct 09 '20 at 06:38

23 Answers23

403

For me implementing a new library just because Safari cannot do it correctly is too much and a regex is overkill. Here is the oneliner:

console.log (new Date('2011-04-12'.replace(/-/g, "/")));
Elzo Valugi
  • 27,240
  • 15
  • 95
  • 114
  • If getting a slash was only my problem, then I'd have 'accepted' your answer (although it was my only aim when I asked this question). Now that I found dateJS, I implemented MMM DD, YYYY format for a more user friendly experience!!! – Shrinath Apr 14 '11 at 07:36
  • 21
    This one line help was perfect for my need! Thanks! – Cyril N. Jul 04 '12 at 09:53
  • 4
    This was simple enough for me as well. Can't believe Safari doesn't like the - but the same format with a \\ works. Thanks @Elzo and thanks Shrinath for posting the question – Pete Jun 21 '13 at 12:10
  • 1
    I think this is the best answer I tend to forget /-/g instead of '-' – Jacek Pietal Oct 10 '14 at 15:37
  • 31
    *applause* for not implementing a library. – lharby Feb 20 '17 at 11:34
  • 2
    i still not get why people wants to use a whole library for a single use.kudos for not implementing one. – Shoyeb Memon Nov 26 '18 at 06:29
  • @Tim technically true, although I think internal functions like string.replace are more optimized and may not go through the regex engine – Elzo Valugi Mar 21 '19 at 09:10
  • I don’t know why, but it gave out a day less than necessary: if just `new Date('2011-04-12')` --> 2011-04-12 and your code 2011-04-11 for '2011-04-12'. I used `.toISOString()` – Илья Зеленько Nov 10 '19 at 21:48
  • That answer was exactly where I needed it! – Alessandro Jan 20 '20 at 23:21
  • I use this solution all the time, even when using a library, because the latest version of date-fns requires a new Date() constructor to be passed in for the date argument, as opposed to just a string, so it's kinda back to square one, but apart from fixing this issue, the slash instead of the dash is actually a key change whenever you want to prevent time-zone issues when displaying a date, if you often create a date with a string like YYYY-MM-DD and get a date one day before the date you wanted, the slashes removes the timezone – xunux Apr 29 '20 at 02:28
  • This should be the accepted answer. There is no need for a library or any complex solution. It's simple like this. – savram Jan 02 '21 at 20:16
  • 2
    But it's not the same!! new Date('2011-04-12'.replace(/-/g, "/")) is midnight local time, and new Date('2011-04-12') is midnight GMT. I can't believe nobody pointed it out in the last 10 years!!! – Quuxuu Jun 25 '21 at 03:15
  • For me, extra white spaces were the issue, which was working perfectly fine in chrome but not in safari – jay rangras Mar 25 '22 at 08:07
  • I would prefer this rather than implementing a library. – JTouchLogic Apr 26 '22 at 20:41
  • very useful thanks for your answer, to make it clearer which one of the fields is month and which one is day I would change it to: console.log (new Date('2011-12-28'.replace(/-/g, "/"))); – talsibony Jul 27 '22 at 18:02
  • I created an eslint rule to warn about it. I've had two different apps crash because of this Safari bug/feature. https://github.com/arnotixe/eslint-plugin-arnotixe/blob/master/README.md – Arno Teigseth Mar 24 '23 at 19:07
244

The pattern yyyy-MM-dd isn't an officially supported format for Date constructor. Firefox seems to support it, but don't count on other browsers doing the same.

Here are some supported strings:

  • MM-dd-yyyy
  • yyyy/MM/dd
  • MM/dd/yyyy
  • MMMM dd, yyyy
  • MMM dd, yyyy

DateJS seems like a good library for parsing non standard date formats.

Edit: just checked ECMA-262 standard. Quoting from section 15.9.1.15:

Date Time String Format

ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 Extended Format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ Where the fields are as follows:

  • YYYY is the decimal digits of the year in the Gregorian calendar.
  • "-" (hyphon) appears literally twice in the string.
  • MM is the month of the year from 01 (January) to 12 (December).
  • DD is the day of the month from 01 to 31.
  • "T" appears literally in the string, to indicate the beginning of the time element.
  • HH is the number of complete hours that have passed since midnight as two decimal digits.
  • ":" (colon) appears literally twice in the string.
  • mm is the number of complete minutes since the start of the hour as two decimal digits.
  • ss is the number of complete seconds since the start of the minute as two decimal digits.
  • "." (dot) appears literally in the string.
  • sss is the number of complete milliseconds since the start of the second as three decimal digits. Both the "." and the milliseconds field may be omitted.
  • Z is the time zone offset specified as "Z" (for UTC) or either "+" or "-" followed by a time expression hh:mm

This format includes date-only forms:

  • YYYY
  • YYYY-MM
  • YYYY-MM-DD

It also includes time-only forms with an optional time zone offset appended:

  • THH:mm
  • THH:mm:ss
  • THH:mm:ss.sss

Also included are "date-times" which may be any combination of the above.

So, it seems that YYYY-MM-DD is included in the standard, but for some reason, Safari doesn't support it.

Update: after looking at datejs documentation, using it, your problem should be solved using code like this:

var myDate1 = Date.parseExact("29-11-2010", "dd-MM-yyyy");
var myDate2 = Date.parseExact("11-29-2010", "MM-dd-yyyy");
var myDate3 = Date.parseExact("2010-11-29", "yyyy-MM-dd");
var myDate4 = Date.parseExact("2010-29-11", "yyyy-dd-MM");
Community
  • 1
  • 1
darioo
  • 46,442
  • 10
  • 75
  • 103
  • 5
    The ISO8601 format is used in the 5th edition of the ECMAScript standard, and isn't yet widely supported, the safest way to go IMO, parse the date manually :( – Christian C. Salvadó Nov 30 '10 at 06:25
  • 1
    That was very helpful dude.. Thank you.. :) Finally ended up using datejs for formatting. – Shrinath Dec 01 '10 at 12:08
  • for those in the future, please note that while datejs is fantastic in most respects, it doesn't solve all date formatting issues, particularly with safari. it's a PITA but it's best to do it manually if you still have problems. – totallyNotLizards Nov 12 '12 at 13:24
  • @darioo So i tried your answer as follow: "var start = Date.parseExact(timestamp, "YYYY-DD-MM HH:mm:SS");" timestamp is "2016-01-28 00:00:00 ". However now I get the error, that " Date.parseExact is not a function". Do you know, what happening here? – threxx Apr 13 '16 at 13:48
  • Really funny that Safari doesn't support that, since it's the default format PHP will output a date string. So really annoying thing when you read an date from PHP with AJAX – Florian Rachor Nov 21 '16 at 10:43
  • 8
    My similar issue was caused by Safari not knowing how to read the timezone in a RFC 822 time zone format. I was able to fix this by using the ISO 8601 format. If you have control of the date format I got this working with "yyyy-MM-dd'T'HH:mm:ss.sssXXX" which creates ie. "2018-02-06T20:00:00.000+00:00". For whatever reason Safari can't read "2018-02-06T20:00:00.000+0000", notice the lack of colon in the timezone format. – Olmstov Mar 06 '18 at 18:56
  • Thank you @darioo I ended up solving the issue down my end by using date-fns `parse()` function to create date objects. – oldo.nicho May 17 '18 at 03:25
  • 13
    Safari is the new Internet Explorer! – Saurabh Sharma Sep 18 '20 at 04:18
99

I was facing a similar issue. Date.Parse("DATESTRING") was working on Chrome (Version 59.0.3071.115 ) but not of Safari (Version 10.1.1 (11603.2.5) )

Safari:

Date.parse("2017-01-22 11:57:00")
NaN

Chrome:

Date.parse("2017-01-22 11:57:00")
1485115020000

The solution that worked for me was replacing the space in the dateString with "T". ( example : dateString.replace(/ /g,"T") )

Safari:

Date.parse("2017-01-22T11:57:00")
1485086220000

Chrome:

Date.parse("2017-01-22T11:57:00")
1485115020000

Note that the response from Safari browser is 8hrs (28800000ms) less than the response seen in Chrome browser because Safari returned the response in local TZ (which is 8hrs behind UTC)

To get both the times in same TZ

Safari:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

Chrome:

Date.parse("2017-01-22T11:57:00Z")
1485086220000
Mazdak Shojaie
  • 1,620
  • 1
  • 25
  • 32
nizantz
  • 1,561
  • 1
  • 13
  • 17
  • Or if you wan't both dates to be the same in Safari and Chrome you can use the `new Date(year, month, date, hours, minutes, seconds, milliseconds)` constructor. Parse the string date to an array of its components in order to use those components in the constructor. @nizantz it would be great if you think such example could be added to your answer. – h3dkandi Nov 16 '17 at 13:11
  • Not particularly useful since you get the date in UTC and not local time. – Jonas Äppelgran Nov 21 '18 at 20:22
  • 2
    This `dateString.replace(/ /g,"T")` magic line of code worked form me. :) – Mazdak Shojaie Dec 14 '18 at 15:06
  • 2
    replace(/-/g, '/') – Jack Hu Nov 06 '19 at 09:24
  • Thank you! So much easier than using a whole extra library! – Magnus Feb 27 '22 at 15:13
25

I use moment to solve the problem. For example

var startDate = moment('2015-07-06 08:00', 'YYYY-MM-DD HH:mm').toDate();
liwp_Stephen
  • 2,720
  • 1
  • 16
  • 11
  • Thank you for this soultion! It the only one over the Internet that works for React app for: IOS IPAD/IPHONE: chrome/safari || Android: chrome || Windows: chrome. Didn't test all the devices and OS versions but still it worked for every device I've found! – Денис Баланчук Oct 23 '20 at 17:34
  • 2
    to any future viewers, please note that the `moment` library is now deprecated – ChumiestBucket Oct 04 '21 at 16:39
10

To have a solution working on most browsers, you should create your date-object with this format

(year, month, date, hours, minutes, seconds, ms)

e.g.:

dateObj = new Date(2014, 6, 25); //UTC time / Months are mapped from 0 to 11
alert(dateObj.getTime()); //gives back timestamp in ms

works fine with IE, FF, Chrome and Safari. Even older versions.

IE Dev Center: Date Object (JavaScript)

Mozilla Dev Network: Date

Luxx
  • 392
  • 3
  • 6
  • I think new Date(2014, 6, 25) doesn't create UTC time, but the Timestamp for your local Timezone for '2014-6-25T00:00'. new Date(Date.UTC(2014, 6, 25)) gives UTC – Corrl Oct 29 '21 at 10:30
5

convert string to Date fromat (you have to know server timezone)

new Date('2015-06-16 11:00:00'.replace(/\s+/g, 'T').concat('.000+08:00')).getTime()  

where +08:00 = timeZone from server

Anja Ishmukhametova
  • 1,535
  • 16
  • 14
  • This doesn't take into account DST. The TZ offset can fluctuate and it dependents on the date itself (and time). – boggy Nov 27 '19 at 08:37
4

I had the same issue.Then I used moment.Js.Problem has vanished.

When creating a moment from a string, we first check if the string matches known ISO 8601 formats, then fall back to new Date(string) if a known format is not found.

Warning: Browser support for parsing strings is inconsistent. Because there is no specification on which formats should be supported, what works in some browsers will not work in other browsers.

For consistent results parsing anything other than ISO 8601 strings, you should use String + Format.

e.g.

var date= moment(String);
Sampath
  • 63,341
  • 64
  • 307
  • 441
4

For people using date-fns we can parseISO date and use it to format

Invalid

import _format from 'date-fns/format';

export function formatDate(date: string, format: string): string {
  return _format(new Date(date), format);
}

This function on safari throw error with Invalid date.

Solution
To fix it we should use:

import _format from 'date-fns/format';
import _parseISO from 'date-fns/parseISO';

export function formatDate(date: string, format: string): string {
  return _format(_parseISO(date), format);
}
OskarLebuda
  • 71
  • 1
  • 3
3

How about hijack Date with fix-date? No dependencies, min + gzip = 280 B

kenberkeley
  • 8,449
  • 3
  • 35
  • 25
3

For me the issue was I forgot to add 0 before the single digit month or day in YYYY-MM-DD format.
What I was parsing: 2021-11-5
What it should be: 2021-11-05

So, I wrote a little utility which converts YYYY-M-D to YYYY-MM-DD i.e. 2021-1-1 to 2021-01-01:

const date = "2021-1-1"
const YYYY = date.split("-")[0];

    //convert M->MM i.e. 2->02
    const MM =
      date.split("-")[1].length == 1
        ? "0" + date.split("-")[1]
        : date.split("-")[1];

    //convert D->DD i.e. 2->02
    const DD =
      date.split("-")[2].length == 1
        ? "0" + date.split("-")[2]
        : date.split("-")[2];

    // YYYY-MM-DD
    const properDateString = `${YYYY + "-" + MM + "-" + DD}`;

    const dateObj = new Date(properDateString);
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
2

Though you might hope that browsers would support ISO 8601 (or date-only subsets thereof), this is not the case. All browsers that I know of (at least in the US/English locales I use) are able to parse the horrible US MM/DD/YYYY format.

If you already have the parts of the date, you might instead want to try using Date.UTC(). If you don't, but you must use the YYYY-MM-DD format, I suggest using a regular expression to parse the pieces you know and then pass them to Date.UTC().

Phrogz
  • 296,393
  • 112
  • 651
  • 745
2

I am also facing the same problem in Safari Browser

var date = new Date("2011-02-07");
console.log(date) // IE you get ‘NaN’ returned and in Safari you get ‘Invalid Date’

Here the solution:

var d = new Date(2011, 01, 07); // yyyy, mm-1, dd  
var d = new Date(2011, 01, 07, 11, 05, 00); // yyyy, mm-1, dd, hh, mm, ss  
var d = new Date("02/07/2011"); // "mm/dd/yyyy"  
var d = new Date("02/07/2011 11:05:00"); // "mm/dd/yyyy hh:mm:ss"  
var d = new Date(1297076700000); // milliseconds  
var d = new Date("Mon Feb 07 2011 11:05:00 GMT"); // ""Day Mon dd yyyy hh:mm:ss GMT/UTC 
venkatskpi
  • 800
  • 6
  • 8
1

Use the below format, it would work on all the browsers

var year = 2016;
var month = 02;           // month varies from 0-11 (Jan-Dec)
var day = 23;

month = month<10?"0"+month:month;        // to ensure YYYY-MM-DD format
day = day<10?"0"+day:day;

dateObj = new Date(year+"-"+month+"-"+day);

alert(dateObj); 

//Your output would look like this "Wed Mar 23 2016 00:00:00 GMT+0530 (IST)"

//Note this would be in the current timezone in this case denoted by IST, to convert to UTC timezone you can include

alert(dateObj.toUTCSting);

//Your output now would like this "Tue, 22 Mar 2016 18:30:00 GMT"

Note that now the dateObj shows the time in GMT format, also note that the date and time have been changed correspondingly.

The "toUTCSting" function retrieves the corresponding time at the Greenwich meridian. This it accomplishes by establishing the time difference between your current timezone to the Greenwich Meridian timezone.

In the above case the time before conversion was 00:00 hours and minutes on the 23rd of March in the year 2016. And after conversion from GMT+0530 (IST) hours to GMT (it basically subtracts 5.30 hours from the given timestamp in this case) the time reflects 18.30 hours on the 22nd of March in the year 2016 (exactly 5.30 hours behind the first time).

Further to convert any date object to timestamp you can use

alert(dateObj.getTime());

//output would look something similar to this "1458671400000"

This would give you the unique timestamp of the time

1

Best way to do it is by using the following format:

new Date(year, month, day, hours, minutes, seconds, milliseconds)
var d = new Date(2018, 11, 24, 10, 33, 30, 0);

This is supported in all browsers and will not give you any issues. Please note that the months are written from 0 to 11.

  • Works well on Safari and Chrome, but still has issues on Firefox. Safari: var date = new Date(2018,06,08,19,17) Sun Jul 08 2018 19:17:00 GMT+0800 (+08) Chrome: var date = new Date(2018,06,08,19,17) Sun Jul 08 2018 19:17:00 GMT+0800 (Malaysia Time) Firefox: var date = new Date(2018,06,08,19,17) Date 2018-07-08T11:17:00.000Z – Biranchi Jul 08 '18 at 11:42
0

As @nizantz previously mentioned, using Date.parse() wasn't working for me in Safari. After a bit of research, I learned that the lastDateModified property for the File object has been deprecated, and is no longer supported by Safari. Using the lastModified property of the File object resolved my issues. Sure dislike it when bad info is found online.

Thanks to all who contributed to this post that assisted me in going down the path I needed to learn about my issue. Had it not been for this info, I never would have probably figured out my root issue. Maybe this will help someone else in my similar situation.

S. Costello
  • 35
  • 1
  • 10
0

Arriving late to the party but in our case we were getting this issue in Safari & iOS when using ES6 back tick instead of String() to type cast

This was giving 'invalid date' error

const dateString = '2011-11-18';
const dateObj = new Date(`${dateString}`); 

But this works

const dateObj = new Date(String(dateString)); 
dev7
  • 6,259
  • 6
  • 32
  • 65
0

In my case, it wasn't the formatting, it was because in my backend Node.js Model, I was defining the database variable as a String instead of a Date.

My backend Node Database Model said:

starttime:{
  type: String,
}

instead of the correct:

 starttime:{
    type: Date,
  }
Ahmedakhtar11
  • 1,076
  • 11
  • 7
0

As an argument of new Date() just write numbers instead of string.
Both Safari and Chrome understand this syntax

alert(new Date(2010, 29, 11));
0

I solved this problem in the following way:

old code, with error:

moment(new Date(date)).format("DD/MM/YYYY [às] HH:mm")

new code, with solution:

moment(date, "YYYY-MM-DD HH:mm:ss").format("DD/MM/YYYY [às] HH:mm")

-1

The same problem facing in Safari and it was solved by inserting this in web page

 <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> 

Hope it will work also your case too

Thanks

Yasir Shabbir Choudhary
  • 2,458
  • 2
  • 27
  • 31
  • Why do you think this would work? I looked at the script and it doesn't seem to override the methods in the Date object. I went here: https://polyfill.io/v3/url-builder/ and there seems to be nothing about parsing dates. – boggy Nov 27 '19 at 07:47
-1

This will not work alert(new Date('2010-11-29')); safari have some weird/strict way of processing date format alert(new Date(String('2010-11-29'))); try like this.

(Or)

Using Moment js will solve the issue though, After ios 14 the safari gets even weird

Try this alert(moment(String("2015-12-31 00:00:00")));

Moment JS

  • 1
    Before you paste this in even more locations, please take the time to read [Is it acceptable to add a duplicate answer to several questions?](https://meta.stackexchange.com/questions/104227/is-it-acceptable-to-add-a-duplicate-answer-to-several-questions). – fcdt Sep 30 '20 at 17:33
  • 2
    Please stop suggesting momentjs to others https://momentjs.com/docs/#/-project-status/ – GorvGoyl Apr 02 '21 at 10:31
-2

use the format 'mm/dd/yyyy'. For example :- new Date('02/28/2015'). It works well in all browsers.

Ravi S
  • 1
-2

This is not the best solution, although I simply catch the error and send back current date. I personally feel like not solving Safari issues, if users want to use a sh*t non-standards compliant browser - they have to live with quirks.

function safeDate(dateString = "") {
  let date = new Date();
  try {
    if (Date.parse(dateString)) {
      date = new Date(Date.parse(dateString))
    }
  } catch (error) {
    // do nothing.
  }
  return date;
}

I'd suggest having your backend send ISO dates.

AndrewMcLagan
  • 13,459
  • 23
  • 91
  • 158
  • 1
    With all respect, when you mean users _have_ to use the browser you wrote code for, that looks bad in general sense. It also depends on our use cases and target audience - if a website is being built for consumption of mass market, we'd be supporting IE10 too, at the very least. I am sure someone in MS thought the same when they were designing/coding for internet explorer. We all know how it is talked about now. – Shrinath Nov 21 '19 at 12:04