Node JS Date Object behaves strangely around daylight savings time - javascript

So I am working on a rather larger project and I ran into a bug and I wanted to see what I could be doing wrong. I loop though a large amount of data and round off some dates to clean my output into 15 minute buckets.
CODE:
//how I've been doing things
let expectedBehvaior = new Date("2020-11-01T05:14:00.000Z");
console.log(expectedBehvaior.toISOString());
expectedBehvaior.setMinutes(0);
console.log(expectedBehvaior.toISOString());
//using set minutes creates an issue for only hours 6 UTC on Nov 1st 2020
let crazyDate = new Date("2020-11-01T06:14:00.000Z");
console.log(crazyDate.toISOString());
crazyDate.setMinutes(0);
console.log(crazyDate.toISOString());
//how i fixed it
let fixedDate = new Date("2020-11-01T06:14:00.000Z");
console.log(fixedDate.toISOString());
fixedDate.setTime(fixedDate.getTime() - 60000 * fixedDate.getMinutes());
console.log(fixedDate.toISOString());
OUTPUT:
2020-11-01T05:14:00.000Z
2020-11-01T05:00:00.000Z
2020-11-01T06:14:00.000Z
2020-11-01T05:00:00.000Z
2020-11-01T06:14:00.000Z
2020-11-01T06:00:00.000Z
This seems related to daylight savings time in the US as the same thing happens on November 3rd 2019. Not sure how Date.setMinutes works in the background and was hoping someone could explain the behavior.
Thank you.
EDIT:
I am expecting the hour to remain the same after I call crazyDate.setMinutes(0). Instead it sets it back to 0500 UTC as opposed to 0600 UTC.

Related

Correctly treating DST shift with momentJS

I've came across something that I thought it was right, but now taking a closer look something is clearly wrong.
I'm on a project of a pill reminder app where someone can set notifications to remind him/her of taking pills in the correct time. There're medicines which a person can take for the rest of his life. And in that case I don't set alerts for years, I set for 3 months max and, when he takes one and mark it as done, I set another alert for 3 months later starting on that date/time.
This app will be released only in Brazil and we have Daylight Saving Time here. When it shifts to DST time the clocks must be adjusted to -1 hour after midnight, when going off DST it gains 1 hour.
For this project I'm using Firebase, Ionic 2, the LocalNotification Plugin and Moment JS.
I have to make a story of the user because other user can see if he's taking it correctly, so I use Moment JS to manipulate the datetime and save the notification and create a node for that user in firebase with UNIX time.
LET'S FINALLY GO TO THE PROBLEM.
When saving a date I check if this date is DST, if it is I add +3 hours to it, if it's not I add +2. I need to add this because when I wrap the isoString in the Moment() function it gives me -3 hours or -2 hours (Haven't searched for this, but I think Moment uses USA time).
This works fine if I'm saving dates inside DST times if I'm in DST time, if in some case I'm not on DST and save a notification for a DST time day it saves with +2 hours.
AN EXAMPLE
The DST time will shift to in DST on October 15. If I need to save 30 notifications, one per day everyday as 12AM, starting at October 1 up to October 30. From day 1 to day 15 the dates will be right, from day 16 to 30 they'll be with +2 hours.
Here's the basic code I use:
// THIS'LL SET MY DATEPICKER TO THE DATE/HOUR I'M IN.
minDate: any = Moment().isDST ? Moment().subtract(3, 'h').toDate().toISOString() : Moment().subtract(2, 'h').toDate().toISOString();
// THIS'LL CONVERT THE SELECTED DATE TO A UNIX TIME IN WICH I'LL USE TO SAVE THE NOTIFICATION AND THE MEDICATION DATA ON FIREBASE
unixConverted = Moment(this.minDate).isDST ? Moment(this.minDate).add(3, 'h').unix() : Moment(this.minDate).add(2, 'h').unix();
What is strange is that using Moment().unix() alone it give me the right time I'm in, if I use Moment(this.minDate).unix() it gives me -2 or -3 hours of the hour I selected.
So if it's in DST (in which I've set my clock to -1 hour) I add 3, if not I add 2.
So how is the proper way to manipulate this DST shift?
Is there a better way to do this than using DST?
Am I right using this logic or is this much more complex than what I think?
Ok so i've found a better way without using .isDST() method.
Simple use Moment().add(Moment().utcOffset(), 'm'), this'll get the current moment time and add the offset in minutes.
The .add() and .subract() methods makes Moment return the UTC time.
The utcOffset() returns a positive or negative number of minutes (representing hours) from UTC, like -60 or 180. So i'll get the correct respecting the time shift.
Worked like a charm for me.

