Globalization issue with Calendar Date - javascript

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

Related

Intl.DateTimeFormat() with format options doesn't work for 'it-CH'

I get a locale from the server and try to format a given date based on this locale formatting options and additional options. It works with all locales, but it-CH
date = new Date(2010,0,1)
new Intl.DateTimeFormat('it-CH', {day:'2-digit', month:'2-digit', year:'numeric'}).format(date)
// output: "01.01.2010"
The correct output should be 01/01/2010
It works though for locale it:
new Intl.DateTimeFormat('it', {day:'2-digit', month:'2-digit', year:'numeric'}).format(date)
// output: "01/01/2010"
Or with the locale it-CH if I don't include the year formatting in options:
new Intl.DateTimeFormat('it-CH', {day:'2-digit', month:'2-digit'}).format(date)
// output: "01/01"
The correct output should be 01/01/2010. I tested it on Window and Mac OS in the latest versions of Chrome.
Where this strange behaviour comes from, how can I fix it?
You can solve this problem by using the intl polyfill module to completely replace NodeJS’s implementation of intl.
First run npm i --save intl
Then you need to replace Intl by polyfill:
Intl = require("intl")
That's it. Now you can try:
const date = new Date();
const options = {
year: 'numeric',
day: 'numeric',
month: 'numeric',
hour: 'numeric',
minute: 'numeric'
};
const dateFormatted = new Intl.DateTimeFormat('pt-BR', options).format(date);
console.log(dateFormatted);
// expected output: 24/09/2019 17:43
Unfortunately the actual formatting of dates by toLocaleString is largely implementation dependent, so while it may be consistent for the most common languages and variants, it's not so good for those that are less common or where multiple date formats are commonly used (which is the case where I live).
The situation is quite complex. The "locale" is a BCP 47 language tag. The list of tags and subtags is maintained by IANA and changes from time–to–time. Further, the mapping of formats to tags and subtags is implementation dependent.
The bottom line is that there is uncertainty over what format should apply to a particular language and variant, and a huge number of local languages and variants (e.g. tribal languages) are not supported at all. So don't rely on toLocaleString doing all the work and getting it right all the time.
An alternative to leaving it all up to the implementation is to manually format the date in an unambiguous format using toLocaleString for the language of the individual components. That way where a specific language isn't supported, you can fall back to the browser default language (see PPS below) and be confident that what you're putting on the page is clear and not leaving it entirely to the implementation, e.g.
function getFormattedDate(d, lang){
return d.getDate().toLocaleString(lang) + ' '
+ d.toLocaleString(lang, {month:'long'}) + ', '
+ d.toLocaleString(lang, {year:'numeric'});
}
var d = new Date();
['it-CH', 'en-GB', 'ar-EG', 'zu-ZA', 'hz', undefined].forEach(
lang => console.log((lang||'Default') +
': ' + getFormattedDate(d, lang))
);
Don't get too hung up over supporting every possible format and language variant. It's far more important to ensure dates are unambiguous than whether the components are separated by commas, dashes, slashes or whatever the local variant uses customarily. As I look at formal correspondence in my locale, dates are represented in 3 or 4 different formats, often two different formats are used on the same page (e.g. in headers, text and tabular data).
PS: You should also test for support for toLocaleString before using it.
PPS: It would be really good if there was a way to test if a language tag is supported before using it, but as far as I can tell that's not possible. E.g. in the example above, "hz" is Herero, a language spoken by a particular ethnic group in southern Africa and likely not supported by any browser, so it should fall back to the browser default language.

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"

Moment.js : Format date according browser lang

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/

What is the "right" JSON date format?

