MongoDB + JS Date shifted -1 day - javascript

I'm trying to add a new date inside my mongodb document using
db.collection('course').insertOne({
date: new Date(item.date)
});
item.date is from
items.push({
date: moment(new Date(day.label)).tz('Europe/Paris').format('YYYY/MM/DD'),
});
day.label is like '14 November 2016'
item.date is formated like 2016/11/14
The document insert work but the dates are not properly formated, for example, for 2016/11/14 Mongo insert "date" : ISODate("2016-11-13T23:00:00Z")
Every inserted dates are shifted -1 day
Is the proper way to insert custom formated date in MongoDB ?
Should I change the momentJs date format ?
EDIT:
Dates are shifted because of different timezone.

It's not shifted by a day, it's not actually shifted at all.
The time shown is shifted by an hour. If you notice, the time has become 23:00 on the previous day, rather than defaulting to midnight on the date you have specified.
More importantly, the Z suffix in the timestamp means that the timezone is UTC, and 2016-11-13T23:00:00 in UTC refers to the same moment in time as the timestamp 2016-11-14T00:00:00+01:00. So the datetime is being created correctly, but just shown back to you in a different timezone that you're creating it in.

if you want proper solution for all date UTC problem, store
date as standard ISO format
// India
moment().toISOString() // "2016-11-06T06:17:33.520Z"
// canada
moment().toISOString() // "2016-11-06T06:19:42.133Z"
now see the diffrence by convering date from database
// canada time zone
moment("2016-11-06T06:19:42.133Z").format() // "2016-11-05T23:19:42-07:00"
// india time zone
moment("2016-11-06T06:19:42.133Z").format() //"2016-11-06T11:49:42+05:30"
as above see the diffrence of local UTC, so don't have to convert date from any
timezone to other timezone

Related

How to display times in different time zones using the offset value

I am trying to display the current moment in different time zones. I have tried to use native javascript and the moment-js package but it seems you require the time zone name (ex. "America/Toronto") to display the information I want. The problem is that the information I currently have is the timestamp in string format (see below for string format) from the desired timezone, and the city the timestamp belongs to. The problem with using the city to create my tz value is that one of the cities I want to display isn't in the IANA tz database (Calgary).
String timestamp:
2022-04-26T14:19:42.8430964-04:00
As can be seen I do have the time offset and I was hoping there was a way to convert this string in js to a Date object and then display the time using the offset in the correct time zone.
Note what I want to display is the following format:
12:19 pm MT
I know I could just parse out the string but I feel like this isn't the best practice, however I may be wrong.
Also note that I will have to get the time zone (ex. MT, ET it can also be MST, EST) using the offset.
you don't need moment here. JS can do this natively. Also moment is now deprecated.
Your IANA timezone is America/Edmonton. So it's simple to do. That date format is an ISO 8601 date format, so you can just pass it into the new Date constructor and it'll parse it correctly:
const iso8601 = '2022-04-26T14:19:42.8430964-04:00';
const date = new Date(iso8601);
console.log(date.toLocaleString('en-US', { timeZone: 'America/Edmonton' }));
It doesn't matter what timezone your input date is set, so long as it has the correct offset in the ISO date. Once it's a Date, the offset is irrelevant. E.g.:
const iso8601 = '2022-04-26T14:19:42.8430964Z';
const date = new Date(iso8601);
//time will now be 4 hours off above as the input date is UTC
console.log(date.toLocaleString('en-US', { timeZone: 'America/Edmonton' }));

How to obtain unix timestamps for same date in 2 different time zones with moment.js?

