setHours in different timezones - javascript

I am comparing two dates but problem is that in my local computer generated date when i use setHours method like so console.log(new Date(new Date().setHours(8))); it gives me an output of 2020-07-22T04:41:46.624Z my Timezone is GMT+4 (Georgia Standard Time) but on my heroku server (EU) or repl.it it gives where timezone offset is -0 it gives me 2020-07-22T08:41:46.624Z for the exact same command, how can i fix this? otherwise if i log new Date() on both machines they all log the same date even if i add time to them, its setting hours (or minutes, etc.) that alters the timezone

A few things:
The setHours function interprets the input in the local time zone. So yes - you will get different results depending on the time zone of the computer where you run it. You are literally saying: "Set the hour to 8 am local time".
If you intended to set the hour to 8 am UTC, you can use the setUTCHours function instead. UTC is the same across the entire planet, so you will get the same result both locally and on your server, regardless of time zone. (Assuming your clock is synchronized correctly by your OS.)
The Z in the string output means UTC.
When you log a Date object, the resulting string format is environment specific. In some environments, you'll get output like you showed, which is the same as if you called toISOString - which is in ISO 8601 format and is always in UTC. In other environments you'll get the output that comes from toString - which is in a different format, and is usually based on local time. The point is - there's no standard that controls the log output for a Date object. Don't log it directly - log the string result of calling one of those two functions (probably toISOString).

Related

javascript date not returning correctly [duplicate]

I'm pulling dates from a SQL database which treats them as dates that start at midnight. When I go to use toLocaleDateString() on them, it formats them properly, however not before losing a day.
Before formatting: 2011-09-01T00:00:00
After formatting: 8/31/2011
Code:
plan.dateReceived = new Date(plan.dateReceived).toLocaleDateString()+','+plan.dateReceived;
Why does it do this, and what inline fix can I make to have it behave properly?
I also found another post that had a similar problem, but I'm not 100% convinced that it's a timezone issue.
If you run the code in pieces, you'll notice that new Date('2011-09-01T00:00:00') produces output like Wed Aug 31 2011 20:00:00 GMT-0400 (EDT) (my computer is in EDT right now).
This is because (doc):
Differences in assumed time zone
Given a date string of "March 7, 2014", parse() assumes a local time
zone, but given an ISO format such as "2014-03-07" it will assume a
time zone of UTC. Therefore Date objects produced using those strings
will represent different moments in time unless the system is set with
a local time zone of UTC. This means that two date strings that appear
equivalent may result in two different values depending on the format
of the string that is being converted (this behavior is changed in
ECMAScript ed 6 so that both will be treated as local).
Converting that to the locale date string will convert it to a string appropriate for the browser's locale. Documentation indicates that "the default is the runtime's default time zone".
If you want to ensure the string is in UTC time, use
new Date('2011-09-01T00:00:00').toLocaleDateString('en-US', {timeZone: 'UTC'})
We experienced this problem on Google Chrome v87.0.4280 IOS, but not on a computer with the same browser.
The problem was that the timezone string did not contain a Z at the end.
"Z" is kind of a unique case for DateTimes. The literal "Z" is
actually part of the ISO 8601 datetime standard for UTC times. When
"Z" (Zulu) is tacked on the end of a time, it indicates that that time
is UTC, so really the literal Z is part of the time.
Appending Z to the datetime fixed the problem.
new Date('2011-09-01T00:00:00Z').toLocaleDateString('en-US', {timeZone: 'UTC'})

Is there a way to override `new Date()` in Javascript so it always returns the date considering one specific hardcoded timezone?