I've seen so many different standards for the JSON date format:
"\"\\/Date(1335205592410)\\/\"" .NET JavaScriptSerializer
"\"\\/Date(1335205592410-0500)\\/\"" .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z" JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00" ISO 8601
Which one is the right one? Or best? Is there any sort of standard on this?
JSON itself does not specify how dates should be represented, but JavaScript does.
You should use the format emitted by Date's toJSON method:
2012-04-23T18:25:43.511Z
Here's why:
It's human readable but also succinct
It sorts correctly
It includes fractional seconds, which can help re-establish chronology
It conforms to ISO 8601
ISO 8601 has been well-established internationally for more than a decade
ISO 8601 is endorsed by W3C, RFC3339, and XKCD
That being said, every date library ever written can understand "milliseconds since 1970". So for easy portability, ThiefMaster is right.
JSON does not know anything about dates. What .NET does is a non-standard hack/extension.
I would use a format that can be easily converted to a Date object in JavaScript, i.e. one that can be passed to new Date(...). The easiest and probably most portable format is the timestamp containing milliseconds since 1970.
There is no right format; The JSON specification does not specify a format for exchanging dates which is why there are so many different ways to do it.
The best format is arguably a date represented in ISO 8601 format (see Wikipedia); it is a well known and widely used format and can be handled across many different languages, making it very well suited for interoperability. If you have control over the generated json, for example, you provide data to other systems in json format, choosing 8601 as the date interchange format is a good choice.
If you do not have control over the generated json, for example, you are the consumer of json from several different existing systems, the best way of handling this is to have a date parsing utility function to handle the different formats expected.
When in doubt simply go to the javascript web console of a modern browser by pressing F12 (Ctrl+Shift+K in Firefox) and write the following:
new Date().toISOString()
Will output:
"2019-07-04T13:33:03.969Z"
Ta-da!!
From RFC 7493 (The I-JSON Message Format ):
I-JSON stands for either Internet JSON or Interoperable JSON, depending on who you ask.
Protocols often contain data items that are designed to contain
timestamps or time durations. It is RECOMMENDED that all such data
items be expressed as string values in ISO 8601 format, as specified
in RFC 3339, with the additional restrictions that uppercase rather
than lowercase letters be used, that the timezone be included not
defaulted, and that optional trailing seconds be included even when
their value is "00". It is also RECOMMENDED that all data items
containing time durations conform to the "duration" production in
Appendix A of RFC 3339, with the same additional restrictions.
Just for reference I've seen this format used:
Date.UTC(2017,2,22)
It works with JSONP which is supported by the $.getJSON() function. Not sure I would go so far as to recommend this approach... just throwing it out there as a possibility because people are doing it this way.
FWIW: Never use seconds since epoch in a communication protocol, nor milliseconds since epoch, because these are fraught with danger thanks to the randomized implementation of leap seconds (you have no idea whether sender and receiver both properly implement UTC leap seconds).
Kind of a pet hate, but many people believe that UTC is just the new name for GMT -- wrong! If your system does not implement leap seconds then you are using GMT (often called UTC despite being incorrect). If you do fully implement leap seconds you really are using UTC. Future leap seconds cannot be known; they get published by the IERS as necessary and require constant updates. If you are running a system that attempts to implement leap seconds but contains and out-of-date reference table (more common than you might think) then you have neither GMT, nor UTC, you have a wonky system pretending to be UTC.
These date counters are only compatible when expressed in a broken down format (y, m, d, etc). They are NEVER compatible in an epoch format. Keep that in mind.
"2014-01-01T23:28:56.782Z"
The date is represented in a standard and sortable format that represents a UTC time (indicated by the Z). ISO 8601 also supports time zones by replacing the Z with + or – value for the timezone offset:
"2014-02-01T09:28:56.321-10:00"
There are other variations of the timezone encoding in the ISO 8601 spec, but the –10:00 format is the only TZ format that current JSON parsers support. In general it’s best to use the UTC based format (Z) unless you have a specific need for figuring out the time zone in which the date was produced (possible only in server side generation).
NB:
var date = new Date();
console.log(date); // Wed Jan 01 2014 13:28:56 GMT-
1000 (Hawaiian Standard Time)
var json = JSON.stringify(date);
console.log(json); // "2014-01-01T23:28:56.782Z"
To tell you that's the preferred way even though JavaScript doesn't have a standard format for it
// JSON encoded date
var json = "\"2014-01-01T23:28:56.782Z\"";
var dateStr = JSON.parse(json);
console.log(dateStr); // 2014-01-01T23:28:56.782Z
JSON itself has no date format, it does not care how anyone stores dates. However, since this question is tagged with javascript, I assume you want to know how to store javascript dates in JSON. You can just pass in a date to the JSON.stringify method, and it will use Date.prototype.toJSON by default, which in turns uses Date.prototype.toISOString (MDN on Date.toJSON):
const json = JSON.stringify(new Date());
const parsed = JSON.parse(json); //2015-10-26T07:46:36.611Z
const date = new Date(parsed); // Back to date object
I also found it useful to use the reviver parameter of JSON.parse (MDN on JSON.parse) to automatically convert ISO strings back to javascript dates whenever I read JSON strings.
const isoDatePattern = new RegExp(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/);
const obj = {
a: 'foo',
b: new Date(1500000000000) // Fri Jul 14 2017, etc...
}
const json = JSON.stringify(obj);
// Convert back, use reviver function:
const parsed = JSON.parse(json, (key, value) => {
if (typeof value === 'string' && value.match(isoDatePattern)){
return new Date(value); // isostring, so cast to js date
}
return value; // leave any other value as-is
});
console.log(parsed.b); // // Fri Jul 14 2017, etc...
The prefered way is using 2018-04-23T18:25:43.511Z...
The picture below shows why this is the prefered way:
So as you see Date has a native Method toJSON, which return in this format and can be easily converted to Date again...
In Sharepoint 2013, getting data in JSON there is no format to convert date into date only format, because in that date should be in ISO format
yourDate.substring(0,10)
This may be helpful for you
I believe that the best format for universal interoperability is not the ISO-8601 string, but rather the format used by EJSON:
{ "myDateField": { "$date" : <ms-since-epoch> } }
As described here: https://docs.meteor.com/api/ejson.html
Benefits
Parsing performance: If you store dates as ISO-8601 strings, this is great if you are expecting a date value under that particular field, but if you have a system which must determine value types without context, you're parsing every string for a date format.
No Need for Date Validation: You need not worry about validation and verification of the date. Even if a string matches ISO-8601 format, it may not be a real date; this can never happen with an EJSON date.
Unambiguous Type Declaration: as far as generic data systems go, if you wanted to store an ISO string as a string in one case, and a real system date in another, generic systems adopting the ISO-8601 string format will not allow this, mechanically (without escape tricks or similar awful solutions).
Conclusion
I understand that a human-readable format (ISO-8601 string) is helpful and more convenient for 80% of use cases, and indeed no-one should ever be told not to store their dates as ISO-8601 strings if that's what their applications understand, but for a universally accepted transport format which should guarantee certain values to for sure be dates, how can we allow for ambiguity and need for so much validation?
it is work for me with parse Server
{
"ContractID": "203-17-DC0101-00003-10011",
"Supplier":"Sample Co., Ltd",
"Value":12345.80,
"Curency":"USD",
"StartDate": {
"__type": "Date",
"iso": "2017-08-22T06:11:00.000Z"
}
}
There is only one correct answer to this and most systems get it wrong. Number of milliseconds since epoch, aka a 64 bit integer. Time Zone is a UI concern and has no business in the app layer or db layer. Why does your db care what time zone something is, when you know it's going to store it as a 64 bit integer then do the transformation calculations.
Strip out the extraneous bits and just treat dates as numbers up to the UI. You can use simple arithmetic operators to do queries and logic.
The following code has worked for me. This code will print date in DD-MM-YYYY format.
DateValue=DateValue.substring(6,8)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(0,4);
else, you can also use:
DateValue=DateValue.substring(0,4)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(6,8);
I think that really depends on the use case. In many cases it might be more beneficial to use a proper object model (instead of rendering the date to a string), like so:
{
"person" :
{
"name" : {
"first": "Tom",
"middle": "M",
...
}
"dob" : {
"year": 2012,
"month": 4,
"day": 23,
"hour": 18,
"minute": 25,
"second": 43,
"timeZone": "America/New_York"
}
}
}
Admittedly this is more verbose than RFC 3339 but:
it's human readable as well
it implements a proper object model (as in OOP, as far as JSON permits it)
it supports time zones (not just the UTC offset at the given date and time)
it can support smaller units like milliseconds, nanoseconds, ... or simply fractional seconds
it doesn't require a separate parsing step (to parse the date-time string), the JSON parser will do everything for you
easy creation with any date-time framework or implementation in any language
can easily be extended to support other calendar scales (Hebrew, Chinese, Islamic ...) and eras (AD, BC, ...)
it's year 10000 safe ;-) (RFC 3339 isn't)
supports all-day dates and floating times (Javascript's Date.toJSON() doesn't)
I don't think that correct sorting (as noted by funroll for RFC 3339) is a feature that's really needed when serializing a date to JSON. Also that's only true for date-times having the same time zone offset.

