ChatGPT解决这个技术问题 Extra ChatGPT

Invalid date in safari

 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.

Just for other looking at same problem : I ended up using DateJS, which solved my problem overall.. See accepted answer for details.
use moment.js to parse the timestamp. Especially when dealing with cross platform web
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.
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.

E
Elzo Valugi

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, "/")));

This one line help was perfect for my need! Thanks!
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
I think this is the best answer I tend to forget /-/g instead of '-'
applause for not implementing a library.
i still not get why people wants to use a whole library for a single use.kudos for not implementing one.
C
Community

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");

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 :(
That was very helpful dude.. Thank you.. :) Finally ended up using datejs for formatting.
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.
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.
Safari is the new Internet Explorer!
M
Mazdak Shojaie

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

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.
Not particularly useful since you get the date in UTC and not local time.
This dateString.replace(/ /g,"T") magic line of code worked form me. :)
replace(/-/g, '/')
Thank you! So much easier than using a whole extra library!
l
liwp_Stephen

I use moment to solve the problem. For example

var startDate = moment('2015-07-06 08:00', 'YYYY-MM-DD HH:mm').toDate();

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!
to any future viewers, please note that the moment library is now deprecated
you saved my hours, thanks!
L
Luxx

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


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
A
Anja Ishmukhametova

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


This doesn't take into account DST. The TZ offset can fluctuate and it dependents on the date itself (and time).
S
Sampath

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);

O
OskarLebuda

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);
}

P
Phrogz

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().


I guess string parsing is the way to go :(
k
kenberkeley

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


Only solution which worked in my case. Thanks Cheers...
v
venkatskpi

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 

A
Abhay Aradhya

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


D
Daniël Brito

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
G
GorvGoyl

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);

S
S. Costello

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.


d
dev7

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)); 

Y
Yasir Shabbir Choudhary

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


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: polyfill.io/v3/url-builder and there seems to be nothing about parsing dates.
S
SARAVANAN KALIMUTHU

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


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?.
Please stop suggesting momentjs to others momentjs.com/docs/#/-project-status
R
Ravi S

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


A
AndrewMcLagan

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.


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.