Moment JS - UTC to Local timestamp fails comparison - javascript

When converting a UTC date format to timestamp this condition will always fail
const start_time = "2017-03-02T15:57:00Z";
const stop_time = "2017-03-02T17:51:00Z";
const local_timestamp = 1488498242256; // Thu Mar 02 2017 16:44:02 GMT-0700 (MST)
const start = moment(start_time).valueOf(); // 1488470220000
const stop = moment(stop_time).valueOf(); // 1488477060000
const is_between = local_timestamp >= start && local_timestamp <= stop; // false
So I tried this and still failed
const start = moment(start_time).utc().valueOf(); // 1488470220000
const stop = moment(stop_time).utc().valueOf(); // 1488477060000
const is_between = local_timestamp >= start && local_timestamp <= stop; // false
Same thing here
const now = moment(local_timestamp);
const isBetween = now.isBetween(start, stop); // false
Please help me understand this.

When converting a UTC date format to timestamp this condition will always fail
A timestamp is anything that represents a date or time, so "2017-03-02T15:57:00Z", "Thu Mar 02 2017 16:44:02 GMT-0700 (MST)" and 1488498242256 are all timestamps.
1488498242256 represents "2017-03-02T23:44:02.256Z" which is not between "2017-03-02T15:57:00Z" and "2017-03-02T17:51:00Z", so the expected result of your tests is false.
So I tried this and still failed
It's not failing, it's returning the expected result.
When you do, say:
new Date(1488498242256)
then a Date instance is created with a time value of 1488498242256, which represents "2017-03-02T23:44:02.256Z". When you write this to output that generates a string, usually Date.prototype.toString is called and a string is generated in what the browser developers have determined is a human friendly format.
Typically this means that the host system timezone offset is used to generate the string and you see something like:
"Thu Mar 02 2017 16:44:02 GMT-0700 (MST)"
On SO, the console seems to use toISOString instead of the default toString, e.g.
var date = new Date(1488498242256);
// Standard output for the host environment
console.log(date);
// Call Date.prototype.toString specifically
console.log(date.toString());

If start and end are UTC times, then use moment.utc(start_time) and moment.utc(stop_time)
But it doesn't seem logical to compare UTC dates against a local date. That is what it looks like you are attempting.

Related

What if I give parameter for Date.prototype.getTime()?

I create date in two ways:
new Date('some date').getTime();
new Date().getTime('some date');
I did it before I had read on MDN, that Date.prototype.getTime() doesn't have parameter. It means second way is wrong. Nevertheless, it gives the same date value the right way gives (new Date('*some date*').getTime();) but amount of milliseconds is different and I don't get why.
Could someone explain me?
(function () {
let dateToCount = "Jan 01, 2022 00:00:00";
let date1 = new Date(dateToCount).getTime();
let date2 = new Date().getTime(dateToCount);
console.log(Date(date1).toString()); // Tue Oct 19 2021 22:41:59 GMT+0300 (Eastern European Summer Time)
console.log(Date(date2).toString()); // Tue Oct 19 2021 22:41:59 GMT+0300 (Eastern European Summer Time)
console.log(`date1 = ${date1} ms`); // date1 = 1640988000000 ms
console.log(`date2 = ${date2} ms`); // date2 = 1634672519002 ms
console.log(`date1 - date2 = ${+date1 - (+date2)} ms`); // date1 - date2 = 6315480998 ms
})();
it gives the same date value the right way gives
No, it doesn't - it just that when you were debugging with console.log(Date(date1).toString()); you fell in yet another trap: missing the new operator in the call the Date. As MDN puts it:
Calling the Date() function (without the new keyword) returns a string representation of the current date and time, exactly as new Date().toString() does. Any arguments given in a Date() function call (without the new keyword) are ignored; regardless of whether it’s called with an invalid date string — or even called with any arbitrary object or other primitive as an argument — it always returns a string representation of the current date and time.
So if you fix that as well, you'll realise that the two different millisecond values you get back from getTime() actually do represent two different dates:
const dateToCount = "Jan 01, 2022 00:00:00";
const date1 = new Date(dateToCount).getTime();
const date2 = new Date().getTime(dateToCount);
console.log(new Date(date1).toString()); // Sat Jan 01 2022 00:00:00, as expected
console.log(new Date(date2).toString()); // Surprise!
console.log(`date1 = ${date1} ms`);
console.log(`date2 = ${date2} ms`);

Include millisecond data in JavaScript Date

