Moment.js : Format date according browser lang - javascript

I use this code to display a date in French format :
var dateToDisplay = moment(myDateInMS, "x").format("DD/MM/YYYY - hh:mm:ss"); // Output : "20/03/2016 - 12:35:32"
I would like to improve this display to have a better display according the browser language. How can i do that using moment ?

I do not recommend setting the locale depending on the browser language as it's not a clear signal of the actual locale of the user. E.g. a user may use an English operating system even though s/he's a French speaker.
That being said. Reading the language from the browser and setting Moment.js to the corresponding locale can be done this way:
var localeData = moment.localeData();
switch (navigator.language || navigator.userLanguage) {
case 'fr':
localeData = moment.localeData('fr');
break;
}
localeData.longDateFormat('LL'); // the example 'LL' will output date in "D MMMM YYYY format"
Notice that this is setting the locale of the entire Moment.js instance (which is probably what you want to do). Also notice that as of Moment.js 2.8.0, changing the global locale doesn't affect existing instances.
Also see
Changing locale globally
Long Date Format

Moment will actually search for substrings of the locale pulled from the browser in an attempt to pick the correct locale. Thus, there is no need to preparse or create a case statement.
As an example, moment has es as a locale, but not es-mx. If the browser is set to es-mx the locale function looks for es-mx and when it doesn't find it, falls back to es. Thus:
moment.locale('es-mx');
"es"
Meaning that for your purposes you can just do:
moment.locale(navigator.userLanguage || navigator.language);
Then when formatting your dates, use one of the locale specific formats to make them appropriate for the user:
moment().format('LL')
"1 de abril de 2016"
moment().format('L')
"01/04/2016"
For all of the localized formats and what they should produce, see the localized format section of the format documentation: http://momentjs.com/docs/#/displaying/format/

Related

(Sanity Check) Do I need a timezone library for this simple use case?

This will be my first time working with time zones, I hear this is a major pain point for a lot of developers so I'm asking this question as a sanity check to make sure I'm not missing anything.
My use case is rather "simple", I want to have a date time picker where the user can choose their date and time in their local timezone (in other words what they see in the picker matches what their computer's date and time is set to).
Then I want to take this chosen date and time, convert it to UTC and send it to the server to be saved.
When the user goes to certain pages I take the UTC date/time coming back from the server and convert it to the user's local date/time and display it to them in a user friendly way.
Do I need a library like moment timezone for this or will the browser's native date methods like Intl.DateTimeFormat, new Date().getTimezoneOffset(), etc be enough? (I only need to support the latest modern browsers so I'm asking this from a "does it do what I need" ​point of view not a browser support POV).
It seems all I need are 2 things:
A way to get the user's timezone offset from UTC (so I can convert their local time to UTC to send to the server and also to convert UTC back to their local time to display it to them on certain pages)
A way get their timezone abbreviation (EST, PDT, CDT, etc) to show in the UI
Do I need a library for these? And if not why do people use such large libraries for working with timezones anyway?
You don't need a time zone library for the functionality you mentioned.
// Get a Date object from your date picker, or construct one
const d1 = new Date("2020-08-02T10:00");
// Convert it to a UTC-based ISO 8601 string for your back-end
const utcString = d1.toISOString();
// Later, you can create a new Date object from the UTC string
const d2 = new Date(utcString);
// And you can display it in local time
const s1 = d2.toString();
// Or you can be a bit more precise with output formatting if you like
const s2 = d2.toLocaleString(undefined, {timeZoneName: 'short'});
console.log("UTC: ", utcString);
console.log("Local Time (default string): ", s1);
console.log("Local Time (intl-based string): ", s2);
Keep in mind that not all time zones will have an abbreviation, so those ones will give output like "GMT+3".

How does Moment JS reads locale/language

I need to show date in localized format, so I used
moment().format('l');
function of Moment JS https://momentjs.com/#multiple-locale-support
It is not working as expected in different systems/browsers
root cause of the issue is that Moment reads current locale as "en" even when the environment is France ("fr")
console.log('moment lang: '+moment.lang());
console.log('userLanguage: '+window.navigator.userLanguage);
console.log('language: '+window.navigator.language);
Results produced:
moment lang: en
userLanguage: fr-FR
language: fr-FR
Moment will give correct locale formatted date if I explicitly set
moment().locale(window.navigator.userLanguage||window.navigator.language);
Do I really need to explicitly set locale in Moment or I am doing something wrong?
A note for duplicate question issue: question is how does Momentjs reads locale.
Yes you have set desired locale using moment.locale:
By default, Moment.js comes with English (United States) locale strings. If you need other locales, you can load them into Moment.js for later use.
To load a locale, pass the key and the string values to moment.locale.
Once you load a locale, it becomes the active locale. To change active locales, simply call moment.locale with the key of a loaded locale.
Please note tha lang is deprecated in 2.8.1
// Deprecated in 2.8.1
moment.lang(String);

Get the given date format (the string specifying the format) in javascript or momentjs

