Ignore/don't convert timezone? - javascript

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.

Related

Return the date format for date without moment.js

I can't figure out how to build a function that does this
INPUT: dateToDateFormat('16/07/2022') -> OUTPUT: DD/MM/YYYY
INPUT: dateToDateFormat('07/16/2022') -> OUTPUT: MM/DD/YYYY
The input dates will be already formatted by .toLocaleString function
Edit:
I think I was not precise enough with the output, it should literally output MM/DD/YYYY as a string, not the actual date value
A) First of all, your desired date string conversion seems to be easy (solution below) without using any package/overhead.
B) However, if you need to process it further as a JS Date Object, things become more difficult. In this case, I like to provide some useful code snippets at least which might help you depending on your usecase is or what you are aiming for.
A) CONVERSION
Seems you need a simple swap of day and month in your date string?
In this case, you do not need to install and import the overhead of a package such as date-fns, moment or day.js.
You can use the following function:
const date1 = "16/07/2022"
const date2 = "07/16/2022"
const dateToDateFormat = (date) => {
const obj = date.split(/\//);
return `${obj[1]}/${obj[0]}/${obj[2]}`;
};
console.log("New date1:", dateToDateFormat(date1))
console.log("New date2:", dateToDateFormat(date2))
B) STRING TO DATE
Are you using your date results to simply render it as string in the frontend? In this case, the following part might be less relevant.
However, in case of processing them by using a JS Date Object, you should be aware of the following. Unfortunately, you will not be able to convert all of your desired date results/formats, here in this case date strings "16/07/2022" & "07/16/2022", with native or common JS methods to JS Date Objects in an easy way due to my understanding. Check and run the following code snippet to see what I mean:
const newDate1 = '07/16/2022'
const newDate2 = '16/07/2022'
const dateFormat1 = new Date(newDate1);
const dateFormat2 = new Date(newDate2);
console.log("dateFormat1", dateFormat1);
console.log("dateFormat2", dateFormat2);
dateFormat2 with its leading 16 results in an 'invalid date'. You can receive more details about this topic in Mozilla's documentation. Furthermore, dateFormat1 can be converted to a valid date format but the result is not correct as the day is the 15th and not 16th. This is because JS works with arrays in this case and they are zero-based. This means that JavaScript starts counting from zero when it indexes an array (... without going into further details).
CHECK VALIDITY
In general, if you need to further process a date string, here "16/07/2022" or "07/16/2022", by converting it to a JS Date Object, you can in any case check if you succeed and a simple conversion with JS methods provides a valid Date format with the following function. At least you have kind of a control over the 'invalid date' problem:
const newDate1 = '07/16/2022'
const newDate2 = '16/07/2022'
const dateFormat1 = new Date(newDate1);
const dateFormat2 = new Date(newDate2);
function isDateValidFormat(date) {
return date instanceof Date && !isNaN(date);
}
console.log("JS Date Object?", isDateValidFormat(dateFormat1));
console.log("JS Date Object?", isDateValidFormat(dateFormat2));
Now, what is the benefit? You can use this function for further processing of your date format depending on what you need it for. As I said, it will not help us too much as we still can have valid date formats but with a falsy output (15th instead of 16th).
CONVERT TO DATE OBJECT BY KNOWING THE FORMAT
The following function converts any of your provided kinds of dates ("MM/DD/YYYY" or "DD/MM/YYYY") to a valid JS Date Object and - at the same time - a correct date. However, drawback is that it assumes to know what kind of input is used; "MM/DD/YYYY" or "DD/MM/YYYY". The dilemma is, that this information is crucial. For example, JS does not know if, for example, "07/12/2022" is "MM/DD/YYYY" or "DD/MM/YYYY". It would return a wrong result.
const newDate1 = "07/16/2022"
const newDate2 = "16/07/2022"
function convertToValidDateObject(date, inputFormat) {
const obj = date.split(/\//);
const obj0 = Number(obj[0])
const obj1 = Number(obj[1])
const obj2 = obj[2]
//
// CHECK INPUT FORMAT
if (inputFormat === "MM/DD/YYYY") {
return new Date(obj2, obj0-1, obj1+1);
} else if (inputFormat === "DD/MM/YYYY") {
return new Date(obj2, obj1-1, obj0+1);
} else {
return "ERROR! Check, if your input is valid!"
}
}
console.log("newDate1:", convertToValidDateObject(newDate1, "MM/DD/YYYY"))
console.log("newDate2:", convertToValidDateObject(newDate2, "DD/MM/YYYY"))
console.log("newDate2:", convertToValidDateObject(newDate2, "MM/YYYY"))
If the wrong format is provided as a second argument, an error is provided in the console. In practise I suggest you to use a try-catch block ( I tried here, but it does not work here in this stackoverflow editor).
I wish you good luck. Hope these information can help you.

Merging partial moments

Unlike a vanilla date, a moment does not have any required units that must be passed to its constructor. For instance, this is a perfectly valid way to instantiate a moment, with the unpassed units defaulting to current date and 00:00 time:
moment.utc('07:35', 'HH:mm').toISOString();
> "2013-10-24T07:35:00.000Z" //let's just ignore the timezones for now, ok?
So how can partial moments be merged into one? For instance, I could just .set() first moment's hours to values from the second:
var mergee = moment.utc('07:35', 'HH:mm');
moment.utc('2015-01-01').
set('hours', mergee.get('hours')).
set('minutes', mergee.get('minutes')).
toISOString();
> "2015-01-01T07:35:00.000Z" //yay!
But what if I don't know in advance the format of the "mergee", or even what units it has parsed?
While not entirely supported or recommended, something like this will work:
var m1 = moment.utc('07:35', 'HH:mm');
var m2 = moment.utc('2015-01-01');
var merged = moment.utc(m1._i + ' ' + m2._i, m1._f + ' ' + m2._f);
The space separator isn't necessarily required, but it might prevent conflicts with certain formats.
I could see that you might have troubles though if both moments contained the same elements with different data.

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.

Problems validating in IE

i'm getting an error message on IE8....all other browsers seem to be fine...i've narrowed it down to specific parts of my JavaScript however i cant find a way around it. It seems to be the greater then or less then signs(i could be wrong). Anyone know a way around it(maybe another way of written the sign, writing and gt; wont do it)
example code:
var selectedDate = new Date(document.getElementById("ExpYear").value,document.getElementById("ExpMonth").value)
var nextmonth = selectedDate.setMonth(selectedDate.getMonth());
var last_date_of_selected_date = new Date(nextmonth -1);
var today = new Date();
today = new Date(today.getFullYear(), today.getMonth());
if (today > selectedDate) {<!--i think its the < sign-->
return false;
}
else {
return true;
}
window.onload = function() {
var a = document.getElementById("PaymentForm");
a.onsubmit = function() { return Validate() };
}
var selectedDate = new Date (document.getElementById("ExpYear").value,document.getElementById("ExpMonth").value)
I'm not sure if this solves your issue, but there are at least three problems with this line of code:
the Date constructor expects either zero arguments, one argument containing a timestamp in milliseconds or a string (discouraged) or three arguments containing year, month and day number respectively (possibly followed by four arguments containing hour, minute, second, millisecond)
the month parameter starts at 0 for January, so you probably should decrement the input value (unless you expect the user to enter a number in the range 0 – 11).
a semicolon is missing; though JavaScript interpreters have something called automatic semicolon insertion, it's likely you write better code using semicolons everywhere.
Update: in your second piece of code, the message about a being null or not an object is probably because there's no element with ID PaymentForm, so the line trying to attach an event handler to a will yield an error.
Moreover, you omitted a semicolon after the closing brace (and you probably forgot a closing brace and semicolon after return Validate();).
I see you're missing a semicolon on the selectedDate variable declaration.
Internet Explorer is extremely picky with semicolons.
var selectedDate = new Date (document.getElementById("ExpYear").value,document.getElementById("ExpMonth").value)

Categories