I'm working on a React.js project that handles lots of comparisons related to DateTime (comparing the hour, the month, the year and so forth to dates retrieved from an API). For this specific React.js application, I would like to always consider DateTimes (from new Date()) as if the user was in the server timezone. Assuming that the server is in "Europe/Berlin" timezone, I would like that at any point in the application, calling new Date('2019-01-01') would retrieve me a DateTime that refers to this time in the "Europe/Berlin" timezone, that would be Tue Jan 01 2019 01:00:00 GMT+0100 (Central European Standard Time). If I set my computer Date and Time as if I was in Brazil, for instance, I get Mon Dec 31 2018 22:00:00 GMT-0200 (Brasilia Summer Time), but would like to get the same as before. The main reason why this is a problem is that we extract data from these DateTimes such as .getHours(), .getDate(), etc.
This would fit this specific application because it's really important for this project that we only support the server Timezone, no matter where the user is. So to keep consistent with the server time, the call new Date('2019-01-01').getDate() should return 1, since it will be 1st January in Berlin. However, if the user is in Brazil, this same call will return 31, as Brazil is some hours before GMT, when it's midnight in GMT time, it will be still the previous day in Brazil.
I tried first to use the date-fns along with date-fns-timezone to set the DateTime to display the dates and times to the client considering the server timezone. That worked fine to display the right data but didn't solve some issues that are caused due to these attributes extraction from the date and that will vary depending on where the user is.
So that's why what I'm trying to do now is override the new Date() method in a way that it will always retrieve the date as if the user was in the server time. I haven't managed to get how it can be done. Whenever I change the Date and Time from my computer, the output for the new Date() already takes into account this new date and time settings.
So how can I force the new Date() to always give back the DateTime with a hardcoded timezone? Also, it would be really good if I could do it without using external libs (like moment.js, for instance), and do it only with plain Javascript.
I was taking a look into the window.navigator variable to see if I could set this one to force the Date to the server timezone, but it doesn't look like that will be the way to solve my issue.
I looked a lot for this answer and didn't find any question that was really close to this one. I'll just list here some of the questions I looked before and why my case differs from them.
1- new Date() for a specific timezone in JavaScript: In this case, the moment is used, and there was no way to accomplish this overriding for the new Date() itself.
2- Convert string to date without considering timezone: In this one, the answer gives back a string with the date formatted to the desired timezone, but not a Date object itself.
3- javascript date considering Request.UserLanguages[0]: also in this one, the question/answer is about formatting the date output rather than retrieving the Date object itself with the new timezone.
4- How do I combine moment.js timezone with toDate to build a new date object?: in this one the answer also is about using moment.js, what I would like to avoid since what I really want to achieve is overriding the new Date() method.
A few things:
Generally speaking, one should try to design their applications such that the server's time zone is not relevant at all. This means only relying on the server's UTC functionality, and working with specific named time zones. Asking for the local time of a server tends to become problematic, especially when dealing with environments where you may not have full control of the server.
Keep in mind that the Date object in JavaScript is misnamed. It is really a timestamp. Essentially it is just an object wrapper around the value you get with .valueOf() or .getTime() or when you coerce it to a number. Everything function on the Date object simply reads this value, applies some logic (which may or may not use the local time zone depending on the function), and emits some result. Similarly, the constructors of the Date object interpret your input and then assign this number in the resulting object. In other words, the Date object does not keep track of a time zone at all. It simply applies it when it is called for. Thus, one cannot change it.
When you pass a string in yyyy-MM-dd format to the Date constructor, per the ECMAScript specification it is interpreted as midnight UTC, not as midnight local time. This is a deviation from ISO 8601, and such often confuses people.
The strings you showed as output like Tue Jan 01 2019 01:00:00 GMT+0100 (Central European Standard Time) are emitted in local time, and are the result of either calling the .toString() function, or by passing a Date object to console.log in some environments. Other environments show the result of .toISOString(), which is emitted in UTC.
There's no global in window.navigator or elsewhere that can change the local time zone. In Node.js apps, if you really need to set the server's time zone globally, you can set the TZ environment variable before launching Node. However, this doesn't work in Windows environments, and doesn't help for browsers.
You're on track with using a library such as date-fns with date-fns-timezone. There are other libraries as well, which are listed in this answer. Alternatively, you could call .toLocaleString with the timeZone option, such as:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
This API provides functionality for emitting a string in a particular time zone, but it does not do anything for applying a time zone to an input string.
So ultimately, to answer your question:
So how can I force the new Date() to always give back the DateTime with a hardcoded timezone?
Sorry, you can't. You can either use a different object to track the time zone statefully, or you can use functions that take the time zone as a parameter. Both are things offered by existing library, but only the one function I showed above is currently built in to JavaScript.
In case someone else has this same problem, here is the approach that I followed to solve the issue:
As in this specific case I really need to compare and group some entities based on date, among other operations (always considering the server timezone), I ended up choosing moment.js along with moment-timezone. The native Date class would not solve it since it has no way to handle different timezones. Then, I tried to use first date-fns and date-fsn-timezone, but as these libs always use the standard Date class, it gets back to the problem that a Date in javascript is only a timestamp and has no clue about other timezones other than the one in the client (the application is a React.js one).
Just to show one example about the issue, consider that the server is placed in Europe/Berlin timezone, and one stamp is retrieved as 2019-04-30T02:00:00+02:00. On the React.js application, I want to group this stamp to all the stamps that are also from 2019-04-30. However, if the browser is in Brazil/Brasilia time, the call new Date('2019-04-30T02:00:00+02:00').getDate() will give me 29 as return, since in the client timezone, this same timestamp will represent 2019-04-29T09:00:00-03:00.
Using moment and moment-timezone it could be fixed by defining in which timezone I want to retrieve the values, such as:
moment('2019-04-30T02:00:00+02:00').tz('Europe/Berlin').date()
// retrieves 30 independent on the client timezone.
Thank you very much to all who contributed with answers and suggestions. You all helped me to find the path to solve this issue.

