Intl.DateTimeFormat 'calendar' and 'numberingSystem' options never work - javascript

I'm trying to set the calendar and numberingSystem options for an Intl.DateTimeFormat object. When I set them via the locale argument as below it works:
var dateFormat = new Intl.DateTimeFormat('en-US-u-ca-chinese-nu-arab');
var usedOptions = dateFormat.resolvedOptions();
console.log("resolved calendar: " + usedOptions.calendar);
console.log("resolved numbering: " + usedOptions.numberingSystem);
But when I try to set them via options argument as below, it doesn't work. Mozilla MDN specifically mentions that this should work:
But when you try it, it doesn't:
var options = {calendar: 'chinese', numberingSystem: 'arab'};
var dateFormat = new Intl.DateTimeFormat('default', options);
var usedOptions = dateFormat.resolvedOptions();
console.log("resolved calendar: " + usedOptions.calendar);
console.log("resolved numbering: " + usedOptions.numberingSystem);
I have tested this on node.js and Firefox with the same results. Online javascript emulators also give the same result.
I could still set them via the locale string but it's rather ugly. I prefer to use the options argument if possible.

I think Mozilla MDN may be wrong about this. If I am reading the ECMA-402 spec for constructing a DateTimeFormat correctly, in step 8 of §13.1.1 the calendar option is considered, but then in step 17 we go to ResolveLocale where in step 9.i.iv of §9.2.7 the calendar option only overrides the default if it is already a possible choice for the calendar in that locale.
That said, I cannot seem to come up with a case where it works as I expect it would from reading the spec, so maybe I am reading it wrong. I would expect that the second line here would return 'japanese', because the Japanese and Gregorian calendars would be valid choices in the Japanese locale:
> new Intl.DateTimeFormat('ja').resolvedOptions().calendar
'gregory'
> new Intl.DateTimeFormat('ja', { calendar: 'japanese' }).resolvedOptions().calendar
'gregory'

Related

Ignore/don't convert timezone?