Set date() to midnight in users timezone with moment.js

I use moment.js to display a UTC date in the users local timezone:
var date = new Date(Date.UTC(2016,03,30,0,0,0));
var now = new Date();
var diff = (date.getTime()/1000) - (now.getTime()/1000);
var textnode = document.createTextNode(moment(date).format('dddd, DD.MM.YYYY') + ' a las ' + moment(date).format('HH:mm A'));
document.getElementsByClassName("date")[0].appendChild(textnode.cloneNode(true));
I later use the diff variable to show a countdown timer.
I would like to show a different countdown timer to everyone in their local time zone. (Using the difference till its midnight in their time zone, not in UTC)
But I am struggeling to get it work. Instead of using var date = new Date(Date.UTC(2016,03,30,0,0,0)); I probably need to use some function of moment.js that gives me till midnight in the users time zone.
The best example would be new years eve. If I use UTC everyone would have the same counter (9 hours left) but in different parts of the world this wouldn't make sense. For someone in australia it should be 2 hours left, and for someone in the US 14 hours.
I'm not sure that I fully understand your question, but I'll give you some general advice and tips.
When using moment.js, there is very little need to ever use the Date object. Only use it for interacting with other APIs that expect a Date object.
To get a moment in UTC, just use moment.utc(...), passing the appropriate arguments, such as moment.utc([2016,3,30]) or moment.utc('2016-04-30') for midnight April 30th UTC.
If you want to convert that back to the user's local time, use the .local() function. For example, moment.utc('2016-04-30').local() will create a moment with the equivalent local time to the UTC time provided.
If you want a moment in the user's local time, then that would be moment(...), such as moment([2016,3,30]) or moment('2016-04-30') for midnight April 30th local time.
You can difference two moments using the diff function, which can give the answer in specific units, such as m1.diff(m2, 'seconds') where m1 and m2 are moment objects.
You don't need to call format twice. Just encapsulate any text you want outputed with square brackets. .format('dddd, DD.MM.YYYY [a las] HH:mm A')
You might look into moment's locale support. If I'm not mistaken, "a las" indicates Spanish, however it's not always "a las", but sometimes "a la", if the hour is 1. Also, moment only uses those words in its .calendar() function, such as when producing a phrase like "mañana a las 13:17". A regular date formatted with .format('LLLL') in the Spanish locale would be something like: "sábado, 19 de marzo de 2016 13:17". So, you might want to verify that "a las" is exactly what you want in every case.
The title to this question was how to set a date to midnight. For that, I recommend using moment's startOf function. m.startOf('day') will give set the moment m to the start of the day, which is usually midnight. Keep in mind that not every local day actually starts at midnight in every time zone. Due to anomalies like daylight saving time, some days might start at 1:00. For example, this occurs in Brazil on October 16th this year.
Also, if you created the moment in UTC mode, you may wish to convert it back to local mode first before setting it to the start of the day. If you don't want to change the original moment object, be sure to clone it first.
Putting this all together:
var m1 = moment.utc([2016,3,30]);
var m2 = m1.clone().local().startOf('day');
var now = moment();
var diff = m1.diff(now, 'seconds');

javascript dates converted to bst time on android devices when using Firefox