I have a requirement to send the current system date to microservices on search. The time should include milliseconds information as well. For now I was sending new Date() for the same and it looked like:
Thu Aug 31 2017 15:06:37 GMT+0530 (India Standard Time)
However I need the milliseconds information as well so the time should look like:
Thu Aug 31 2017 15:06:37.228 GMT+0530 (India Standard Time)
Here 228 is the millisecond at that moment that I can extract using getMilliseconds() method of date. The question is how can I add this in the date so that it works for all locations wherever the application is accessed?
If you don't mind having the result as a string, this will show the output you are looking for:
// ES5
var fmtDateMsES5 = function(date) {
var splitDate = date.toString().split(' ');
splitDate[4] = splitDate[4] + '.' + date.getMilliseconds();
return splitDate.join(' ');
}
// log output (ES5)
console.log('ES5 output\n', fmtDateMsES5(new Date()));
// ES6
const fmtDateMsES6 = date => {
const splitDate = date.toString().split(' ');
splitDate[4] = `${splitDate[4]}.${date.getMilliseconds()}`;
return splitDate.join(' ');
};
// log output (ES6)
console.log('ES6 output\n', fmtDateMsES6(new Date()));
// ES5 and ES6 functions logged simultaneously
console.log(
`\nES5 and ES6 functions logged simultaneously`,
`\n${'-'.repeat(55)}`,
`\nES5 output ${fmtDateMsES5(new Date())}`,
`\nES6 output ${fmtDateMsES6(new Date())}`
);
Initially I saw the format method on the Date object but this is not built-in and requires a library.
If you must use a time library I would recommend the excellent moment.js and use the "SSS" syntax to get the milliseconds, for example:
var now = moment().format('MMM DD h:mm.SSS A');
//Sep 12 8:21.167 AM
http://jsfiddle.net/kLL2eobh/

how to disable moment.js daylight timezone conversion

It is possible to disable the daylight timezone conversion in moment.js?
http://plnkr.co/edit/MjFelt?p=preview
$scope.obj.date = moment('2016-06-03T04:00:00.000Z');
Basically my application deals with events and dates only, but moment.js converting the daylight savings time is causing issue with dates. Does it have any setting which will disable it across the entire application usage?
If you are saying that you want moment to display your date and time (which is UTC, as indicated by the 'Z'), exactly as is, you should use moment.utc:
moment.utc('2016-06-03T04:00:00.000Z').format()
"2016-06-03T04:00:00Z"
When you use the default moment constructor, as you are now, you are telling moment to convert your UTC time to local time, and this is why you are seeing a time difference. For instance, on my local machine (I am currently UTC-5) I get the following:
moment('2016-06-03T04:00:00.000Z').format()
"2016-06-02T23:00:00-05:00"
This question comes up quite a lot, so I wrote this blog post that explains moment's constructor functions and how it converts ISO8601 dates in detail: https://maggiepint.com/2016/05/14/moment-js-shows-the-wrong-date/
In my case, I had a problem with timezone changing due to 'daylight saving time'.
I had the next period:
{
"from": "2020-10-01 00:00:00 +0200",
"to":"2020-11-01 00:00:00 +0100",
}
And I wanted to get:
{
"from": "2020-10-01 00:00:00 +0200",
"to":"2020-11-01 00:00:00 +0200",
}
My solution is to get current (local) timezone and set it to the both date moment:
const currentTzOffset = moment().utcOffset(); // getting current timezone offset
const startToLocalZone = moment(from, yourDateFormat)
.local() // just checking. not sure if this is necessary
.utcOffset(currentTzOffset) // put your tz to here
.format(yourDateFormat);
const endToLocalZone = moment(to, yourDateFormat)
.local() // just checking. not sure if this is necessary
.utcOffset(currentTzOffset) // put your tz to here
.format(yourDateFormat);
console.log(startToLocalZone); // output: "2020-10-01 00:00:00 +0200"
console.log(endToLocalZone); // output: "2020-11-01 00:00:00 +0200"
And dont forget to set your date format instead 'yourDateFormat'
var tz = 'America/Vancouver'; // or whatever your time zone is
var dt = '2022-03-13T07:00:00.101Z'; // or whatever date/time you're working with
var momentVal = moment.tz(dt,tz)
function isNextDayDST(mObj){
return mObj.clone().add(1, 'days').isDST();
}
function isTodayDST(mObj) {
return mObj.clone().isDST();
}
function getDSTHourCompensation(mObj) {
const todayDST = isTodayDST(mObj.clone());
const tomorrowDST = isNextDayDST(mObj.clone());
if(todayDST == false && tomorrowDST == true) {
return 1
}
if(todayDST == true && tomorrowDST == false) {
return -1
}
return 0
}
function removeDST(mObj){
const hourCompentation = getDSTHourCompensation(mObj);
return mObj.clone().add(hourCompentation, 'hours');
}
console.log(momentVal.format('YYYY-MM-DD HH:mm'))
console.log(removeDST(momentVal).format('YYYY-MM-DD HH:mm'))
Maybe use the moment lib to compensate for the hours when you want to remove DST for the particular case.

