I have a page which allows a user to view and edit times (with dates) stored in a database. The times are stored in the database in UTC and attached to a location with a different timezone. When the user views the times they are shown in the attached timezone and not necessarily the timezone of the browser. The user should then be able to edit a time and make and AJAX request. I need to be able to convert the inputted time from an arbitrary timezone to UTC in javascript, but the only conversion javascript seems to allow is from browser timezone to UTC. Passing an absolute offset in javascript is not going to work because the user should be able to edit times before or after daylight savings. This seems like it should be a problem that has been solved before... any pointers?
This is an extremely nasty problem. As long as the user is presented with all times in his/her own timezone (or in GMT), you would have no problem. But asking JS to provide accurate local Daylight Saving Time values for different locales is nasty stuff. The browser is aware of GMT and local time and (thanks to the OS) it also knows when DST kicks in locally. But without changing the user's system timezone information, JS has no way of telling when DST kicks in in another locale. The rules of when DST comes into effect not only differ from country to country, the date can change unexpectedly over time (remember when North American countries recently moved DST dates?). You can likely figure out the locale DST details on your server pretty easily and communicate that to the browser. But it's probably not practical to attempt it entirely in the browser. You could have a sort of DST_changeover_by_locale array in your application, but you'd need to update it periodically.
[EDIT] There seems to be some confusion about how the JS Date object works in regards to timezones. Here are some useful points:
Timezone offsets
// Create a time in winter (Standard time)
dt = new Date('Jan 1 2010 12:00:00 GMT-0000');
alert(dt.getTimezoneOffset());
// In Japan right now, users would see "-540"
// In New York right now, users would see "300"
// Create a time in summer (DST)
dt = new Date('Jul 1 2010 12:00:00 GMT-0000');
alert(dt.getTimezoneOffset());
// In Japan right now, users would see "-540"
// In New York right now, users would see "240"
// NOTE: Japan has no DST while NY does
Parsing dates to local time
// The following will all return the same time string, which will be
// the time according to the user's OS time settings and locale
alert((new Date('Jun 25 2010 13:30:00 GMT-0230'))); // Newfoundland time
alert((new Date('Jun 25 2010 13:00:00 GMT-0300'))); // Atlantic time
alert((new Date('Jun 25 2010 12:00:00 GMT-0400'))); // Eastern time
alert((new Date('Jun 25 2010 11:00:00 GMT-0500'))); // Central time
alert((new Date('Jun 25 2010 10:00:00 GMT-0600'))); // Mountain time
alert((new Date('Jun 25 2010 9:00:00 GMT-0700'))); // Pacific time
Timestamps
// If you don't want to work with strings, use numbers instead.
// These return the JS timestamp for the same values above.
// The value is a *delta*, so it is unaffected by DST.
alert((new Date('Jun 25 2010 13:30:00 GMT-0230')).getTime()); // Newfoundland time
alert((new Date('Jun 25 2010 13:00:00 GMT-0300')).getTime()); // Atlantic time
alert((new Date('Jun 25 2010 12:00:00 GMT-0400')).getTime()); // Eastern time
alert((new Date('Jun 25 2010 11:00:00 GMT-0500')).getTime()); // Central time
alert((new Date('Jun 25 2010 10:00:00 GMT-0600')).getTime()); // Mountain time
alert((new Date('Jun 25 2010 9:00:00 GMT-0700')).getTime()); // Pacific time
I don't think you have to do the timezone conversion on the browser. You can just display an "opaque" date time on the client, let them modify it, then post to the server to convert it to UTC, as required.
Not sure if I should put this as an answer but I cannot leave a comment as I did not associate that temporary account with this ID...
Unfortunately it looks like doing the time zone calculation server side is the only clean way to do this, however I'm still hopeful someone might have another solution. By convention in this code all times should be sent in UTC and I'd like to avoid breaking that convention (and making it confusing in other places we might use the service call) if possible.
Related
I'm writing some JavaScript for one of our database tables for CRUD functions, and one of the ID fields used for identify a data item is a date. When pulling this data in using AJAX, it comes in the full JavaScript data format: Thu Apr 25 2019 00:00:00 GMT+0100 (British Summer Time).
This is causing problems since when it is sent off, Kendo UI changes it to UTC, and in this case, the day changes to the 24th of April, meaning our backend code can't find the record.
What I've done to try to fix this is change this field when it comes in using .toLocalDateString. This has fixed my problem, as it seems to just chop off the information about the timezone, and just gives me DD/MM/YYYY, which the backend accepts.
My question is: will this have the intended effects (ignore the timezone and just give me the date) if the program is used in, say, Eastern USA.
Since I am in Britain, and our timezone is currently British Summer Time, which is the timezone in which the original data pulled in was in, is this only working since I am in BST? If I was in EST, which is 5 or 6 hours behind, would .toLocaleDateString cause the day to go back 1?
I've looked in the documentation and all it says is 'Using local conventions', and the meaning of this is unclear to me.
Edit:
I am getting Mon May 13 2019 00:00:00 GMT+0100 (British Summer Time) back from the AJAX request. When I send this back off, I stringify the data, and it stringifies to this: "2019-05-12T23:00:00.000Z", which is in UTC, causing the problem.
I am investigating an issue involving the conversion of serialized UTC dates in to JavaScript date objects; I have read a few questions on this topic already but I am still unclear.
Firstly let me say that I am in the UK. If I take for example the UTC epoch 1473805800000, which is Tue, 13 Sep 2016 22:30:00 GMT, then use that value to create a JavaScript date:
var date = new Date(1473805800000);
console.log(date);
The console logs:
Tue Sep 13 2016 23:30:00 GMT+0100 (GMT Summer Time)
I.e. the browser has recognised that an extra hour needs to be added for DST.
My question is, if I were to run this same code again after the 30th October when the clocks have gone back, would I still get the same result of 23:30, or would it be 22:30 as if it were GMT? In other words, has the browser added an hour because the subject date is DST or because we are currently in DST?
I'm prevented from altering my work station's system clock by group policy, otherwise I would skip it forward in time and test this myself.
Javascript Date objects use a time value that is an offset in milliseconds since 1970-01-01T00:00:00Z. It is always UTC.
If the Date constructor is given a single number argument, it is treated as a UTC time value, so represents the same instant in time regardless of system time zone settings.
When you use console.log(date), the built–in toString method is called which generates an implementation dependent string, generally using the current time zone setting of the host system to create a convenient, human readable string.
The current daylight saving rules in the system are used to determine the offset to use for "local" time, so if the date changes from a time when daylight saving applies to one when it doesn't, the time zone offset will be similarly adjusted (note that daylight saving offsets aren't always 1 hour). It does not matter what the current system offset is, the one used is based on the setting for the date and time that the time value represents.
Also, Date objects are very simple, they're just a time value. The time zone offset comes from system settings, it's not a property of the Date itself.
So, given:
My question is, if I were to run this same code again after the 30th
October when the clocks have gone back, would I still get the same
result of 23:30, or would it be 22:30 as if it were GMT?
the answer is "yes", it will still be 23:30 since on 13 September BST applies. It doesn't matter when the code is run, only what the system offset setting is for that date.
In your case, the Date was created using epoch 1473805800000 and converted to your timezone GMT+0100. Epoch is always UTC time, therefore it was read as UTC and converted to your current timezone.
On September 13 2016, GMT+01 had summer time, therefore it was considered in the calculus.
In my case, I get the following, running the same code as yours:
Thu Sep 15 2016 14:13:14 GMT-0300 (E. South America Standard Time)
I'm logging out the following....
dbResponseStub.startTime = new Date(2014,6,13);
console.log(dbResponse[0].startTime);
console.log(new moment(dbResponse[0].startTime).utc().format());
But I am getting...
Fri Jun 13 2014 00:00:00 GMT+0100 (BST)
2014-06-12T23:00:00+00:00
I'm confused because the second one is an hour behind what it should be. Obviously the BST thing that happens in the first one is causing a problem. Anyone know how to turn this off in node so that what time i say it is it will be?
Dates are given in local time.
The first one has BST in it because it is showing you the time zone, and that is the time zone the computer is configured to use.
British Summer Time is an hour ahead of Coordinated Universal Time.
If you want to stay in BST then remove .utc() so you don't convert to it.
I have just cast a 08/23/2012 to date in javascript:
var value = '08/23/2012';
var newdate = new Date(value);
newdate happens to be Date {Thu Aug 23 2012 00:00:00 GMT+0100 (BST)}
I live in London (GMT 0:00) so where does the +1 assumption come from and how can I set it right?
You're in the Europe/London timezone, with is GMT+0100 during the summer, due to the Daylight Saving Time scheme.
This is why it's usually better to configure systems based on the location, and adapt the timezone by looking up the tz database. Unfortunately, JavaScript implementations in browser are quite poor regarding the general handling of time zones.
London is currently GMT+1 because of Daylight Savings.
If you want dates unaffected by timezones or DST, you need to do two things:
Define dates with a timestamp. A timestamp is a number of milliseconds since the Epoch, and is completely agnostic with regards to timezones and DST
Use the Date.getUTC___() functions to get the date and time in UTC, which is basically GMT but without the daylight savings.
I want to show the timezone code (such as BST or GMT) based on the user's locale. However, in each browser it is positioned in different places from new Date().toLocaleString() and on some browsers (such as Opera) it is not available at all.
It looks like the solution would be to get a database or structure of timezone codes against timezone offset but there can be multiple matches (e.g. BST == GMT) and I can't even find such a list.
Does this mean it can't be done?
You have to manually define the timezone differences in your code. It is complicated because GMT time is different than UTC (Zulu) time. GMT includes a change for daylight savings time, while UTC has no daylight savings and is otherwise the same timezone representation.
Additional confusion is that not all political zones define their timezones to vary by an example number of hours. India is UTC + 5.5 hours and Afghanistan UTC + 4.5 hours. Notice that is UTC and not GMT as the base as those countries do not observe daylight savings. Some small island nations in the southwest Pacific can vary on the quarter hour.
Then some political timezone definitions have internal differentiation. Arizona is typically considered to be in the US Pacific timezone, GMT - 8 hours, except that it does not observe daylight savings, so half the year it is in US Mountain timezone as Arizona is really UTC - 8.
With all that confusion there are hundreds of definitions for timezones, and some of those change as political boundaries change. I just say screw it and use either the user's clock time or adjust to UTC time by dynamically adjusting a constant in your JavaScript from the server to reflect a known value that represents UTC time when the user requested the page.