Given a datestring, how can I get the format string describing that datestring?
Put another way, how can I get the format string that Date() or MomentJS (might be different for each, that's fine) would use to parse that datestring if one didn't pass an explicit format to use?
So given '2016-01-01' it should output something like 'YYYY-MM-DD', for example.
(I am aware this is a simple question and may have an answer somewhere, but it is difficult to word concisely, so I could only find questions and answers about how to parse datestrings or how to display dates. None about how to output the format itself.)
Consolidating information from Matt Johnson's answer, some comments, and my own contribution.
With Moment.js (version 2.10.7+), you can use the Creation Data API. Something like this in Node.js:
moment('2016-01-01 00:00:00').creationData().format
outputs
'YYYY-MM-DD HH:mm:ss'
Just as any date parsing is, there is ambiguity about the format of many datestrings due to things such as locale (the order of months and days are switched between the US and Europe, for example). But the above method is sufficient for me.
You can't, without having additional information, such as the locale. For example, 01/12/16 could be Jan 12, 2016, December 1, 2016, or December 16, 2001.
Even when you know the locale, there are several places in the real world where more than one date format is used, depending on context.
See https://en.wikipedia.org/wiki/Date_format_by_country
However, if you are just trying to determine which one of multiple known formats was used to parse the input string, moment has an API for that called Creation Data. For example:
var m = moment("2016/06/10", ["YYYY-MM-DD", "MM/DD/YYYY"], true);
var f = m.creationData().format; // "MM/DD/YYYY"

Javascript users incorrect locale with date formatting

In javascript I'm using Date.toLocaleDateString to format my dates in the user's locale. While in theory it should work, it doesn't.
I am located in the UK. My computer is set to UK and my default language is set to en/gb in both system settings and the browser content settings. Yet, Firefox always displays dates the US format. Is there some trick I'm missing?
The full code for formatting is this:
var timestamp = ...; //some value from ajax call
var dt = new Date(timestamp);
$('#audit-date').text(dt.toLocaleDateString());
In the UK for today's date I would expect to see 05/02/2014, but I see 02/05/2014, which is the US version of it.
Use this to pass the locale.
var locale = window.navigator.userLanguage || window.navigator.language;
alert(date.toLocaleString(locale));
A quick look into to awesome MDN Documentation tells me that you need a locale parameter, otherwise the result depends on the browser. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
// British English uses day-month-year order
alert(date.toLocaleString("en-GB"));
// → "20/12/2012 03:00:00"
For more custom date formats I use the moment.js library. http://momentjs.com/

Globalization issue with Calendar Date

How to handle dates with different cultures i.e how can i use common javascript code to handle dates for all cultures.
For example -
Globalize.culture( "en" );
Globalize.parseDate( "1/2/2003" ); // Thu Jan 02 2003
Globalize.culture( "fr" );
Globalize.parseDate( "1/2/2003" ); // Sat Feb 01 2003
In the above code how i can make generic code instead of changing date format for different cultures.
Thanks in advance
You cannot. There is no date notation that is shared by all cultures. The example of 1/2/2003 is particularly illustrative: you cannot know what it means, unless you have reliable information about the cultural conventions that person who produced it was using. In fact, you would need to distinguish between en-US (US English) and en-GB (British English).
The Globalize.js library is meant to deal with this variation, not to remove it.
It is possible to allow different date notations e.g. as follows (code excerpt from my book [Going Global with JavaScript and Globalize.js][1]):
function read(dateInput) {
var languages = ['en', 'fi', 'sv', 'ru'];
var formats = ['d', 'D'];
var date;
for(var langNr in languages) {
for(var fmtNr in formats) {
date = Globalize.parseDate(dateInput,formats[fmtNr],languages[langNr]);
if(date != null) {
return date;
}
}
}
return null;
}
This would allow short and long date notations as used in (US) English, Finnish, Swedish, and Russian, so it would be fairly liberal and suitable for a situation where users are expected to use one of those languages.
But the more locales you add, the more ambiguities arise. If a notation like 1/2/2003 is allowed in different locales but has several meanings in them, then your loop structure would define which meaning is applied. This in turn could mean that input would be taken in a meaning that is differs from the user’s intent. It might be better to avoid all-numeric date notations for this reason. Formats that require month name are much safer.
Formats such as 2003-02-01 are unambiguous in principle, but only in principle, and they look unnatural to most people. You can read such formats in Globalize.js, though; you just need to specify the format explicitly.
You mean internationalisation. There are standards, such as ISO8601, that specify unambiguous formats such as 2012-02-01 for 1 February, 2012.
I don't think date formats are related to "culture", more to nationality. The vast majority of English speakers in the world use a format of day/month/year, that is related to the country in which they live rather than the any culture they may follow or support.
There are other unambiguous formats, such as always using the month name rather than number, e.g. 01-Feb-2012 or 1 February 2012. The same works for calendars other than Gregorian.
To be honest, your question is not very clear. From the context, I deduce you want to let users enter the date in their native format and use Globalize to somehow automatically "detect" what the format will be and apply appropriate parsing method.
If that is what you are after, it can't be done. You already know about differences in formatting for various countries. To make matters worse, there could be long or short format used (unfortunately Globalize does not support the concept of default format available in .Net by calling DateTime's ToString("g")). That means, that you may have things like "2012-10-31", "31.10.12" and "31 października 2012", which are all (more or less) valid Polish date formats.
I hope now you realize that allowing free-form input is not a good idea. So what to do instead? The answer is to use jQuery UI's Datepicker. It could be fairly easy localized, all you have to do is to add valid regional script:
$( "#datepicker" ).datepicker( $.datepicker.regional[ "fr" ] );
Then, to get JavaScript's Date object you call Datepicker's getDate() method:
var currentDate = $( ".selector" ).datepicker( "getDate" );
That's it. BTW. Datepicker allows for converting dates entered by end user (if you attach it to the text field). But of course it will be the format specified by regional script...

Categories