Messed support for Intl.DateTimeFormat with Chinese Calendar - javascript

new Intl.DateTimeFormat('zh-CN-u-ca-chinese', { dateStyle: 'full' }).format(1680537600000)
The above code outputs 0040闰0214 12:00 上午 in Firefox, 2023癸卯年闰二月十四星期二 in Chrome/node/deno, 2023癸卯年闰二月14星期二 in bun.
Why those outputs are so different? How can I produce a uniform output?

Related

What's the correct format of the default javascript Date returned object

When the new Date() is called, it returns something like this
Wed Jul 13 2022 16:15:35 GMT-0600 (Central Standard Time)
So I was curious what is the correct format used in that case? I tried building it with the following format: E MMM d yyyy H:mm:ss zzzz However the result was
Wed Jul 13 2022 16:15:00 GMT-06:00
This is the closest I can get. I've been searching the internet but can't find the correct format. By the way, the local used is en_US
Example:
let momentDate = moment(date, 'E MMM d yyyy H:mm:ss zzzz', true);
If I execute the momentDate.isValid() it returns false.
From MDN: Date.prototype.toString() returns a string representation of the Date in the format specified in ECMA-262.
That last part is described as:
Optionally, a timezone name consisting of:
space
Left bracket, i.e. "("
An implementation dependent string representation of the timezone, which might be an abbreviation or full name (there is no standard for names or abbreviations of timezones), e.g. "Line Islands Time" or "LINT"
Right bracket, i.e. ")"
Different date formatting libraries in different frameworks will have different ways to get a string representation of the time zone and, importantly, this is implementation-specific. This SO answer shows one way to get that value, basically by outputting it from a date and parsing the result. But you should not rely on it (or really any aspect of date outputs, apart from toISOString()) having any consistency between browsers or other execution environments.
Until ECMAScript 2018 (edition 9), the format of the string returned by Date.prototype.toString was implementation dependent. Therefore it should not be relied upon to be in the specified format.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString#description
output variations are by design, and allowed by the specification... you cannot expect to be able to compare the results of toLocaleString() to a static value
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString#avoid_comparing_formatted_date_values_to_static_values

dayjs() telling me invalid date for this date string

DayJs
Using it on the browser if that matters (firefox + Vue + typescript).
This is my date string
2021-02-05 12:00 AM
It fusses about the AM/PM in my code:
const dateObj: any = dayjs('2021-02-05 12:00 AM').format('YYYY-MM-DD hh:mm A');
The output of dateObj is always "Invalid Date". If I remove the "AM" from the string it parses correctly. If I try this online tester for the same code, the output is
NaN-NaN-NaN NaN:NaN PM
Like with my dev environment, if I remove the AM, it's fine.
Any ideas?
EDIT: Working on Chrome and not Firefox...
Issue on Firefox
If you deeply look at the implementation, you would see above day string going through the Day constructor: new Day('2021-02-05 12:00 AM'). Unfortunately FF doesn't support this support this day string format, but Chrome does.
Best approach
The dayjs documentation mentions:
For consistent results parsing anything other than ISO 8601 strings, you should use String + Format.
If you're still keen to use above format, you would have to use a plugin as mentioned here
Basically, you have to change as below to work in all browsers:
import customParseFormat from 'dayjs/plugin/customParseFormat'
import dayjs from "dayjs"
dayjs.extend(customParseFormat)
const yourDate = dayjs('2021-02-05 12:00 AM', 'YYYY-MM-DD HH:mm A')

Formatting UTC date don't works in Safari with JavaScript

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

Why does the same date have different hours?

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.

Incorrect timezone in Firefox, compared to Safari, using javascript Date()

The following code
var date = new Date();
console.log( date );
gives me
Sun Mar 06 2011 21:41:36 GMT+1300 (NZST) {}
in Firefox, but
Sun Mar 06 2011 21:40:51 GMT+1300 (NZDT)
in Safari (which is correct).
My system Date & Time is set to NZDT, so I'm wondering where firefox is getting its NZST from. Mind you, the UTC offset (+1300) is correct in both cases.
How can I get Firefox displaying the correct timezone: NZDT?
You shouldn't rely on that output as it's different in other browsers (IE), instead you should use the getTimezoneOffset method.
var date = new Date;
console.log( date.getTimezoneOffset() );
The offset will change with day light savings but there are ways to work with this.
If everything is how you want it except for the "NZST", you could just do a simple text replace:
console.log(date.toString().replace('NZST', 'NZDT'));
Note that this is really only simple fix for the display issue, it doesn't address the underlying cause.
This was a bug that was fixed in Firefox v4 and later.

Categories