I'm working on an app where users can choose what time zone they are recording time in. But internally, I want to store the time as a unix timestamp.
Say I have a date '2016-01-01 1:00 pm'. If I store this date in CDT (America/Chicago), it is my understanding that the resulting unix time stamp should be different than had I stored the same date in MDT (America/Denver). However, I get the same unix time stamp for both dates, and I'm having trouble understanding why.
var chicagoDate = moment('2016-01-01 1:00 pm').tz('America/Chicago');
var denverDate = moment('2016-01-01 1:00 pm').tz('America/Denver');
chicagoDate.format();
// "2016-01-01T07:00:00-06:00"
denverDate.format();
// "2016-01-01T06:00:00-07:00"
So far this confirms that the 2 dates are distinct from one another as shown by their UTC representation obtained by using format(). But here is where I'm getting confused:
chicagoDate.unix();
// 1451653200
denverDate.unix();
// 1451653200
Shouldn't 2 distinct UTC dates result in 2 distinct unix timestamps?
In:
moment('2016-01-01 1:00 pm').tz('America/Chicago');
there is no parse format parameter, so moment.js looks to see if the format is one that it can parse without the format. It can't, so it falls back to the built–in parser as if you'd written:
moment(new Date('2016-01-01 1:00 pm')).tz('America/Chicago');
And puts warning in the console:
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions…
Safari at least parses it as an invalid date (timestamp), so you should include the parse format:
moment(new Date('2016-01-01 1:00 pm', 'YYYY-MM-DD h:mm a')).tz('America/Chicago');
Secondly, the string is parsed as local since there is no timezone associated with the timestamp. So both lines of code produce exactly the same time value (i.e. offset from the epoch) and the two Dates produced are effectively identical.
The call to tz sets the timezone to use for all subsequent operations, so the output shows different times because different offsets have been applied at the formatting stage. The actual Dates being formatted are still effectively identical.
If you want the string to be parsed as for another timezone, you need to either manually include it in the string at the parse stage (e.g. '-06:00' or whatever), or use a library like Luxon with an IANA location (e.g. 'America/Chicago').

Inconsistency when converting DateTime to JavaScript

I have a ASP.NET webapi with a DateTimeZoneHandling set to Local and I am getting two different results when converting to a JavaScript date.
Example 1
Date returned from server 1932-10-13T00:00:00-04:00
var strDate = new Date("1932-10-13T00:00:00-04:00");
strDate.toISOString(); // 1932-10-13T04:00:00.000Z
strDate.toLocaleString(); // 10/12/1932, 11:00:00 PM
Example 2
Date returned from server 2013-05-09T00:00:00-04:00
var strDate = new Date("2013-05-09T00:00:00-04:00");
strDate.toISOString(); // 2013-05-09T04:00:00.000Z
strDate.toLocaleString(); // 5/9/2013, 12:00:00 AM
I expected behaviour should always be midnight as the dates returned from the server are always midnight. It appears all recent dates parse correctly, however, dates far in the past are incorrect.
The timezone can vary in some locales, for example, I'm UTC-0300, and on certain season shifts it becomes UTC-0200, so it indicates that your locale changed the offset too, making it display the time one hour lesser, basicaly because you locale adopted a different offset along the year.
The example bellow, I've changed your first example to use the same day and month than the second one, so that it proves you that old dates has nothing to do with it.
console.log("Example One");
var strDate = new Date("1932-05-09T00:00:00-04:00");
console.log(strDate.toISOString());
console.log(strDate.toLocaleString());
console.log("--------------------------");
console.log("Example Two");
var strDate2 = new Date("2013-05-09T00:00:00-04:00");
console.log(strDate2.toISOString());
console.log(strDate2.toLocaleString());
Further explanation on UTC/Zulu time
It has normalized the iso date to a zulu date (zero offset iso date). It is still the same datetime, but it has converted the timezone offset into hours making the timezone offset zero.
date [2013-05-09]
separator [T]
time [00:00:00]
offset [-04:00]
The fundamental aspect is that 00:00:00.000-04:00 is the same than 04:00:00.000Z.
If you're simply trying to display the date as someone living in that time would have remembered it (in your case, October 13th happened on October 13th), you may be able to (ab)use Moment Timezone, which appears to format the date as expected:
moment.tz("1932-10-13T00:00:00-04:00", "America/Toronto").tz("UTC").format(); // 1932-10-13T04:00:00Z
In your case, this hacktechnique results in 1932-10-13T04:00:00Z which may be what you are looking for.

Displaying timezone-formatted date as UTC time

