I'm currently trying to format a DB UTC timestamp to the local timezone. For that I'm trying this:
new Date( "2020-03-13 18:40:45 UTC".replace( /\s/, 'T' ) )
First I had this:
new Date( "2020-03-13 18:40:45 UTC" )
Which works in Chrome and Firefox but not in Safari. So I did some research and came up with the replace. Because of my replace I'm getting now Invalid Date in every browser. I've now idea why... What can I do to fix this?
Make sure your string is in the officially supported format, since anything else is falling back to "...any implementation-specific heuristics or implementation-specific date formats."
The space needs to be a T, and UTC needs to be Z with no space in front of it. (No need for a regular expression here.)
new Date("2020-03-13 18:40:45 UTC".replace(" ", "T").replace(" UTC", "Z"))
Live Example:
const dt = new Date("2020-03-13 18:40:45 UTC".replace(" ", "T").replace(" UTC", "Z"));
console.log(dt.toISOString());
It would appear that Chrome and Firefox have implementation-specific heuristics/formats that would make them accept it with the space and UTC, but not with the T and UTC. :-)
Related
I want to check difference between given date and now. I want to use exactly the code below and it works fine in chrome. but the console log says something else in Firefox.
Why? and how to fix this?
// input your custom Date below
const date = new Date('2020-6-23 14:22:00 GMT+0430'); // Set End Time Here!
const dif = (date.getTime() / 1000) - ((new Date().getTime())/1000);
const end = Math.max(0, dif);
console.log(date, dif, end);
"GMT" does not belong in that string. The string should be ISO 8601 compliant, if you want to be sure that it gets parsed correctly.
To align it with the ISO standard:
remove "GMT" and the space before it,
separate the time part from the date part with a "T",
write the month with double digits.
Either use punctuation (hyphen, colon) in the date, time and timezone, or don't use any at all. This condition is not really clear in the ISO 8601 specs I have access to, but apparently there is a move towards a more strict definition which excludes using punctuation only in a part of the string. In short, you are sure to align when you add also a colon in +04:30.
const date = new Date('2020-06-23T14:22:00+04:30');
// Now also output it in the Iranian timezone:
console.log(date.toLocaleString("en", { timeZone: "Iran" } ));
BTW: GMT is an ambiguous term anyway. UTC is a more exact defined term.
I have a datepicker which was returning a moment object that was always in UTC timezone. I needed to do some logic on this date, but always wanted it in the users local timezone so I did the following:
//strip submission date of timezone offset
let submission_date = moment(this.state.startDate).format('YYYY-MM-DD hh:mm:ss a');
submission_date = moment(submission_date);
let last_date = this.last_date.diff(submission_date, 'days');
However, when I do this my iPhone complains that submission_date is not a valid date. Desktop is fine so I'm guessing this is a safari issue. When I inspect this.state.startDate just prior to being momentized it's a string like 2018-11-01T17:52:44-00:00
Shouldn't moment accept that as a valid date?
I had figured out that it's the a flag in the format string. I changed it to YYYY-MM-DDTHH:mm:ss and it worked perfectly. Safari must not like am/pm data.
Try wrapping up with String function
//strip submission date of timezone offset
let submission_date = moment(String(this.state.startDate),'YYYY-MM-DD hh:mm:ss a');
let last_date = moment(String(this.last_date),'YYYY-MM-DD hh:mm:ss a').diff(submission_date, 'days');
Safari engine has some unique way of processing/parsing the date object
follow this format. year should be at the beginning. have to use "/" instead of "-".
cannot use "MMM" for month
YYYY/MM/DD hh:mm A
I solved this problem by ensuring all the letters in my ISO8601 formatted date-time (such as T and Z) were upper case. When they were lower case, moment failed to parse the date-time string.
I'm trying to convert javascript date strings into date objects. It seems that when I format the strings with slashes, like 2010/05/21, I get the date object I was expecting, but when I format the string with dashes, like 2010-05-21, I get a different date object which seems to refer to the previous day.
The following code illustrates my issue:
var aDate = new Date('2010-05-21')
console.log(aDate.toDateString())
console.log(aDate.toISOString())
console.log('=-=-=-=-=')
var anotherDate = new Date('2010/05/21')
console.log(anotherDate.toDateString())
console.log(anotherDate.toISOString())
The above code produces the following output:
2010-05-21T00:00:00.000Z
Thu May 20 2010
=-=-=-=-=
2010-05-21T06:00:00.000Z
Fri May 21 2010
It seems like part of the issue might be related to timezones, since getting the ISO string of the date objects shows the date objects to be 6 hours apart from each other, but I have no idea why using dashes instead of slashes would cause that. I'm using Google Chrome on MacOS Sierra, in case that's relevant.
2010/05/21 is a non-ISO date format, so support will be browser implementation dependent. Some browsers may reject it, others will accept it but use different time zones. It looks like your browser is parsing 2010/05/21 with your local time zone.
2010-05-21 is in a simplified ISO 8601 format, so ES5+ has specifications for how it must be parsed. In particular, it must assume the UTC time zone.
You can verify that it's using your local time zone by comparing it to how your browser parses an ISO 8601 date and time (which the ES5 specification says must use the local time zone).
var dateNonISO = new Date('2010/05/21');
var dateLocal = new Date('2010-05-21T00:00:00');
var dateUTC = new Date('2010-05-21');
console.log("Non-ISO:", dateNonISO.toISOString());
console.log("ISO Local:", dateLocal.toISOString());
console.log("ISO UTC:", dateUTC.toISOString());
Maybe the answer is obvious, but I don't get it. Why are the Dates in the Code Snippet different? Does the format say something about the hours as well?
console.log("2017-1-9 -->")
console.log(new Date("2017-1-9"))
console.log("2017-1-09 -->")
console.log(new Date("2017-1-09"))
console.log("2017-01-9 -->")
console.log(new Date("2017-01-9"))
console.log("2017-01-09 -->")
console.log(new Date("2017-01-09"))
console.log("2017-01-11 -->")
console.log(new Date("2017-01-11"))
.as-console-wrapper {
min-height: 100%;
}
Even in my chrome-console and the code-snippet-console I get different dates:
My problem is not that both consoles log different dates. Look only at the hours in each console, for the very same date, only the datestring is different. Consequently my question:
Why are the dates different?
UPDATE
Why is new Date("2017-1-1").getTime() != new Date("2017-01-01").getTime() --> true?
var date = new Date("2017-2-9");
var dateWithZero = new Date("2017-02-09");
console.log(date);
console.log(date.getTime());
console.log(dateWithZero);
console.log(dateWithZero.getTime());
console.log(date.getTime() == dateWithZero.getTime());
.as-console-wrapper {
min-height: 100%;
}
The dates being displayed are using different timezones. The Chrome console output is using your browsers local timezone and adjusting it appropriately. The (GMT+0100) is telling you which timezone and adjustments that are being made. The code snippet console is displaying using UTC. The 'Z' at the end of the string signifies that.
If you want to convince yourself of that they are the same, print the timestamp for each date also. This is also why when you are dealing with dates, you should rely on timestamps rather than comparing dates like this. Things get very confusing and difficult to deal with.
TL;DR: Because the language specification says that date strings not conforming to the specified format can be parsed according to "any implementation-specific heuristics or implementation-specific date formats," and YYYY-M-D is just such a string.
Let's dive into the spec. Here's what the ECMAScript 5.1 spec says about the Date constructor (I'm quoting it instead of the current, ES2016 spec just because it's simpler, but the latter works basically the same in this case):
15.9.3.2 new Date (value)
...
The [[PrimitiveValue]] internal property of the newly constructed
object is set as follows:
Let v be ToPrimitive(value).
If Type(v) is String, then
Parse v as a date, in exactly the same manner as for the parse method (15.9.4.2); let V be the time value for this date.
...
And here's the spec for parse (emphasis mine):
15.9.4.2 Date.parse (string)
The parse function applies the ToString operator to its argument and interprets the resulting String as a date and time... The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats. ...
Date Time String Format, in a nutshell, is YYYY-MM-DDTHH:mm:ss.sssZ and its subsets. Since YYYY-M-D doesn't conform to that format, the interpreter is (unfortunately) free to do whatever it wants. If you want to know why Chrome does it in this particular way, you'll have to dig around in the V8 source.
In some browsers, months or days with no leading zeroes may produce an error:
new Date("2017-2-9");
In consquent, that the behavior of the format "yyyy-mm-dd" is undefined.
Some browsers will try to guess the format, some will return NaN and some will return null.
That is why new Date("2017-02-09") has Thu Feb 09 2017 01:00:00 GMT+0100 (Mitteleuropäische Zeit) as output, because the behavior for this format is defined and it adds the timezone to the date. new Date("2017-2-9") has Thu Feb 09 2017 00:00:00 GMT+0100 (Mitteleuropäische Zeit) as output, because chrome trys to guess the format, but cannot add the timezone. In Safari in return null.
I have a string representing the current time: 2015-11-24T19:40:00. How do I parse this string in Javascript to get a Date represented by this string as the LOCAL TIME? Due to some restriction, I cannot use the library moment, but jquery is allowed. I know that someone has asked this question before, but the answer used moment
For example, if I run the script in California, then this string would represent 7PM pacific time, but if I run the script in NY then this string would represent Eastern Time?
I tried the following but Chrome and Firefox give me different results:
var str = "2015-11-24T19:40:00";
var date = new Date(str);
Chrome consumes it as UTC time (Tue Nov 24 2015 11:40:00 GMT-0800 (Pacific Standard Time)),
but Firefox consumes it as my local PACIFIC time (Tue Nov 24 2015 19:40:00 GMT-0800 (Pacific Standard Time))
I tried adding "Z" to str, like this var date = new Date(str+"Z");, then both browsers give me UTC time. Is there any similar letter to "Z" which tells all browsers (at least chrome, Firefox and Safari) to parse the string as local time zone?
Parsing of date strings using the Date constructor or Date.parse (which are essentially the same thing) is strongly recommended against.
If Date is called as a function and passed an ISO 8601 format date string without a timezone (such as 2015-11-24T19:40:00), you may get one of the following results:
Pre ES5 implementaitons may treat it as anything, even NaN (such as IE 8)
ES5 compliant implementations will treat it as UTC timezone
ECMAScript 2015 compliant implementations will treat it as local (which is consistent with ISO 8601)
A Date object has a time value which is UTC, and an offset based on system settings. When you send a Date to output, what you see is usually the result of Date.prototype.toString, which is an implementation dependent, human readable string representing the date and time, usually in a timezone based on system settings.
The best way to parse date strings is to do it manually. If you are assured that the format is consistent and valid, then parsing an ISO format string as a local date is as simple as:
/* #param {string} s - an ISO 8001 format date and time string
** with all components, e.g. 2015-11-24T19:40:00
** #returns {Date} - Date instance from parsing the string. May be NaN.
*/
function parseISOLocal(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1]-1, b[2], b[3], b[4], b[5]);
}
document.write(parseISOLocal('2015-11-24T19:40:00'));
Note that parsing of ISO strings using Date.parse only accepts UTC, it does not accept any other timezone designation (noting the above behaviour if it's missing).
A variation on RobG's terrific answer.
Note that this will require that you run bleeding edge JavaScript as
it relies on the arrow notation and spread operator.
function parseDateISOString(s) {
let ds = s.split(/\D/).map(s => parseInt(s));
ds[1] = ds[1] - 1; // adjust month
return new Date(...ds);
}
Note that this doesn't take into account if the date/time given is in any timezone. It will assume local time. You can change new Date for Date.UTC to assume UTC.
There are technical reasons for why you would write you code like this. For example, here we apply the correct number of arguments, with their corresponding expected type. It's true that the Date constructor will turn strings into numbers but what could be happening is that there's a deoptimization taking place where the optimized code is expecting a number but sees a string and takes a slower path. Not a big deal but I try to write my JavaScript to avoid such things. We also won't be indexing outside the bounds of the array if less than 6 components can be found in the string which is also one of those things you can do in JavaScript but it has subtle deoptimization caveats.
Where Date is called as a constructor with more than one argument, the specified arguments represent local time.
I also have a much faster way than using the string.split() because we already know where the numbers are:
return new Date(Number(date.substring(0, 4)), Number(date.substring(5, 7))-1,
Number(date.substring(8, 10)), Number(date.substring(11, 13)),
Number(date.substring(14, 16)), Number(date.substring(17, 19)));
This will work with and/or without the 'T' and 'Z' strings and still has decent performance. I added the explicit Number conversion (faster and better than parseInt) so this also compiles in TypeScript.
Number