Wouldn't these values always been the same as getSeconds and getMilliseconds?
The adustment between local time and UTC time is based on an offset specified as a number of milliseconds.
http://es5.github.com/#x15.9.1.7 says
15.9.1.7 Local Time Zone Adjustment
An implementation of ECMAScript is expected to determine the local time zone adjustment. The local time zone adjustment is a value LocalTZA measured in milliseconds which when added to UTC represents the local standard time. Daylight saving time is not reflected by LocalTZA. The value LocalTZA does not vary with time but depends only on the geographic location.
As to when this is useful, http://bugs.python.org/issue5288 explains an API problem that arose from assuming that timezone offsets were an integral number of minutes:
The Olson time zone database (used by most UNIX systems and Mac OS X)
has a number of time zones with historic offsets that use second
resolution (from before those locations switched to a rounded offset
from GMT).
Once you get down to second resolution, not having a getUTCMillis just seems an odd asymmetry.
because there are leap seconds.
Related
I wanted to know if a date object created at any point of time differ based on time zones or not. I tried this by executing new Date().getTime() once for IST and immediately again by setting my PC time zone to GMT. The resultant values are:
IST - 1633334780053
GMT - 1633334788831
A difference of around 8000 milliseconds
From this it seems that datetime objects created at same moment are exactly same no matter in which time zone they are created. Please suggest if this understanding is correct or is there more to it.
You're right. Two different date time objects created at the same point of time are same no matter the time zone.
They can be formatted to their corresponding timezone representation using javascript.
One important thing to be noted is that the date time object created uses the system's date time configuration to find the correct time. If the system's date and time configurations are correct and in sync, then the date time object created in the browser will be correct and will match the system time at the time of creating that object.
This is detailed in the JavaScript specification: https://tc39.es/ecma262/#sec-date-objects.
More information is in the MDN docs Date.getTime():
The getTime() method returns the number of milliseconds* since the Unix Epoch.
*JavaScript uses milliseconds as the unit of measurement, whereas Unix Time is in seconds.
getTime() always uses UTC for time representation. For example, a client browser in one timezone, getTime() will be the same as a client browser in any other timezone.
So new Date().getTime() will always return the number of milliseconds since 1970-01-01 00:00:00 UTC, regardless of the client / machine timezone setting.
I save dates as UTC in mongoDB. I already know that date object creation converts it to the local time offset according to the user's OS settings.
But let's say that in 21 aug 2020 the local offset was +8 hours and because of daylight saving in 22 aug 2020 the offset was +9.
My question is what happens to past dates I saved in the DB. The Date object will convert it to the local time as it was in the past date or it converts to the local time as for now.
Hope I explained it well. Thank you in advanced.
UTC does not have the concept of daylight savings time. DST only applies to local times.
Therefore dates that are stored in UTC are not affected by DST in any way.
Another way of looking at it is time in UTC is always continuous.
When you are converting from UTC to local time, you need to know which time zone the local time is in. Time zone is not the same thing as a UTC offset - a time zone is a rather extensive set of rules and historical transitions that define exactly what time it was in that time zone at any instant in physical time.
For example, a time zone is "America/New_York". This time zone uses two UTC offsets, -4 and -5, depending on time of year, and what year it is.
So a little context, I have an array of 24 arrays -- one for every hour in the day.
So midnight, 0 index, would be [133.00, 234.00] which would indicate 133 actions from 12 - 1230 and 234 actions between 1230 - 1am.
I need to adjust these indexed arrays to account for the user's timezone in a browser with JS, so that if the user is in New York the 0 index (midnight in the user's home turf) is displayed in China's offset (12pm tomorrow, from user's perspective).
I've been trying to think of a solution, I have a simple function for what I've been able to think of
function offsetHourIndex(hourIndex, dataCenterTimeZone) {
let userTime = new Date().setHour(hourIndex)
return moment(userTime).tz(dataCenterTimeZone).hour();
}
How reliable would this approach be?
Your approach has a few problems:
You are assuming that the current date in the local time zone is the correct date for the target time zone. Most of the time, there are two dates active somewhere around the world. For example, 2019-04-02 04:00 in London is 2019-04-01 23:00 in New York. If you just take hour 4 from London but apply it to the current date in New York, you've created a whole new point in time, a day too early.
You assume there will be exactly 24 hours in every day. In time zones that have transitions for daylight saving time or changes in standard time, you may have more or less hours of local time on a the day of the transition.
In the case of a backward transition, there is a period of ambiguous local time. For example, when US Pacific Time moves from PDT to PST in November, the hour from 1:00-1:59 is repeated. If data from both hours are summarized into array element 1, then you will have higher than normal results for that hour. The opposite is true for forward transitions - you will have an hour with no data.
The time zone setting of the server can be a fickle thing. What if you change data centers? What if you move to the cloud? What if you are operating multiple data centers? What if a server administrator thinks all they are affecting by changing the system time zone is the readout on the taskbar or front panel, etc., and then it affects your application? In general one should avoid these things by never relying on the server's local time zone setting.
You can avoid all of these problems by basing everything on Coordinated Universal Time (UTC) - especially the array. Then you can be ignorant of any server time zone setting, and just base everything off the current UTC day, which is the same all over the world.
This will give you the local hour from the given UTC hour in your index:
var localHour = moment.utc({hour: hourIndex}).local().hour();
You do not need moment-timezone for the above recommendation.
However, if you really feel like you need to convert from a specific time zone to the browser local time, then you would use moment-timezone like this:
var localHour = moment.tz({hour: hourIndex}, timeZoneName).local().hour();
Note when you do this, you also have another problem - not every time zone is offset by a whole number of hours. For example, India uses UTC+05:30. There are many that are :30 and a few that are :45. By tracking hours only, you're not providing enough information to properly convert to the correct local hour. Your results may be off by one.
It seems reasonable. And the code should work as long as you have the properly formatted inputs. I like the brevity and clarity of the function. Any reason you are concerned about reliability?
You might mention in your question that you are using the moment and moment-timezone packages here to derive your data via its functions (moment & tz) on this line of code:
return moment(userTime).tz(dataCenterTimeZone).hour();
Your function may appear a bit cryptic without the imports in your example for folks reading here to understand, such as :
import * as moment from 'moment';
import 'moment-timezone';
I've updated Chrome to 67 version.
new Date(1924,4,1,0,0,0,0).getTime()
return -1441245724000
must -1441249200000
if millisecond(1000), second(60), minute(60) === 0
getTime must give at the end a minimum of 5 zeros
There can be only one explanation: You are in Ukraine.
Allow me to explain:
When passing individual components to the Date constructor, those values are based on the local time zone of the computer where the code is running. Keeping in mind that months are zero based, new Date(1924,4,1,0,0,0,0) is asking for 1924-05-01 00:00:00.000 local time.
.getTime() is asking for a Unix timestamp in milliseconds, which are based on UTC - so there is an implicit conversion from local time to UTC. Therefore, anyone who runs this code will get different results depending on their own time zone.
Time zones are a relatively modern invention. They have not always existed in the way we use them today. The data that most computers keep about time zones comes from the IANA time zone database. In this data, for most time zones, the earliest entry is based on the solar local mean time (LMT) for the latitude and longitude associated with the city used to identify the time zone.
In this case, your value -1441245724000 translates to 1924-04-30 21:57:56 UTC. Since it was derived from a local time of midnight, then by math - the offset from UTC in that local time must have been +02:02:04.
The only time zone in the TZDB with an LMT value of +02:02:04 is Europe/Kiev, as shown here. For reasons I'm not certain of exactly, the TZDB also assigns the abbreviation KMT (Kiev Mean Time) from 1880 to 1924.
As to why you are seeing this on newer versions of Chrome - it is likely that older versions did not take the entire TZDB into consideration, but had truncated it at some point in the past. Indeed, the ECMAScript 5.1 standard used to require only the current time zone rule be applied as if it was in effect for all time. This was removed in ECMAScript 6, and most browsers now use the correct rule that was in effect for the timestamp provided.
TL;DR: Local time in Ukraine before 1 May 1924 was determined by the sun - not by the government. At least - that is the best known information that your computer has.
I have MVC web application. I am storing UTC time in database. (Not datetime but just a time). In C# When I retrieve this time from the database I get timespan object back. I also have offset available in minutes. For example.
double offset = 600;
How do I use this offset to convert timespan to local datetime.
Note I don't want to use DateTime.ToLocalTime () method because that will use server's timezone.
UPDATE1
I am using the Javascript new Date().getTimezoneOffset() method to get the client's offset, and i have offset value stored on the server. Then I also have drop down list that show times as 12:00 AM, 12.30 AM, 1:00 AM etc etc. The dropdownlist is bound to model property SelectedDateTime of type DateTime. Idea is to convert user selected time to UTC and then UTC to localtime based on the offset. So lets say i have offset 300 minitues that would be 300/60 = 5 hours
double offset = 5.00; // this is available on the server
When the user selects time in a drop down list, I am getting a datetime object on the server, ignoring the date part i want to store UTC time into database. This is how I'm converting to UTC time.
TimeSpan utcTime = SelectedDateTime.AddHours(offset).TimeOfday;
I store this utcTime into the database. Now I want to convert UTC timespan into the client's datetime.
I am assuming i have Subtract offset now
var newLocalTimeSpan = utcTime.Subtract(TimeSpan.FromHours(offset));
var newLocalDateTime = new DateTime(newLocalTimeSpan.Ticks, DateTimeKind.Local);
However this throws the error:
Ticks must be between DateTime.MinValue.Ticks and
DateTime.MaxValue.Ticks.\r\nParameter name: ticks
For example with offest 5 hours, If user selects 8:00 PM then it will be converted to UTC and will be stored as 01:00:00.0000000 in database. When I retrieve the UTC value from database its '1:00:00 AM'. Then I subtract 5 hours form this TimeSpan which equals to `-4' now and if I pass Ticks to DateTime..i get above error.
NOTES: If you are curious why model property is DateTime instead of TimeSpan thats because i am using Kendo TimePicker which needs DateTime type.
UPDATE 2
I really appreciate all for your help. I have gone through all the articles #Matt Johnson has posted and it looks like I should not be using offset for calculating the UTC time. Mainly because of the day light time saving. But instead I should be using timezone. So I have 3 options here to find client’s time zone:
1> Use JavaScript to detect time zone
In JavaScript I can do new Date().toString() which returns date time as Sun May 22 2016 02:12:36 GMT-0500 (Central Daylight Time) I can then parse the string to get “Central Daylight Time” and post it to the server. However on server, for .net “Central Daylight Time” is not a valid windows time zone ID.
Question
Is this correct approach? Is JavaScript returning IANA zone id? Will it always return IANA zone id?
If JavaScript is returning IANA Id then I can use Matt’s article here to get windows time zone id
2> Use http://momentjs.com/ to detect client’s time zone
Question
Is momentjs returns IANA zone id?
If momentjs return IANA zone id then I can use Matt’s article above to get windows zone id. One of the reason I don’t like this approach is because I have to use 2 third party libraries momentjs and Noda Time
3> Provide user a drop down list using TimeZoneInfo.GetSystemTimeZones() and let the user selects the timezone.
User will select a time and timezone, then on server I will convert it to UTC using selected timezone and save it DB. However I have to show that time on some other pages, So I again need timezone. That means I have to put the drop down list in such a place on UI where it will be available all the time. Like top menu.
(I can certainly save timezone into DB along with the time, however if user travel to other place he will still see time in initially selected time zone. Which I don’t want)
Are these correct approaches? Am i missing something?
Question
Assume that I implement timezone selection using one of the approach above and i have correct client's time zone with windows timezone id on server in some variable.
Now lets say user selects 6:00 PM (Central Daylight Time , UTC -5) which will convert to UTC as 23:00:00. As long we are in Central Daylight Time the conversion from UTC to local will show 6:00 PM. Once we go into Central Standard Time which is UTC -6 Will the conversion still show 6:00 PM or 5:00 PM?
I am planning to use TimeZoneInfo.ConvertFromUtc(datetimevalue, timezone) method for converting UTC to Local
In general, there are only two viable approaches:
Pass only UTC dates and times to the client, and do all conversions to local time in the browser using JavaScript.
Use this approach when you don't care what the time zone actually is, but you just want it to match the browser's local time.
The Date object can do this, but you may find it easier to use a library such as moment.js, which gives you better control of output format, among other things.
Apply a time zone (not just an offset) to the UTC date and time on the server side, to produce the correct local time value.
Use this approach when the time zone affects an entire application, and needs to be known in server-side business logic.
You can try to guess the user's time zone using jsTimeZoneDetect or moment.tz.guess() in moment-timezone. However, it's just a guess, and it is always an IANA time zone ID (such as America/Los_Angeles).
Asking the user for their time zone from a list is a good idea. Usually one would place this on a user settings or profile page. You can use the guess made earlier to pick a default value from the list.
You will indeed need to use Noda Time on the server if you are using IANA time zones on the client.
Some applications choose to list Windows time zones instead, which is a much simpler approach as you can get everything from the TimeZoneInfo class. However, recognize that there are limitations with this approach including:
Localization issues, as you cannot easily get at display name strings other than the ones matching the operating system's default language, not .NET's globalization and localization features.
Maintainability issues, as you yield control to the operating system for keeping the time zone data updated. This may seem more convenient, but you may find that your hands are tied when keeping up with short-notice time zone changes. This is especially problematic when you don't have control over how or when updates are applied to the OS, such as with Microsoft Azure App Service.
Compatibility issues, as Windows time zones aren't generally recognized outside of Windows. If you ever expose the user's time zone setting in an API, you'll likely have translation issues for callers from other platforms.
Now, getting to your specific points:
I am using javascript new Date().getTimezoneOffset() method to get the client's offset...
That gives you the client's current offset. You have no guarantees that it is the correct time zone to apply for an arbitrary date and time.
If wanted to apply a fixed offset to a UTC DateTime in C#, the best way is with a DateTimeOffset.
DateTime utc = new DateTime(2016, 12, 31, 0, 0, 0, DateTimeKind.Utc);
DateTimeOffset dto = new DateTimeOffset(utc); // DateTimeKind matters here
TimeSpan offset = TimeSpan.FromMinutes(-300); // The offset is inverse of JavaScript's
DateTimeOffset result = dto.ToOffset(offset);
But do note this is only for a fixed time zone offset. For a true time zone, you would use the TimeZoneInfo class if you're using Windows time zones, or you would use NodaTime's DateTimeZone class for IANA time zones.
In JavaScript I can do new Date().toString() which returns date time as Sun May 22 2016 02:12:36 GMT-0500 (Central Daylight Time) I can then parse the string to get "Central Daylight Time" and post it to the server.
No, this approach is not recommended, for several reasons:
There's no guarantee you will get output in any particular format from JavaScript's toString function. The results are implementation specific, and will vary across browsers and platforms.
They are generally intended for display purposes. When DST is in effect, they'll show a daylight name, and when standard time is in effect they'll show a standard name.
They are often localized for the user's language, English, French, Chinese, etc.
The only native API that can return the user's time zone is:
Intl.DateTimeFormat().resolvedOptions().timeZone
This is part of the ECMAScript Internationalization API. Unfortunately, it currently only works in a handful of browsers. Both jsTimeZoneDetect and moment.tz.guess() will use this API if it's available, then will fall back to their own guessing logic if not.
Assume that i implement timezone selection using one of the approach above and i have correct client's time zone with windows timezone id on server in some variable. Now lets say user selects 6:00 PM (Central Daylight Time , UTC -5) which will convert to UTC as 23:00:00. As long we are in Central Daylight Time the conversion from UTC to local will show 6:00 PM. Once we go into Central Standard Time which is UTC -6 Will the conversion still show 6:00 PM or 5:00 PM?
I am planning to use TimeZoneInfo.ConvertFromUtc(datetimevalue, timezone) method for converting UTC to Local
As you said earlier, "Central Daylight Time" is not a valid Windows time zone identifier. Your user wouldn't pick that. You'd display a list generated from TimeZoneInfo.GetSystemTimeZones(), showing the DisplayName to the user, and using the Id for the value. The Id would be "Central Standard Time", which indeed is the correct identifier for US Central Time, inclusive of both CST and CDT - despite having the word "Standard" in the string.
You need to convert the TimeSpan to a DateTime, using the current Year, Month and Day. If you subtract from a TimeSpan without doing so, it can result in an unobtainable date.
Also, I noticed in your update that you left the results in a DateTime, so I did the same.
This code is showing you the time if the UTC time was 1:00 AM, as your problem states.
double offset = 5.00;
TimeSpan utcTime = new TimeSpan(1,0,0); //setting manually to your representation of 1 am.
DateTime newLocalDateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, utcTime.Hours, utcTime.Minutes, utcTime.Seconds);
newLocalDateTime = newLocalDateTime.Subtract(TimeSpan.FromHours(offset));