I have a web application that runs on Chrome without any problems on a Android Device but when running it on Firefox it converts the "newvalue" to BST time zone instead of GMT Standard Time.
var now = new Date();
var start = new Date();
var newvalue = new Date(now - start);
The newvalue timezone output is GMT+0100(BST) but should actually be GMT+0000(GMT Standard Time)
Firefox is adding an an extra hour.
I have tried to convert to UTC and GMT but doesn't seem to work.
Any ideas?
OK so ... Ermmm ... I'm not clear on what you're doing with the line:
var newvalue = new Date(now - start);
Are you trying to time something?
Regardless, the first thing this line does is to subtract start from now, and give the difference between the 2 dates in milliseconds. Assuming this happens basically instantly, the result will be approximately (if not precisely) 0 milliseconds.
When you create a date and pass in a single parameter like this, you are asking for the date as it was, X milliseconds after epoch. Epoch is defined as Thursday Jan 1st 1970 (for reasons I won't go into). So by creating a new Date with a parameter of 0, you're just asking the browser to give you epoch.
Why Firefox decides to give you epoch in BST instead of GMT, I'll grant is actually pretty odd (since Jan 1st is clearly not in British Summer Time). But this fact is probably irrelevant, given that this is almost certainly NOT what you are trying to achieve here. If you're trying to time something, I'd suggest you probably just want to do:
var newvalue = start - now;
Where newvalue is now the difference in time. Note: I have swapped now and start around, since in your example start is defined after now, and hence this will give you the positive time difference.
EDIT IN RESPONSE TO COMMENT
To be clear, I'm suggesting that you DON'T create a new Date object with the result of the subtraction.
If you want to get the number of milliseconds between the two times using dates, just subtract them:
var start = new Date();
// do time consuming stuff
var end = new Date();
var difference = end - start; // NOT: var difference = new Date(end - start)
Resolved the issue by turning the two dates in to a UTC date and then finding the difference between the two dates using milliseconds.
This then works on Android.
Thanks for your assistance

Set JavaScript countdown to end at midnight PST?

I am trying to get a countdown to end Monday # midnight PST. I thought I had it working a week ago but apparently not.
I am using date.js
var monday = Date.today().next().monday();
var UTCmonday = new Date(monday.getTime() + monday.getTimezoneOffset() * 60000);
var PSTmonday = new Date(UTCmonday.setHours(UTCmonday.getHours() + 9));
$('#defaultCountdown').countdown({until: UTCmonday});
I think the problem is in determining UTC time? Am I right? How do I work this out?
Assuming you Pacific Standard Time, then you need to remember that PST === UTC-8
Thus, your third line would be
var PSTmonday = new Date(UTCmonday.setHours(UTCmonday.getHours() - 8));
The problem with this is that this will fail if the UTC is any earlier than 8am, since you can't pass a negative number into setHours.
Since you're using Datejs, why not use its full capabilities for changing the timezone?
http://code.google.com/p/datejs/wiki/APIDocumentation#setTimezone
Getting the time strictly in PST doesn't make much sense, as for almost half of the year PST isn't observed in the Pacific time zone. PST (UTC-8) is observed in the winter, and PDT (UTC-7) is observed in the summer. You can't represent Pacific Time as just a fixed offset, and unless it happens to be your own local time zone, you can't easily determine the transition between them without a time zone database. See the timezone tag wiki.
Also, date.js has been abandoned. I can't recommend any solution that continues its use. Support for the setTimezone method that Dancrumb suggested is culture specific, and it still doesn't take daylight saving time into consideration.
Instead, I recommend trying moment.js. You can use the moment-timezone add-on to work with the America/Los_Angeles zone - which is a good exemplar of US Pacific time. Make sure your moment-timezone-data.js file includes at least this zone. Then you can do the following:
var m = moment().tz('America/Los_Angeles').day(7).startOf('day');
var s = m.toISOString(); // if you need a string output representing UTC
var dt = m.toDate(); // if you need an actual JavaScript Date object
Let's break that down a bit:
moment() gets you the current time
tz('America/Los_Angeles') adjusts the time to the timezone you are interested in.
day(7) advances the time to the next Monday.
startOf('day') snaps the time back to midnight.

Is there a way in javascript to know what hours will be 9 am in a specified timezone?

Well I need to know what hours will be 9am in user time compared with my timezone.
like:
I'm from Brazil 9 am GMT -0300
i.e: some user from 'Cairo' access my website then I need to know when will be 9 am in his time compared with my time 'Cairo' gmt is +0200.
Is there a way to do it with Javascript?
You are probably looking for getTimezoneOffset() method
(see http://www.w3schools.com/jsref/jsref_gettimezoneoffset.asp):
var d = new Date()
var n = d.getTimezoneOffset();
n will be the timezone difference between UTC and Local Time in minutes.
More comprehensive guide here: http://www.onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/.
EDIT:
Oh, I forgot about the future time part. In that case, it should be enough to create custom date instance using one of the extended constructors:
var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);
It can be used to determine the timezone difference at that time.
You can easily determine the offset o at some time, and the final offset at the specified time is either o, o + 60 or o - 60, which can be easily checked with getTimezoneOffset() on the Date object created with the extended constructor.
In the worst-case scenario, you might have to do 2-3 calculation steps to determine your final result.
Checkout: javascript timezone converter, there's an already open discussion there about your inquired topic.

Categories

Resources