My page was working fine and displaying dates and times as expected until I had to add new Date() to avoid the momentjs deprecation warning. Now my date is 5 hours off what it should be.
How can I fix this? vd and v should both be 12:14:26 and, in this instance, fn should be "Seconds ago".
Here is the full code:
var k = key;
var v = obj[key];
var vd = Date.parse(obj[key]));
if (moment(vd).isValid()) {
var fn = moment(vd).fromNow();
v = fn;
}
return {
name: k,
value: v
};
I tried the following based on this post, but it brought back the momentjs deprecation warning:
var vd = new Date(Date.parse(obj[key])).toUTCString();
(and still didn't work)
__________________________________________________________________________________
Threaded comments would be cool
What happens if you just run moment(v)? Should work. – Maggie Pint
It does work, but I get the deprecation warning.
I just looked closer. The format of V is ISO8601 with offset, so you shouldn't be getting a deprecation if you just call moment(v). If you are, try moment(v, moment.ISO_8601) – Maggie Pint
Again, works, but I still get the deprecation warning.
instead of var vd = new Date(Date.parse(obj[key])).toUTCString(); did you try var vd = new Date(Date.parse(obj[key])).toISOString(); ? or even simplier var vd = Date.parse(obj[key]) – user3
With .toISOString() it outputs "Invalid Date". var vd = Date.parse(obj[key]) Is what I had originally, it works as expected but I get the warning.
Your v string appears to use ISO8601 format already? Maybe append the Z, or ask moment to recognise it automatically as UTC when timezone info is missing – Bergi
I just tried var vd = new Date(Date.parse(obj[key] + "Z")); and it works!
In your example, you're passing a value for v as an ISO8601 string without any offset specified. It is ambiguous as to what point in time you are actually talking about.
Because of changes in the ECMAScript specification, the value will be interpreted as UTC by some browsers, and as local time by others.
The way to avoid this ambiguity is to not use the date constructor. Anywhere you have new Date or Date.parse, you're introducing potential differences in behavior. Just use moment's own parser, and be specific as to your intent.
// your input
var v = "2016-09-14T12:14:26.149";
// pick only one of these:
var m = moment(v); // input is local time
var m = moment.utc(v) // input is UTC
// then proceed as normal
if (m.isValid()) {
var fn = m.fromNow();
// etc.
}
If the input is in some other time zone, or has some other specific fixed offset from UTC, then you have various other options for constructing the moment object. But really, don't rely on the Date object to do the parsing. That's the whole point of the deprecation message.
If the input is not always in the expected format (you're looking for invalid inputs, etc.), then you should specify the expected format such that you don't get the deprecation warning. For example:
var m = moment.utc(v, "YYYY-MM-DD[T]HH:mm:ss.SSS");
This particular format is also available as a constant:
var m = moment.utc(v, moment.ISO_8601);
This, and much more are spelled out in the Moment documentation.
It looks like the problem is when you create the date that recovered from the database... because it does not have the timezone... but you know it is "-0500", might be you can add that part hard coded... not ideal but it works
Look at this example:
function getMoment(v){
var vd = moment(v+"-0500");
var result = "?";
if (vd.isValid()){
result = vd.fromNow();
}
return result;
}
Check the getMoment() function, you can just copy and paste and use it in your code.

Show yyyyww (yearweek) in Google Scripts / Javascript (Sunday-Monday)

I'm really struggling to do a clean, efficient way of showing yearweek for Sunday to Monday
e.g.:
201624
201625
201626
201627
201628
Is there an efficient way to do so in Google Scripts or Javascript without using a library?
Thanks!
Found a solution! :
var yearMonth = parseInt(Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "yyyyww")).toFixed(0);
It was provided by user: Balu Ertl at Get week of year in JavaScript like in PHP
I would use Moment.js. Documentation for the use can be found here for the format you are looking for http://momentjs.com/docs/#/displaying/.
To have it work with google script you will need to first add it to the libraries using MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48, then you need to load it in using something like var moment = Moment.load().
From here you can get the month and year already formatted into your requested format.
var date = getDate();
var wwyy = moment(date).format('wo, YY');
My appologies, my format wasn't exactly as you wanted it to be. To answer in the format you are looking for:
var date = new Date();
var yyyyww = moment(date).format('YYYY ww');

Settnig duration values in jtsage datebox in mode durationflipbox

I'm having difficulty setting a time (duration) value in a datebox. A simple demonstration of the problem is if I do something like:
function initDuration() {
this.d['header Text'] = "Set";
this.d['headerText'] = "Set Duration";
var element = 'input#'+this.element[0].id;
var currentDt = $(element).datebox('getTheDate');
// ***************
var dt = $(element).datebox('parseDate', '%H:%M', this.element[0].value); // Where this.element[0].value = "01:00:00"
// ***************
$(element).datebox('setTheDate', this.element[0].value);
$(element).trigger('datebox', { 'method': 'doset' });
}
dt just contains the current date/time; i.e. jtsage didn't like it. The element is defined (in jade) as:
input.Duration(type="text" name="duration" form="form#{i}"
id="duration#{i}" value="#{map[i].duration}" data-role="datebox"
data-options=
'{"mode":"durationflipbox", "overrideDurationOrder":["h","i"],'
+' "overrideTimeFormat": "%l:%M", "minuteStep":15, "beforeOpenCallback": "initDuration"}')
Also I'm not sure how to change the flipbox title. The 2nd line in initDuration() sets the text for the button but the title still says 'Set Time'.
Because of the first problem the last 2 lines in initDuration() don't do what I want. i.e. they just use the current time, whatever that happens to be.
My apologies that this is going to be an incomplete answer, but it was going to be too long for a comment.
For the title - give "overrideHeaderText" a shot instead. It is entirely possible that I screwed this up at some point, it's not a feature I use in any of my own projects.
Next...
var dt = $(element).datebox('parseDate', '%H:%M', this.element[0].value); // Where this.element[0].value = "01:00:00"
I think I am reading you correctly that "dt" isn't containing what you are expecting. It's because 01:00:00 != %H:%M - to read this "format", you'd need to either use "%H:%M:%S" or "%H:%M:00" (the later ignoring the seconds field).
That said, I think what you are trying to do is set a duration, which, is a little different. There are a few ways to do it - and I'm noticing that there isn't a lot of support to do it functionally. The simplest method, is the set the value of the input, and let datebox handle the math - just be aware that the format you drop into the input must be exactly the same as the output format - it will read it when the control opens (or is initialized if the control is being shown inline - if you are doing it inline, and set the value "later", you can use the 'refresh' method to update it).
For what it's worth, if you really, really, really want to use the setTheDate method, duration modes work by comparing "theDate" (the publicly available date, i.e. setTheDate, getTheDate) with an internal initDate - which is not exposed to the API, but can be found here:
$(element).data('jtsage-datebox').initDate
So, in pseudo-code, for a duration of an hour
myNewDate = $(element).data( 'jtsage-datebox' ).initDate;
myNewDate.setHour( myNewDate.getHour() + 1 );
$(element).datebox( 'setTheDate', myNewDate );

Dijit DateTextBox - setting the date in ISO/numeric format?

I'm using DateTextBox as one of many controls in my screen. I register them in one place and then batch set values to them in loop, calling set('value', val) on each of them. All controls behave correctly, only the DateTextBox won't accept the data from server.
Initially java's Date was serialized as long (ex. 1280959200000), but when I've changed to ISO format (ex. "2010-08-04T22:00:00.000+0000") it isn't accepted either. But both are accepted date formats for new Date() constructor.
On the output I get the date value in ISO format: "2013-08-04T22:00:00.000Z" so it should be also accepted on input.
What can I do with DateTextBox to make it accept values in all formats supported by JavaScript's Date object, or one of the formats that can be returned from my server?
I think the fundamental problem is that the Javascript built-in Date object only accepts certain formats, and Dojo is relying on that built-in-behavior. At work, we have a similar issue, where lots of legacy PHP code is accustomed to passing dates around in a Mysql-derived format (ex. YYYY-MM-DD HH:MM:SS)
Our current workaround is to subclass dijit/form/DateTextBox, which also lets us impose some UI improvements. When something tries to set a value which isn't already a Date object and looks like a MySQL datetime, this code re-forms it to match ISO-8601 and passes it on through.
Dojo 1.9 code for a custom version of DateTextBox:
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dijit/form/DateTextBox"
], function(declare, lang, array, DateTextBox){
var clazz = declare([DateTextBox], {
_mysqlStyleExp : /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})$/,
postMixInProperties: function(){ // change value string to Date object
this.inherited(arguments);
this.constraints.datePattern = "yyyy-MM-dd"; // Affects display to user
},
_convertMysqlDateToIso: function(value){
value = lang.trim(value);
var matches = this._mysqlStyleExp.exec(value);
if(matches !== null){
// Put the "T" in the middle and add fractional seconds with UTC
// timezone
// If your MySQL dates are NOT in UTC, obviously this will screw things up!
return matches[1] + "T" + matches[2] + ".000Z";
}else{
return null;
}
},
_setValueAttr : function(/*Date|String*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
/*
We want to be slightly more permissive in terms of the strings that can be set in order to support
older code... But someday it'd be nice to standardize on Date.toJSON, so warn.
*/
if(typeof(value) === "string"){
var isoDate = this._convertMysqlDateToIso(value);
if(isoDate !== null){
console.warn("Converting non-ISO date of "+value);
value = isoDate;
}
}
this.inherited(arguments);
}
});
return clazz;
});
Note that this only affects data flowing into the Dojo widget.
The docs say:
The value of this widget as a JavaScript Date object, with only
year/month/day specified.
So instead of this (which I assume you're currently doing):
new dijit.form.DateTextBox({value: "2010-08-04T22:00:00.000+0000"}, domNode);
Do this:
var myDate = new Date("2010-08-04T22:00:00.000+0000");
new dijit.form.DateTextBox({value: myDate}, domNode);

Receiving Invalid Argument in IE8

I've been staring at this for hours and could really use some help. I'm working with some existing code for a movie theater website and the following should fill a select list with dates ranging from today to a max date from an xml file.
function populateSelect(xmlDoc, elSel) {
var dmindate = new Date();
var showings = xmlDoc.getElementsByTagName('Session');
fmaxdate = "";
for (var showing = 0; showing < showings.length; showing++) {
if (retText(showings[showing].getElementsByTagName('Date_time')[0]) > fmaxdate) {
fmaxdate=retText(showings[showing].getElementsByTagName('Date_time')[0]);//get the Max Date
}
}
var dmaxdate = new Date.parseString(fmaxdate, "yyyyMMddHHmmss");
while(dmindate <= dmaxdate){ //Fill in the Select List
var elOptNew = document.createElement('option');
elOptNew.text = dmindate.format("EE NNN d, yyyy");
elOptNew.value = dmindate.format("MM/dd/yyyy");
dmindate.setDate(dmindate.getDate()+1);
try {
elSel.add(elOptNew, null); // standards compliant doesn't work in IE
}
catch(ex) {
elSel.add(elOptNew); // IE only
}
}
}
This works perfectly fine in FF, Chrome and Safari but IE8 doesn't display the dropdown with dates and it showed the Invalid Argument as being the same line as the closing bracket for try.
Any help would be greatly appreciated!
I don't know where Date.prototype.parseString or format methods come from, presumably you are adding some date library. They aren't part of ECMAScript ed 3 or 5.
You can replace these lines:
> var elOptNew = document.createElement('option');
> elOptNew.text =dmindate.format("EE NNN d, yyyy");
> elOptNew.value = dmindate.format("MM/dd/yyyy");
with:
var elOptNew = new Option(dmindate.format("EE NNN d, yyyy"), // option text
dmindate.format("MM/dd/yyyy")); // option value
then add it to the select:
elSel.appendChild(elOptNew);
The above will work in all versions of IE and other browsers. See http://dev.w3.org/html5/spec/single-page.html#the-option-element for details of the Option constructor.
Edit
In the DOM 2 HTML specification for the add method it says:
This method is the equivalent of the appendChild method of the Node
interface if the before parameter is null.
That doesn't mean to pass the ECMAScript null object, it means "if there is no second parameter". The specification is language neutral, it isn't javascript specific. The HTML5 OptionsCollection add method is the same (i.e. "null" means no parameter, not the javascript null object).
From the documentation I could find, having a null parameter doesn't make any sense. However, it is clear that the JavaScript engines in the different browsers handle this method differently, and that IE doesn't like null as the second parameter.
So, as per the mantra, you should use jQuery. It is good and does all things. It does actually help protect you from differences between browser implementations of the DOM, because it has a fairly broad compatibility. It fixed this guy's issue anyway.
You will probably want to use append() instead of the add(). For example:
var elOptNew = $('<option></option>');
...
elSel.append(elOptNew);
There is also an alternative way to add new options in to a select, i.e
var opts = elSel.options;
opts[opts.length] = new Option(dmindate.format("EE NNN d, yyyy"), dmindate.format("MM/dd/yyyy"));
Example that works in all mejor browsers.
Try to use
elSel.options.add(elOptNew)
This must work in all browsers. See example.

Categories