Convert date to UTC using moment.js

Probably and easy answer to this but I can't seem to find a way to get moment.js to return a UTC date time in milliseconds. Here is what I am doing:
var date = $("#txt-date").val(),
expires = moment.utc(date);
Any idea what I am doing wrong?
This is found in the documentation. With a library like moment, I urge you to read the entirety of the documentation. It's really important.
Assuming the input text is entered in terms of the users's local time:
var expires = moment(date).valueOf();
If the user is instructed actually enter a UTC date/time, then:
var expires = moment.utc(date).valueOf();
I use this method and it works. ValueOf does not work for me.
moment.utc(yourDate).format()
As of : moment.js version 2.24.0
let's say you have a local date input, this is the proper way to convert your dateTime or Time input to UTC :
var utcStart = new moment("09:00", "HH:mm").utc();
or in case you specify a date
var utcStart = new moment("2019-06-24T09:00", "YYYY-MM-DDTHH:mm").utc();
As you can see the result output will be returned in UTC :
//You can call the format() that will return your UTC date in a string
utcStart.format();
//Result : 2019-06-24T13:00:00
But if you do this as below, it will not convert to UTC :
var myTime = new moment.utc("09:00", "HH:mm");
You're only setting your input to utc time, it's as if your mentioning that myTime is in UTC, ....the output will be 9:00
This will be the answer:
moment.utc(moment(localdate)).format()
localdate = '2020-01-01 12:00:00'
moment(localdate)
//Moment<2020-01-01T12:00:00+08:00>
moment.utc(moment(localdate)).format()
//2020-01-01T04:00:00Z
moment.utc(date).format(...);
is the way to go, since
moment().utc(date).format(...);
does behave weird...
This worked for me. Others might find it useful.
let date = '2020-08-31T00:00:00Z'
moment.utc(moment(date).utc()).format() // returns 2020-08-30T22:00:00Z
If all else fails, just reinitialize with an inverse of your local offset.
var timestamp = new Date();
var inverseOffset = moment(timestamp).utcOffset() * -1;
timestamp = moment().utcOffset( inverseOffset );
timestamp.toISOString(); // This should give you the accurate UTC equivalent.
This moment.utc(stringDate, format).toDate() worked for me.
This moment.utc(date).toDate() not.
here, I'm passing the date object and converting it into UTC time.
$.fn.convertTimeToUTC = function (convertTime) {
if($(this).isObject(convertTime)) {
return moment.tz(convertTime.format("Y-MM-DD HH:mm:ss"), moment.tz.guess()).utc().format("Y-MM-DD HH:mm:ss");
}
};
// Returns if a value is an object
$.fn.isObject = function(value) {
return value && typeof value === 'object';
};
//you can call it as below
$(this).convertTimeToUTC(date);
Read this documentation of moment.js here.
See below example and output where I convert GMT time to local time (my zone is IST) and then I convert local time to GMT.
// convert GMT to local time
console.log('Server time:' + data[i].locationServerTime)
let serv_utc = moment.utc(data[i].locationServerTime, "YYYY-MM-DD HH:mm:ss").toDate();
console.log('serv_utc:' + serv_utc)
data[i].locationServerTime = moment(serv_utc,"YYYY-MM-DD HH:mm:ss").tz(self.zone_name).format("YYYY-MM-DD HH:mm:ss");
console.log('Converted to local time:' + data[i].locationServerTime)
// convert local time to GMT
console.log('local time:' + data[i].locationServerTime)
let serv_utc = moment(data[i].locationServerTime, "YYYY-MM-DD HH:mm:ss").toDate();
console.log('serv_utc:' + serv_utc)
data[i].locationServerTime = moment.utc(serv_utc,"YYYY-MM-DD HH:mm:ss").format("YYYY-MM-DD HH:mm:ss");
console.log('Converted to server time:' + data[i].locationServerTime)
Output is
Server time:2019-12-19 09:28:13
serv_utc:Thu Dec 19 2019 14:58:13 GMT+0530 (India Standard Time)
Converted to local time:2019-12-19 14:58:13
local time:2019-12-19 14:58:13
serv_utc:Thu Dec 19 2019 14:58:13 GMT+0530 (India Standard Time)
Converted to server time:2019-12-19 09:28:13
This worked for me:
const localtime = 1622516400000
moment(localtime).utc(true).format()
We can get 2 UTC date formats.
const date = '2021-07-20T18:30:00Z';
moment.utc(moment(date).utc()).format(); // 2021-07-19T18:30:00Z
moment.utc(moment(date).utc()).toISOString(); // 2021-07-20T18:30:00.000Z (Complete ISO-8601)
This works in my case.
Library: "moment": "^2.29.1",
moment().utc().format()
Don't you need something to compare and then retrieve the milliseconds?
For instance:
let enteredDate = $("#txt-date").val(); // get the date entered in the input
let expires = moment.utc(enteredDate); // convert it into UTC
With that you have the expiring date in UTC.
Now you can get the "right-now" date in UTC and compare:
var rightNowUTC = moment.utc(); // get this moment in UTC based on browser
let duration = moment.duration(rightNowUTC.diff(expires)); // get the diff
let remainingTimeInMls = duration.asMilliseconds();