Manipulating dates in Javascript without the Date object

It appears I can't use the javascript Date object as it inherintly defaults to US dates when you initialise with a datestring. There is no way of passing any culture information to the date object
I.e. No matter what the clients locale settings are
var d = new Date("08/10/2009") will always create a date object representing the 10th August 2009 rather than the 8th October 2009 if the clients locale was the UK.
So given that my requirement is to be able to add/subtract days/months/years easily is there a clever way of doing this easily without the Date object
All i need to do is add a day to a date (or a string representation of a date). so if my code detects the locale setttings are in the US, when it sees a string like "10/08/2009" it whacks it up to "10/09/2009" but if it had detected it was in the UK it would have know it a uk string representation of a date and whacked it up to "09/10/2009"
For date manipulation and localization on JavaScript I always recommend the DateJS library.
This library abstracts the use of Date objects, has a very good localization options, powerful date parsing and formatting, and it also has a very nice fluent API.
If you know you are getting input formatted dd/mm/yyyy you can easily assemble the correct date.
function britDay(D){
D= D.match(/\d+/g);
return new Date(+D[2], D[1]-1, +D[0]);
}
toLocaleDateString will return the date in the format expected by the user.
Relying on the user input that obeys particular formatting rules is optimistic-
which is why most sites use separate, labeled inputs or select fields for the month, date and year.
You probably know that it's easy to add one day to a date, just add 86,400 * 1000 milliseconds to the date. It sounds like displaying in your locale is the issue; does Date.toLocaleString() not do the right thing for you?
dojo.date.locale.parse will be able to parse a formatted string according the locale of your choice. It has a table of cultural data based off unicode.org/cldr. See this article for more information.

Categories