How does Date.toLocaleDateString() work? - javascript

I've to represent the date with local user's configurations. Follows the MDN description:
The toLocaleDateString method relies on the underlying operating
system in formatting dates. It converts the date to a string using the
formatting convention of the operating system where the script is
running. For example, in the United States, the month appears before
the date (04/15/98), whereas in Germany the date appears before the
month (15.04.98).
I do this:
var date = new Date ();
console.log (date.toLocaleDateString ());
It prints out Saturday, October 13, 2012 but what I expect is Sabato, 13 Ottobre, 2012 (that's the Italian date format).
Now, configurations of my browser and my system are set properly (Italian language and the above format date) so I don't understand how does toLocaleDateString work.
Am I doing it right?

According to the Mozilla documentation, the format can vary wildly depending on the user's location and computer settings.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
The exact format depends on the platform, locale and user's settings.

This question is out-of-date.
These are my tests:
(new Date ()).toLocaleDateString () -> "4/9/2013" (italian format 'd/m/Y') with Chrome 29
(new Date ()).toLocaleDateString () -> "mercoledì 4 settembre 2013" (italian format 'D d M Y') with Firefox 22
It works with newest browsers versions.

Related

Get default browser settings like TimeZone, Dateformat, timeFormat and language using javascript

How we can get all of the default browser/system/country settings using javascript or any other js library?
Like what is the default timezone format of the browser?
(UTC+05:30 or UTC+01:00, etc)
What is the default Date format according to timezone? ('DD/MM/YYYY' or
'MM/DD/YYYY' or 'YYYY/MM/DD')
What is the default Time format according to a browser? ('AM/PM' or '24 Hour')
Default language of browser?
If we do navigator.language using javascript we get "en-GB" but can we get a full form? like English, Spanish, Sweedish or etc
Default temperature unit? (Celsius or Fahrenheit)
Like what is the default timezone format of the browser? (UTC+05:30 or UTC+01:00, etc)
Timezone is a preference, there is no default. Be careful about what you assume
To get the timezone offset, which is the number of minutes you need to subtract from UTC, use the following. This will usually be a negative number for users in Asia and Australia, and usually a positive number for users in the Americas.
new Date().getTimezoneOffset()
If you want to know the timezone, you can get it with
Intl.DateTimeFormat().resolvedOptions().timeZone
// => "Atlantic/Reykjavik"
// => "Americas/New_York"
// => "Asia/Shanghai"
Be careful if you translate this to a 3 character abbreviation. "Americas/New_York" could be "EST" or "EDT" depending on the time of year. "CST" could be China standard time, or Cuba standard time, or Central Australia standard time, or Central America standard time.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
Other than temperature unit (which the browser knows nothing about), the IETF language setting (in this case "en-GB") tells the browser how to format outputs when using .toLocaleString(). A date object will be printed with the TZ offset, the same date with .toLocalDateString() will give the date in proper locale 'DD/MM/YYYY' , and the same date with .toLocaleTimeString() will give the time with 'AM/PM or 24h' representation.
const date = new Date();
console.log(date.toString());
console.log(date.toUTCString());
console.log(date.toLocaleString());
console.log(date.toLocaleDateString());
console.log(date.toLocaleTimeString());
// Get TZ for instance
const tz = date.toString().match(/GMT(-|\+)[0-9]{4}.*/)[0];
console.log(tz);

Initialize JS date object from HTML date picker: incorrect date returned

How do you correctly intitialize a timezone-independent date (or I guess a date that is fixed to a single timezone across the html side and the JS side) from a html datepicker?
I have the following simple code, which is producing incorrect dates:
function printDate(){
let d = new Date(document.getElementById("date").value)
alert(d)
}
document.getElementById("printDate").addEventListener("click", e => printDate())
<html>
<body>
Print Date: <br><input type="date" id="date"> <button id="printDate">Add</button>
</body>
</html>
But at least on my computer, currently sitting in U.S. mountain time, it produces incorrect dates. I give it today's date (March 9, 2019), and it alerts yesterday's date in the following format: Fri Mar 08 2019 17:00:00 GMT-0700 (MST). How do I make it not do that?
I really just want it to assume that all input and all output are in GMT.
In a <input type="date" /> element, the selected date is displayed in the locale format, but the value property is always returned in yyyy-mm-dd format, as described in the MDN docs.
In other words, when you choose March 9, 2019, you may see 03/09/2019 from the US or 09/03/2019 in other parts of the world, but value is 2019-03-09 regardless of any time zone or localization settings. This is a good thing, as it allows you to work with the selected date in a standard ISO 8601 format, without trying to apply a time.
However, when you parse a date string in that format with the Date object's constructor (or with Date.parse), you run up against a known issue: The date is not treated as local time, but as UTC. This is the opposite of ISO 8601.
This is described in the MDN docs:
Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
It's also in the ECMAScript specification (emphasis mine):
... When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.
There was a debate about this in 2015, but ultimately it was decided that maintaining compatibility with existing behaviors was more important than being ISO 8601 compliant.
Going back to your question, the best thing to do would be to not parse it into a Date object if you don't need one. In other words:
function printDate(){
const d = document.getElementById("date").value;
alert(d);
}
If you really need a Date object, then the easiest option is to parse the value yourself:
function printDate(){
const parts = document.getElementById("date").value.split('-');
const d = new Date(+parts[0], parts[1]-1, +parts[2], 12);
alert(d);
}
Note the ,12 at the end sets the time to noon instead of midnight. This is optional, but it avoids situations of getting the wrong day when midnight doesn't exist in the local time zone where DST transitions at midnight (Brazil, Cuba, etc.).
Then there's your last comment:
I really just want it to assume that all input and all output are in GMT.
That's a bit different than what you showed. If really that's what you want, then you can construct the Date object as you previously did, and use .toISOString(), .toGMTString(), or .toLocaleString(undefined, {timeZone: 'UTC'})
function printDate(){
const d = new Date(document.getElementById("date").value); // will treat input as UTC
// will output as UTC in ISO 8601 format
alert(d.toISOString());
// will output as UTC in an implementation dependent format
alert(d.toGMTString());
// will output as UTC in a locale specific format
alert(d.toLocaleString(undefined, {timeZone: 'UTC'}));
}

is there any workaround for broken v8 date parser?

V8 Date parser is broken:
> new Date('asd qw 101')
Sat Jan 01 101 00:00:00 GMT+0100 (CET)
I can use fragile regular expression like this:
\d{1,2} (jan|feb|mar|may|jun|jul|aug|sep|oct|nov|dec) \d{1,4}
but it is too fragile. I cannot rely on new Date (issue in V8) and also moment cant help me because moment is getting rid off date detection (github issue-thread).
is there any workaround for broken v8 date parser?
To be clear. We have Gecko and V8, both have Date. V8 has broken Date, Gecko has working one. I need the Date from in Gecko (Firefox).
Update: It’s definitely broken parser https://code.google.com/p/v8/issues/detail?id=2602
nope, Status: WorkingAsIntended
Date objects are based on a time value that is the number of milliseconds since 1 January, 1970 UTC and have the following constructors
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
From the docs,
dateString in new Date(dateString) is a string value representing a date. The string should be in a
format recognized by the Date.parse() method (IETF-compliant RFC 2822
timestamps and also a version of ISO8601).
Now looking at the v8 sourcecode in date.js:
function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
if (!%_IsConstructCall()) {
// ECMA 262 - 15.9.2
return (new $Date()).toString();
}
// ECMA 262 - 15.9.3
var argc = %_ArgumentsLength();
var value;
if (argc == 0) {
value = %DateCurrentTime();
SET_UTC_DATE_VALUE(this, value);
} else if (argc == 1) {
if (IS_NUMBER(year)) {
value = year;
} else if (IS_STRING(year)) {
// Probe the Date cache. If we already have a time value for the
// given time, we re-use that instead of parsing the string again.
var cache = Date_cache;
if (cache.string === year) {
value = cache.time;
} else {
value = DateParse(year); <- DOES NOT RETURN NaN
if (!NUMBER_IS_NAN(value)) {
cache.time = value;
cache.string = year;
}
}
}
...
it looks like DateParse() does not return a NaN for for a string like 'asd qw 101' and hence the error. You can cross-check the same with Date.parse('asd qw 101') in both Chrome(v8) [which returns -58979943000000] and Gecko (Firefox) [which returns a NaN]. Sat Jan 01 101 00:00:00 comes when you seed new Date() with a timestamp of -58979943000000(in both browsers)
is there any workaround for broken v8 date parser?
I wouldnt say V8 date parser is broken. It just tries to satisfy a string against RFC 2822 standard in the best possible way but so does gecko and both break gives different results in certain cases.
Try new Date('Sun Ma 10 2015') in both Chrome(V8) and Firefox(Gecko) for another such anomaly.
Here chrome cannot decide weather 'Ma' stands for 'March' or 'May' and gives an Invalid Date while Firefox doesnt.
Workaround:
You can create your own wrapper around Date() to filter those strings that V8's own parser cannot. However, subclassing built-ins in ECMA-5 is not feasible. In ECMA-6, it will be possible to subclass built-in constructors (Array, Date, and Error) - reference
However you can use a more robust regular expression to validate strings against RFC 2822/ISO 8601
^(?:(?:31(\/|-|\. |\s)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.|\s)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.|\s)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.|\s)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$
Image generated from debuggex
So, seems like v8 aint broken, it just works differently.
Hope it helps!
You seem to be asking for a way to parse a string that might be in any particular format and determine what data is represented. There are many reasons why this is a bad idea in general.
You say moment.js is "getting rid of date detection", but actually it never had this feature in the first place. People just made the assumption that it could do that, and in some cases it worked, and in many cases it didn't.
Here's an example that illustrates the problem.
var s = "01.02.03";
Is that a date? Maybe. Maybe not. It could be a section heading in a document. Even if we said it was a date, what date is it? It could be interpreted as any of the following:
January 2nd, 2003
January 2nd, 0003
February 1st, 2003
February 1st, 0003
February 3rd, 2001
February 3rd, 0001
The only way to disambiguate would be with knowledge of the current culture date settings. Javascript's Date object does just that - which means you will get a different value depending on the settings of the machine where the code is running. However, moment.js is about stability across all environments. Cultural settings are explicit, via moment's own locale functionality. Relying on the browser's culture settings leads to errors in interpretation.
The best thing to do is to be explicit about the format you are working with. Don't allow random garbage input. Expect your input in a particular format, and use a regex to validate that format ahead of time, rather then just trying to construct a Date and seeing if it's valid after the fact.
If you can't do that, you'll have to find additional context to help decide. For example, if you are scraping some random bits of the web from a back-end process and you want to extract a date from the text, you'd have to have some knowledge about the language and locale of each particular web page. You could guess, but you'd likely be wrong a fair amount of the time.
See also: Garbage in, garbage out
ES5 15.9.4.2 Date.parse: /.../ If the String does not conform to
that format the function may fall back to any implementation-specific
heuristics or implementation-specific date formats. Unrecognizable
Strings or dates containing illegal element values in the format
String shall cause Date.parse to return NaN.
So that's all right and according to the citation above result of v8 date parser:
new Date('asd qw 101') : Sat Jan 01 101 00:00:00 GMT+0100
(CET)
new Date('asd qw') : Invalid Date

Javascript new date treats differently towards different date style?

I tested the following code in firefox scratchpad and got interesting result?
var date=new Date("2012-05-12");
var date2 = new Date("05/12/2012");
date;
/*
Fri May 11 2012 17:00:00 GMT-0700 (Pacific Daylight Time)
*/
date2;
/*
Sat May 12 2012 00:00:00 GMT-0700 (Pacific Daylight Time)
*/
Two dates are different. Apparently this is due to the timezone issue. What I want is date2 result. How can I make js engine correctly treats the ISO date style?
I think the issue is that the string "2012-05-12" is taken to be an ISO 8601 date, while "05/12/2012" is an RFC 2822 date. In the ISO format, the lack of a timezone implies UTC. At midnight on the morning off May 12, in California (or wherever you are) it's 7 PM the previous evening.
The RFC date without a time zone, however, is parsed under the assumption that you want the timestamp for midnight in your local timezone. (Well, not necessarily your timezone; the timezone of the computer where your JavaScript runs :-)
You can see the difference if you pass those strings to Date.parse().
The RFC date format can include an explicit time zone, but the ISO format cannot. (Well, it can, but browsers don't pay attention, and apparently IE doesn't handle those at all.)
edit — here's a simple (dumb; no error checking) function that'll give you a date from that 3-part ISO form:
function isoDate( str ) {
var rv = null;
str.replace(/^(\d\d\d\d)-(\d\d)-(\d\d)$/, function(_, yr, mn, dy) {
rv = new Date(parseInt(yr, 10), parseInt(mn, 10) - 1, parseInt(dy, 10));
});
return rv;
}
By the standard, with Date(), you can parse ISO dates or dates in an implementation-dependent format, in an an implementation-dependent manner. To get anything more reliable, use a suitable library that can parse dates in some known formats.

js Date toLocaleString

I use the 3 browsers to output this result.
Chrome:
new Date().toLocaleString()
> "Sun Sep 04 2011 21:40:04 GMT+0800 (HKT)"
Safari:
new Date().toLocaleString()
> "2011年9月4日 下午09时54分51秒格林尼治标准时间+0800"
FF:
new Date().toLocaleString()
> "Sun Sep 4 21:46:03 2011"
why not the same output result? timezoom?
It depends on the configuration of the computer, the user's preferred date format, obviously the user's locale, and how the browser determines this.
You should really prefer using a proper date library such as datejs for formatting.
See their Date.toString() and format specifiers.
That's a bug in webkit, actually; in particular in Chrome but Safari is indeed affected too: http://code.google.com/p/chromium/issues/detail?id=3607
toLocaleString() does not translate to the locale!
The worst is, it's closed as WontFix. How is that possible? We should try and re-open it. The conclusion on the bug is that somewhen a new javascript globalization apis (that is well explained here) will appear. That doesn't sound like a solution to me!
In any case, if possible, follow #arnaud576875 suggestion to use datejs which is old but still very good.
Check this link
And this example:
var event = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
// British English uses day-month-year order and 24-hour time without AM/PM
console.log(event.toLocaleString('en-GB', { timeZone: 'UTC' }));
// expected output: 20/12/2012, 03:00:00
// Korean uses year-month-day order and 12-hour time with AM/PM
console.log(event.toLocaleString('ko-KR', { timeZone: 'UTC' }));
// expected output: 2012. 12. 20. 오전 3:00:00

Categories

Resources