toLocaleDateString() is subtracting a day

I'm pulling dates from a SQL database which treats them as dates that start at midnight. When I go to use toLocaleDateString() on them, it formats them properly, however not before losing a day.
Before formatting: 2011-09-01T00:00:00
After formatting: 8/31/2011
Code:
plan.dateReceived = new Date(plan.dateReceived).toLocaleDateString()+','+plan.dateReceived;
Why does it do this, and what inline fix can I make to have it behave properly?
I also found another post that had a similar problem, but I'm not 100% convinced that it's a timezone issue.
If you run the code in pieces, you'll notice that new Date('2011-09-01T00:00:00') produces output like Wed Aug 31 2011 20:00:00 GMT-0400 (EDT) (my computer is in EDT right now).
This is because (doc):
Differences in assumed time zone
Given a date string of "March 7, 2014", parse() assumes a local time
zone, but given an ISO format such as "2014-03-07" it will assume a
time zone of UTC. Therefore Date objects produced using those strings
will represent different moments in time unless the system is set with
a local time zone of UTC. This means that two date strings that appear
equivalent may result in two different values depending on the format
of the string that is being converted (this behavior is changed in
ECMAScript ed 6 so that both will be treated as local).
Converting that to the locale date string will convert it to a string appropriate for the browser's locale. Documentation indicates that "the default is the runtime's default time zone".
If you want to ensure the string is in UTC time, use
new Date('2011-09-01T00:00:00').toLocaleDateString('en-US', {timeZone: 'UTC'})
We experienced this problem on Google Chrome v87.0.4280 IOS, but not on a computer with the same browser.
The problem was that the timezone string did not contain a Z at the end.
"Z" is kind of a unique case for DateTimes. The literal "Z" is
actually part of the ISO 8601 datetime standard for UTC times. When
"Z" (Zulu) is tacked on the end of a time, it indicates that that time
is UTC, so really the literal Z is part of the time.
Appending Z to the datetime fixed the problem.
new Date('2011-09-01T00:00:00Z').toLocaleDateString('en-US', {timeZone: 'UTC'})

Is there a simple time to get a timezone from a given time?

