Why this sample give me 22 number instead client 23 number:
console.log(new Date().toISOString());
Output is: 2019-01-22T22:58:46.606Z
Client side time:
The toISOString() method always outputs the time in UTC. From the docs:
The timezone is always zero UTC offset, as denoted by the suffix "Z".
In this case, the date is still the 22nd in UTC but, in your timezone, it's already the 23rd.
The Date object you have here is still in your local timezone, though. It just happens that the toISOString() method always outputs a UTC representation. If you do the following, you should see the date you're expecting:
console.log(new Date().toLocaleString()) // "1/22/2019, 3:14:18 PM" for me (US Pacific Time)
toISOString() returns a date/time in ISO format with timezone as UTC +0.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
Just to add on to what's already been offered. You still need to be careful about using the Date() method. It can generate different dates depending on what you give it.
//This outputs midnight (12:00AM) on January 22nd in the UTC timezone
new Date('2019-01-22').toISOString() // output: "2019-01-22T00:00:00.000Z"
//This outputs 5:00AM on January 22nd in the UTC timezone because my PC is in the
//Eastern Standard timezone and I used a different format for my date string.
new Date('01/22/2019').toISOString() // output: "2019-01-22T05:00:00.000Z"
Related
I am trying to get an UTC Date using the moment.js library (just to send it to my server), as follows:
const eighteenYearsAgoUTC = moment().utc().subtract(18, "years").toDate();
const eighteenYearsAgoUTCSinceUnixEpoch = eighteenYearsAgoUTC.valueOf()
console.log(eighteenYearsAgoUTCSinceUnixEpoch);
The millis since unix epoch are: 1051875596343
But... if I do the same without utc, I get the same result
const eighteenYearsAgoUTC = moment().subtract(18, "years").toDate();
const eighteenYearsAgoUTCSinceUnixEpoch = eighteenYearsAgoUTC.valueOf()
console.log(eighteenYearsAgoUTCSinceUnixEpoch);
1051875596343
Why am I getting the same milliseconds since Unix Epoch for an UTC date and a local Date?
My local date is: Fri May 02 2003 13:37:00 GMT+0200 (Central Europe)
The utc method just changes how moment parses and formats dates. The underlying information is still the same.
Milliseconds-since-The-Epoch values are always UTC. Both of your code snippets do the same thing:
Get "now"
Subtract 18 years
Get the result as the milliseconds-since-The-Epoch value
You'd notice a difference if you were formatting a date or parsing one, but you aren't doing either of those things.
I want to convert a local date object to a date object in another timezone and this is what I have:
moment("2016-08-04T23:30:37Z").tz("Asia/Hong_Kong").format("M/DD/YYYY h:mm a")
>>"8/05/2016 7:30 am"
but if I do
moment("2016-08-04T23:30:37Z").tz("Asia/Hong_Kong").toDate()
>>Thu Aug 04 2016 16:30:37 GMT-0700 (PDT)
As you can see, I can format the moment object to however I like, but how do I return it to a date object again?
... to a date object in another timezone
The JavaScript Date object cannot represent another time zone. It is simply a timestamp, measured in milliseconds since 1970-01-01 midnight UTC, which you can see with .valueOf() or .getTime().
When you call .toString() on a Date object, or otherwise coerce it into a string (such as when displaying it in the debug console), it converts the timestamp to the local time zone where the environment is running.
Therefore, despite any conversions you do with moment-timezone, you are still talking about the same moment in time, and thus will have the same timestamp in the resulting Date object.
In other words, these are all equivalent:
moment("2016-08-04T23:30:37Z").toDate()
moment.utc("2016-08-04T23:30:37Z").toDate()
moment("2016-08-04T23:30:37Z").tz("Asia/Hong_Kong").toDate()
new Date("2016-08-04T23:30:37Z")
... because they all have the same internal timestamp of 1470353437000
moment("2016-08-04T23:30:37Z").valueOf() // 1470353437000
moment.utc("2016-08-04T23:30:37Z").valueOf() // 1470353437000
moment("2016-08-04T23:30:37Z").tz("Asia/Hong_Kong").valueOf() // 1470353437000
new Date("2016-08-04T23:30:37Z").valueOf() // 1470353437000
I'm trying to pass both date strings to new Date(t).
I expect both strings represent the same time, after all, if I omit the time, shouldn't it be midnight of that day?
But while,
new Date("2016-02-16 00:00")
returns 2016-02-16, midnight, local time as expected,
new Date("2016-02-16")
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
I would understand it if they would both have the same behavior, whether it is to return the time as local time, or as UTC, but it seems very inconsistent why they return different things like this.
As a workaround, whenever I encounter a date that has no corresponding timestamp I can append " 00:00" to get consistent behavior, but it seems like this is rather fragile.
I am getting this value from an INPUT element, of type 'datetime-local' so it seems especially inconsistent that I have to work around a value returned by a page element.
Am I doing something wrong, or should I be doing something differently?
It's what the ES5.1 specification says to do:
The value of an absent time zone offset is “Z”.
It also says:
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.
Since the format requires a T separator between date and time, the valid times go to UTC:
> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
...while in node.js, an invalid time (without the T separator) seems to go to the implementation specific localtime:
> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)
Note that ES6 changed this, in the same part of the documentation it changes to:
If the time zone offset is absent, the date-time is interpreted as a local time.
The joy of breaking changes.
Edit
According to TC39, the specification is meant to be interpreted as date and time strings without a time zone (e.g. "2016-02-16T00:00:00") are treated as local (per ISO 8601), but date only strings (e.g. "2016-02-16") as UTC (which is inconsistent with ISO 8601).
According to the specifications:
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.
And Date Time String Formats accept 2016-02-16 as a valid date
This format includes date-only forms:
YYYY
YYYY-MM
YYYY-MM-DD
[...] If the HH, mm, or ss fields are absent “00” is used as the value
and the value of an absent sss field is “000”. The value of an absent
time zone offset is “Z”.
Thus 2016-02-16 translates to 2016-02-16T00:00:00.000Z.
The other date 2016-02-16 00:00 does not conform to the format and therefore its parsing is implementation specific. Apparently, such dates are treated as having local time zone and your example date will return different values depending on time zone:
/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z
Summary:
For conforming date time formats the behavior is well defined — in the absence of time zone offset the date string is treated as UTC (ES5) or local (ES6).
For non-conforming date time formats the behavior is implementation specific — in the absence of time zone offset the usual behavior is to treat the date as local.
As a matter of fact, the implementation could choose to return NaN instead of trying to parse non-conforming dates. Just test your code in Internet Explorer 11 ;)
You are perhaps running into a differences between ES5, ES6 implementations and your expected result. Per Date.parse at MDN, "especially across different ECMAScript implementations where strings like "2015-10-12 12:00:00" may be parsed to as NaN, UTC or local timezone" is significant.
Additional testing in Firefox 44 and IE 11 revealed they both return a date object for new Date("2016-02-16 00:00"), which object returns NaN when atttempting to get a date component value, and whose toString value is
"Invalid Date" (not "NaN"). Hence appending " 00:00 to get consistent behavior" can easily break in different browsers.
As noted in other answers new Date("2016-02-16") uses a timezone offset of zero by default, producing midnight UTC instead of local.
Per DateParser::Parse() of V8 source codes for Chrome.
ES5 ISO 8601 dates:
[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]
An unsigned number followed by ':' is a time value, and is added to the TimeComposer.
timezone defaults to Z if missing
> new Date("2016-02-16 00:00")
Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)
A string that matches both formats (e.g. 1970-01-01) will be parsed as an ES5 date-time string - which means it will default to UTC time-zone. That's unavoidable if following the ES5 specification.
> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
It adds the timezone offset to the 00:00
new Date("2016-02-16") outputs Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)
My timezone being IST with an offset value (in minutes) +330, so it added 330 minutes to 00:00.
As per ecma-262, section 20.3.3.2 Date.parse ( string )
If ToString results in an abrupt completion the Completion Record is
immediately returned. Otherwise, parse interprets the resulting String
as a date and time; it returns a Number, the UTC time value
corresponding to the date and time. The String may be interpreted as a
local time, a UTC time, or a time in some other time zone, depending
on the contents of the String.
When you explicitly set the time-units new Date("2016-02-16 00:00") it wll use set that as hours and minutes,
Otherwise as stated here in 20.3.1.16
If the time zone offset is absent, the date-time is interpreted as a
local time.
Can anyone explain why getFullYear does not return 2014?
console.log(new Date('2014-01-01').getFullYear()) //2013
console.log(new Date('2014-01-01').getUTCFullYear()) //2014
From MDN:
The dateString of "March 7, 2014" returns a different date than "2014-03-07" unless the local time-zone is UTC. When converting a dateString of "March 7, 2014" the local time-zone is assumed. When converting a dateString of "2014-03-07" the UTC time-zone is assumed. This results in two different Date values depending on the format of the string that is being converted.
So when you ask it to parse "2014-01-01", you're getting the time in UTC.
Then you call .getFullYear() on your object, which uses local time. If you live in the Eastern US like I do, then it basically subtracts 4 hours from the internal time and returns the year.
So here's what happens:
"2014-01-01" is converted to "1388534400000"
.getFullYear() is called and "1388534400000" is converted to local time
Local time is something like "1388534160000"
New years hasn't yet occurred at "1388534160000", so it's still 2013
All of this implies that if we do something like
console.log(new Date('January 1, 2014').getUTCFullYear()); // 2014
console.log(new Date('January 1, 2014').getFullYear()); // 2014
We'll get the same year, because we told the browser to use our timezone right on New Year's, but they're not equivalent:
console.log(new Date('January 1, 2014').getUTCHours()); // 5
console.log(new Date('January 1, 2014').getHours()); // 0
According to this:
"The difference is when you specify a string in the format YYYY-MM-DD, you get a date that is 12am in the GMT timezone and when you specify a date in the format DD-MM-YYYY, you get a date that is 12am in your current timezone."
So basically since you are specifying News Years Day 2014 when it gets converted from GMT to your local time it believes it is 12-31-13 not 01-01-14.
Why does moment.js UTC always show the wrong date. For example from chrome's developer console:
moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()
Both of them will return "2013-07-17" why is it returning 17th instead of 18th, that was passed in.
But if I use momentjs without the utc:
moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()
I get back "2013-07-18" which is what I also expect when using moment.js UTC.
Does this mean we cannot get the correct date when using moment.js UTC?
By default, MomentJS parses in local time. If only a date string (with no time) is provided, the time defaults to midnight.
In your code, you create a local date and then convert it to the UTC timezone (in fact, it makes the moment instance switch to UTC mode), so when it is formatted, it is shifted (depending on your local time) forward or backwards.
If the local timezone is UTC+N (N being a positive number), and you parse a date-only string, you will get the previous date.
Here are some examples to illustrate it (my local time offset is UTC+3 during DST):
>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"
If you want the date-time string interpreted as UTC, you should be explicit about it:
>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"
or, as Matt Johnson mentions in his answer, you can (and probably should) parse it as a UTC date in the first place using moment.utc() and include the format string as a second argument to prevent ambiguity.
>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"
To go the other way around and convert a UTC date to a local date, you can use the local() method, as follows:
>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"
Both Date and moment will parse the input string in the local time zone of the browser by default. However Date is sometimes inconsistent with this regard. If the string is specifically YYYY-MM-DD, using hyphens, or if it is YYYY-MM-DD HH:mm:ss, it will interpret it as local time. Unlike Date, moment will always be consistent about how it parses.
The correct way to parse an input moment as UTC in the format you provided would be like this:
moment.utc('07-18-2013', 'MM-DD-YYYY')
Refer to this documentation.
If you want to then format it differently for output, you would do this:
moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')
You do not need to call toString explicitly.
Note that it is very important to provide the input format. Without it, a date like 01-04-2013 might get processed as either Jan 4th or Apr 1st, depending on the culture settings of the browser.
use this :
return moment.utc(new Date(oData.CreatedAtUtc), 'MM/DD/YYYY h:mm A').local().format("YYYY-MM-DD HH:mm") + ' (' + timezoneAbbr + ')';