on my UI, I try to display a date based on a specific timezone. In this example, I will use Americas/New_York as the timezone. This is how I did it.
$scope.getStartTime = function(){
var date = new Date();
return moment(date).tz("Americas/New_York").format('YYYY-MM-DD HH:mm:ss');
};
Afterwards, I want to send this data and send it to my server. In my server however, I want it so that it is always serialized into UTC time instead of in the New York Timezone (EST).
For example, if the time was 12:00 P.M. in New York, then the time would be serialized to 4:00 P.M. in UTC time before it was sent to the backend. This was my attempt:
var date = getStartTime();
....
// Display the date in the UI
....
$scope.revertStartTime(date);
$scope.revertStartTime = function(startTime) {
console.log("Start time: ", startTime);
console.log("Moment: ", moment(startTime).format());
console.log("Converted to utc time: ", moment().utc(startTime).format());
return moment.utc(startTime).format("YYYY-MM-DD'T'HH:mm:ss.SSSZ");
}
I tried to revert the start time by using the moment().utc() function and hoped that the date would change to a UTC based date but unfortunately it keeps turning my date into the localized date instead of UTC date and I'm not sure why. Any help would be appreciated. Thanks!
Edit:
Tried to follow the below method and here is what I did:
$scope.getStartTime = function(){
var date = new Date();
var startTime = new moment(date).tz($rootScope.userinfo.timeZone).format('YYYY-MM-DD HH:mm:ss');
$rootScope.offset = moment().utcOffset(startTime);
console.log("offset: ", $rootScope.offset);
return startTime;
};
$scope.revertStartTime = function(startTime) {
console.log("User Selected Time: ", moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss'));
return moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss');
}
But all I get is an error saying that revertStartTime returns an Invalid Date.
A few things:
Hoping it's a typo, but just to point out, the zone ID is America/New_York, not Americas/New_York.
You can pass a value as moment.utc(foo), or moment(foo).utc(), but not moment().utc(foo). The difference is that one interprets the input as UTC and stays in UTC mode, while they other just switches to UTC mode. You can also think of this as "converting to UTC", but really the underlying timestamp value doesn't change.
Yes, you can switch to UTC mode and call format, but you can also just call .toISOString() regardless of what mode you're in. That's already in the ISO format you're looking for.
Note that if you start with a unique point in time, and you end with converting to UTC, no amount of switching time zones or offsets in the middle will change the result. In other words, these are all equivalent:
moment().toISOString()
moment.utc().toISOString()
moment(new Date()).toISOString()
moment.utc(new Date()).toISOString()
moment(new Date()).utc().toISOString()
moment().tz('America/New_York').toISOString()
moment.tz('America/New_York').toISOString()
moment().utcOffset(1234).toISOString()
moment.utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
moment().utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
Only the last two even need to be in UTC mode, because the format function would produce different output if in local mode or in a particular time zone.
In order to accomplish this you'd want to use .utcOffset(). It is the preferred method as of Moment 2.9.0. This function uses the real offset from UTC, not the reverse offset (e.g., -240 for New York during DST). Offset strings like "+0400" work the same as before:
// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')
The older .zone() as a setter was deprecated in Moment.js 2.9.0. It accepted a string containing a timezone identifier (e.g., "-0400" or "-04:00" for -4 hours) or a number representing minutes behind UTC (e.g., 240 for New York during DST).
// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')
To work with named timezones instead of numeric offsets, include Moment Timezone and use .tz() instead:
// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')

format just a time for use with ui-bootstrap timepicker

I have a server returning a time value like so
14:00
The reason for this is it represents the start time of say a task that happens repetively say every monday at 14:00 so the date is irrelevant. I want to display this value to the user when they are editing the task so that they can change it with ui-bootstraps timepicker.
The timepicker requires either an epoch, an rfc2822 or ISO 8601 date so I need to just add a random date that I can discard later for the timepicker to be able parse and display the value (which seems ridiculous seen as it is a time picker not a time on a specific day picker but whatever)
so either using the javascript date object or moment.js how can I take that value and create a valid date object with it?
As you requested a moment.js solution also:
var date = moment("14:00", "HH:mm").toDate();
// assume returned is the hours and minutes you get in this format: 14:00
hourData = returned.split(':');
var date = new Date();
date.setHours(hourData[0]);
date.setMinutes(hourData[1]);
date will be something like Sat Jul 12 2014 14:00:13 GMT+0300 (EEST)

Categories