I need to get a timezone from a time, date is not important, but daylight savings is.
something like:
timezone = function("15:00");
Is there a simple way to do this?
I dont think you can get the timezone from the time but you might get some help from Date.prototype.getTimezoneOffset()
The getTimezoneOffset() method returns the time-zone offset from UTC,
in minutes, for the current locale.
Example:
var x = new Date();
var currentTimeZoneOffsetInHours = x.getTimezoneOffset() / 60;
No, of course not. Think about it, you're passing 15:00 to that function, presumable denoting it's 3PM. But in what timezone is it 3 PM? No way of knowing. It's like me saying it's quarter to, without saying what hour it's quarter to to.
The only way you can get a timezone in JS is by using the Date object, but that just shows the timezone of the machine on which your code is running, nothing about the TZ that "created" the time you're processing.
Also note that daylight saving isn't a global phenomenon, quite the contrary. AFAIKT, there isn't a single time-zone where DST has always been in place...
In order to get TimeZone information you need more than a Date (and an offset). You need a location.
Javascript does not know the location that it resides in but it does know the current offset from UTC. That is different than a Time Zone. The daylight savings time issue play havoc with this key difference.
This has posed problems when dealing with server applications that know their timezone and report dates as being in a specific Time Zone.
My rule of thumb has been fairly simple in this regard.
Always use Long or long (a 64 bit number) to store, pass and process dates times or intervals, only convert to Date, Calendar or DateTime objects when interacting with people.
Once you have a date object, such as with new Date(), you can use .getTimezoneOffset() to get the number of minutes between the date's object and UTC, which is timezone information you can use.

ExtJS dates and timezones

I have a problem with the Ext Date class seemingly returning the wrong timezone for a parsed date. Using the code below I create a date object for the 24th May, 1966 15:46 BST:
date = "1966-05-24T15:46:01+0100";
var pDate = Date.parseDate(date, "Y-m-d\\TH:i:sO", false);
I then call this:
console.log(pDate.getGMTOffset());
I am expecting to get the offset associated with the orignal date back (which is GMT + 1), but instead I get the local timezone of the browser instead. If the browser is set to a timezone far enough ahead GMT, the day portion of the date will also be rolled over (so the date will now appear as 25th May, 1966).
Does anyone know how to get around this and get Ext to recognise the correct timezone of the parsed date rather than the local browser timezone?
If this is not possible, can Ext be forced to use GMT rather than trying to interpret timezones?
I checked the parseDate() implementation in ExtJS source code and the documentation of Date in core JavaScript, the Date() constructor used by ExtJS does not support time zone information. JavaScript Date objects represent a UTC value, without the time zone. During parsing in ExtJS source code, the time zone is lost while the corresponding offset in minutes/seconds is added to the Date.
I then checked the source code of getGMTOffset() defined by ExtJS: it builds a time-zone string using the getTimezoneOffset() function defined in JavaScript.
Quoting the documentation of getTimezoneOffset():
The time-zone offset is the difference
between local time and Greenwich Mean
Time (GMT). Daylight savings time
prevents this value from being a
constant.
The time-zone is not a variable stored in the Date, it is a value that varies according to the period of the year that the Date falls in.
On my computer, with a French locale,
new Date(2010,1,20).getTimezoneOffset()
// -60
new Date(2010,9,20).getTimezoneOffset()
// -120
Edit: this behavior is not specific to Date parsing in ExtJS, the following note in the documentation of Date.parse() on Mozilla Doc Center is relevant here as well:
Note that while time zone specifiers
are used during date string parsing to
properly interpret the argument, they
do not affect the value returned,
which is always the number of
milliseconds between January 1, 1970
00:00:00 UTC and the point in time
represented by the argument.
I'm a little late but in latest ExtJS, you can pass an optional boolean to prevent the "rollover" in JS
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.Date-method-parse
My two cents, because I can't really set all my time to 12:00 like Tim did. I posted on the sencha forum

Categories

Resources