Date Comparison always returns false no matter which operator used

I'm pulling my hair out a little here. I understand that an == comparison will always return false between two date objects. But really can't understand why this code returns false every time regardless which way round I set the operator.
var prevWeek = response.prevWeek // The date to compare.
, pickedDate = prevWeek.split("-");
var pickedDate = new Date(pickedDate[0], pickedDate[1], pickedDate[2]);
var todaysDate = new Date();
console.log(pickedDate); // logs Thu Apr 17 2014 00:00:00 GMT+0100 (GMT)
console.log(todaysDate); // logs Fri Nov 15 2013 18:30:13 GMT+0000 (GMT)
var compareValueOf = pickedDate.valueOf() < todaysDate.valueOf();
console.log(compare); // always returns false
var compare2 = pickedDate < todaysDate;
console.log(compare2); // always returns false
var compare3 = pickedDate.getTime() < todaysDate.getTime();
console.log(compare3); // always returns false
that's because the picedDate IS smaller than the todaysDate (2014 > 2013, not the other way around) ;)
if pickedDate is set in 2014, and todaysDate in 2013, there is no way pickedDate can be smaller than todaysDate.
I see a couple of problems with your code.
var prevWeek = response.prevWeek // The date to compare.
, pickedDate = prevWeek.split("-");
I assume respone.prevWeek is a human readable string, like '2013-03-17' for the 17:th of march 2013. When you create a new date object you get the 17:th of april 2013 because the Date-object expects to get the month in 0-11 instead of 1-12. (The year is ok, and so is the day)
var pickedDate = new Date(pickedDate[0], pickedDate[1], pickedDate[2]);
var todaysDate = new Date();
console.log(pickedDate); // logs Thu Apr 17 2014 00:00:00 GMT+0100 (GMT)
console.log(todaysDate); // logs Fri Nov 15 2013 18:30:13 GMT+0000 (GMT)
Notice that you now have a time in pickedDate as 2014-04-18 00:00:00.000 (including microseconds) and in todaysDate 2013-11-15 18:30:13.324 (including microseconds, the exact value is not know so I made it up)
var compareValueOf = pickedDate.valueOf() < todaysDate.valueOf();
console.log(compare); // always returns false
Above you assign the value into compareValueOf but logs the value of compare. But even if you did log the right variable you should get false since a date in 2014 isn't less than a date in 2013.
var compare2 = pickedDate < todaysDate;
console.log(compare2); // always returns false
Another way to compare date objects, that is ok to use. But once again you get false since you are asking if a date in 2014 is less than a date in 2013. It isn't.
var compare3 = pickedDate.getTime() < todaysDate.getTime();
console.log(compare3); // always returns false
Another compare that is exactly like the one above where you use .valueOf() since getTime() gives the exact same value (number of milliseconds since 1 January 1970 00:00:00 UTC). And once again you get false since the picked date is in the future.
If you only want to compare the date-part you could make sure that the time-part of todaysDate is zero by running todaysDate.setHours(0,0,0,0);. Notice that there are 4 parameters: hours, minutes, seconds and microseconds.

Categories