I am working on a application, which detects the browser's time zone and asks the user's to set the time zone to the browser detected values.
So, I have populated, a select drop down which list all the All the keys present in ActiveSupport::TimeZone::MAPPING.
Now, I have a user whose timezone is (GMT-08:00) Pacific/Pitcairn.
There are many such values which are not present in ActiveSupport::TimeZone.
How should I handle such values. I've checked many js files which claim to send in Rails Supported Values, but none of them seem to work.
If I set my timezone to UTC-08:00 in Windows machine then my javascript plugin detects a time zone and sends in a value of America/Los Angeles.
We have a check box to not allow DST Timings on Windows machine.
So in this case with UTC-08:00 as time zone and DST box unchecked we're getting a value Pacific/Pitcairn.
So to go with matching before / for two different values of America/Los Angeles and Pacific/Pitcairn it's not possible.
Set the value by UTC offset, by ignoring name also wouldn't help. We have two seperate value with (UTC-08:00) Pacific Time (US & Canada) and (UTC-08:00) for Tijuana. So how do I decide which value to set.
showTimeZoneInfo: function(member_time_zone, timeZoneInfo, invertTZHash){
var tzValue = jQuery().get_timezone({'defaultvalue' : 'Etc/UTC'});
var railsOffset = TimeZoneFlash.extractOffset(timeZoneInfo[member_time_zone]);
var browserOffset = TimeZoneUtils.zoneWithoutDST();
if ( railsOffset != browserOffset) {
jQuery(".time_zone_text").text(browserOffset + " " + invertTZHash[tzValue]);
jQuery('.cjs_display_time_zone').removeClass('hide');
}
}
Now we have a case where invertTZHash doesn't contain Pacific/Pitcairn. And It returns a undefined value.
I am working on building a alert box for users who are in a different time zone compared to their browser's timezone. Even Intl.DateTimeFormat().resolved.timeZone wouldn't help because most of my traffic is from IE and FF browsers
Time Zone != Offset. See the timezone tag wiki. So just swapping it for another time zone that happens to be on UTC-8 is not a good idea. You will pick up all the DST rules for that zone, which don't necessarily apply.
Even Pacific/Pitcairn isn't purely UTC-8 if you deal with past dates. It moved from UTC-08:30 to UTC-08:00 in 1998 - you can see that here.
This is one of the reasons I'm not happy with ActiveSupport::TimeZone. They make it quite clear in their docs that it is limited:
Limit the set of zones provided by TZInfo to a meaningful subset of 146 zones.
This seems rather arbitrary. Who is it that determines what is "meaningful" and what isn't? If it wasn't meaningful, it wouldn't have been in the database to begin with!
You should look at using the tzinfo gem, which is what ActiveSupport based theirs on anyway. It has the full TZDB with all of its time zone data instead of a limited subset.
Regarding time zone detection, I'm not sure what JavaScript you are using to "detect" the time zone. You show calling some functions get_timezone and TimeZoneFlash.extractOffset that must be custom to your app or provided by external libraries. Please elaborate on exactly what you're using.
The only timezone detection library for JavaScript that I am aware of is jsTimeZoneDetect - which makes it quite clear that it just takes an educated guess. Unless you are depending on the new internationalization APIs in the very newest Chrome an Opera (which I don't think you are), then there's no guaranteed way to detect a time zone without user involvement. See also this answer.
We have a check box to not allow DST Timings on Windows machine. So in this case with UTC-08:00 as time zone and DST box unchecked we're getting a value Pacific/Pitcairn.
Yes, that is an awful reality. IMHO - that should never be unchecked. It would be better if the checkbox wasn't there. Whether DST applies or not is handled by the time zone, so there's no good reason to disable it. I'm sure that they left it there specifically for cases like Pitcairn, because there isn't a Windows time zone entry for them specifically.
Update
From your comments:
I already have a drop-down for this. I am working on building a alert box for users who are in a different time zone compared to their browser's timezone.
Take the current offset from JavaScript using new Date().getTimezoneOffset(). (It's in minutes, and the sign is reversed, so you may need some simple math.) Compare it to the current offset for the selected time zone in your drop down. (You should be able to get that from your server-side code.)
If they don't match, then alert your user. No need for jsTimeZoneDetect at all for this.
First Option: Set by UTC Offset
Get the UTC Offset
Search for UTC offset in your ruby array.
Set value by UTC offset, ignore name. Choose the first timezone which has the correct UTC offset.
Some code for this:
timezone = ActiveSupport::TimeZone.all.select { |tz| tz.utc_offset == my_offset }.first
Second Option: Add a new Timezone to the list
If you know the UTC offset, add a new TimeZone to the list. See Docs.
Hope that helps!
Related
I have some timezone saved in my profile as "America/New York". When my device moves to "Dubai" then device timezone is changed while profile timezone is still "America/New York".
(1) How to autodetect and prompt user that his device timezone has changed and is different from profile/saved timezone?
The user is accessing app through channels like web, android and ios device as well.
(2) How to get list of available timezones so that when prompted for timezone change, he can manually update profile timezone same as device timezone.
This timezone list should be same for all devices like web, android and ios device.
The issue here, is some timezone returns "Asia/Kolkata" and "Asia/Calcutta". Since to synchronize all devices regarding timezone. How to get list of available timezones same for all devices.
How to autodetect and prompt user that his device timezone has changed and is different from profile/saved timezone?
Time zone detection is covered in this answer. There are multiple approaches, but ultimately you want to get the IANA time zone identifier (such as America/New_York) to compare against your saved value in the user's profile.
How to get list of available timezones...
JavaScript doesn't have a built-in method for this, but you can use a library. For example, Moment-timezone provides the moment.tz.names() function, and Date-fns-timezone provides the listTimeZones() function.
... This timezone list should be same for all devices like web, android and ios device.
While most environments use IANA time zone identifiers, there is no guarantee that all devices will have fully updated data. Say a new time zone is introduced and your devices detect it - if your server-side platform doesn't have the latest time zone data, then you might encounter an error. The best thing you can do here is to make sure you regularly check for updates, which varies depending on platform.
... some timezone returns "Asia/Kolkata" and "Asia/Calcutta"
That is fine. Asia/Kolkata is the prefered canonical zone, and Asia/Calcutta is a link (or alias) of that zone. All modern platforms should be able to interpret either. If you're trying to do this yourself, you'll need to be sure to resolve links to their canonical zones before comparing. There are libraries that can do this for you.
The frequency of the check should be based on your own analysis: if the timezone should be automatically updated (or the user should be prompted almost immediately to update it's own timezone) a setInterval that performs a check each minute should be the best option.
I think that the best option is to use a time parameter instead of the matching string, like the offset expressed in minutes if compared to the UTC. Actually, JavaScript comes in handy with a quite useful method placed into the DateTime object:
setInterval(() => {
let dt = new Date();
if(dt.getTimezoneOffset() !== localStorage.get('tzOffset') {
// redirect to a proper component or automatically update the tz
}
}, 60000);
I am assuming that you are storing the current timezone in the local storage at the key 'tzOffset'. getTimezoneOffset returns the difference in minutes between UTC time and local time, accprdingly to the MDN
For what regards the other question, using moment timezones could help a lot to obtain a properly formatted select on different devices:
for(let tz of moment.tz.names()) {
// do your stuff wuth the timezone name
}
I realize this is a commonly asked question but I couldn't find any posts that point out the disadvantages of using/storing offset for user's time zone. Is this not a better and more efficient way?
Long drop down lists of time zones are not user friendly and most of such lists don't have all the cities anyway. They also require user to specify their time zone. I feel it may be much better to simply detect it. In my case, my app is an ASP.NET Core app with Reach front end and it's pretty easy to capture user's time zone offset via JavaScript.
Any reason why storing the offset of user's timezone is NOT a good idea?
Any reason why storing the offset of user's timezone is NOT a good idea?
Yes. Many. A time zone and an offset are not the same thing. A time zone represents a geographical area in which local time is aligned. A time zone may undergo several different changes in its offset from UTC. Some of which are regular (like daylight saving time), and some of which are irregular (like when a government changes its standard time or dst rules).
... In my case, I simply want to display all date time values in user’s current time zone so that they’re meaningful to the user.
Ok, so let's say you check the user's current time zone offset and it is UTC-7. So you apply that to some dates and times in your application and done - so you think. Except that you didn't take into account that the user is in California, and one of your dates is in December when the offset should be UTC-8.
So you try to correct for that, and work out the rules of "when I see -7, it might be -8 sometimes". Except now you have a user come along who is in Colorado, where it is -7 during the winter and -6 during the summer. Or another user from Arizona, where most of the state is in -7 for the whole year. How do you know which set of rules to follow? Without referencing an actual time zone, it cannot be done.
This gets even more complex worldwide. For example, the number of variations for UTC+2 is just crazy. Even for countries that switch between UTC+2 and UTC+3 - they don't all switch on the same dates or at the same time of day!
See also: The Problem with Time & Timezones - Computerphile (YouTube)
and the StackOverflow timezone tag wiki.
I have an admin panel where items entered will have a time_posted and an expiration time. These times use a timestamp (time()) upon being entered.
I want the entering of the expiration time to use a fancy date/time selector, but the selector uses JavaScript client time rather than server time.
A way to fix this would be to save the timezone a user is in, then use that as offset for the data entered, but it's something that has to be 100% correct.
Is there any 'proper' way to approach this? I saw that some PHP functions do use the timezone setting but others do not, for instance the actual time() function doesn't and even if I create a DateTime object, output the current timestamp, change the timezone and output the timestamp again it just returns the same timestamp twice.
Any pointers would be lovely
I assume that the actual timestamp value would still be correct (independent) regardless of what settings/timezone the end user has.
Problems may apper when/if you want to generate date strings server-side and thus return times with offsets.
Either
1. dont generate date strings server side, if you are not sure about the timezone offsets or
2. warn users and make sure that they specify their timezone and then force that timezone whenever you output date string from timestamps
A few things:
You probably don't need to identify the user's time zone for the scenario you describe, but if you did then please recognize that a time zone and an offset are two different things. See "time zone != offset" in the timezone tag wiki. If you actually think you need the user's time zone (such as "America/Los_Angeles"), then refer to this answer.
If you want the entered date to be relative to the client's local time zone, then you need to use either a Date object, or a library like moment.js in JavaScript. Use the individual date/time components from the date picker to get either a unix timestamp, or an ISO8601 formatted date/time string at UTC. For example, "2016-09-02T01:23:45Z"
If you want the entered date to be relative to some other time zone, then you need to transmit the actual values the client entered without modification. The best way is in ISO8601 format without offset. For example, "2016-09-02T08:00:00". On the server side, parse that value and apply whatever time zone is applicable.
If you are only selecting a date, and not a time, then you should really think about whether any time is applicable or not. Is 00:00 really applicable? Or should it be 24:00 or 23:59:59.999? If you don't care about the user's time zone, then really you shouldn't assign any time value at all. Just pass the date. For example: "2016-09-02"
Don't rely on the server's time zone setting to be anything in particular. Though PHP has functionality for setting a "default" time zone, you should try to avoid using it. It is much safer to be explicit about time zones on a per-operation basis. Use the DateTime class in PHP, not time().
Be sure to read Daylight saving time and time zone best practices, and to search thoroughly for other questions on StackOverflow, as much of this has been answered already in various other questions.
I have a table that needs to display a date/time in the client's timezone. However, I am having a hard time finding a way to do this effectively. I know I can use client side javascript to get the timezone (and that this method is a little flaky), but I need it in the Page_Load event, so I can't call javascript beforehand.
I can get it from a separate page (at login for example), but that doesn't always work, because sometimes people use bookmarks directly into internal pages, and bypass logon with a cookie.
So I am left a few choices:
1. Have a cache per user for the last timezone that I fill up at every opportunity from a postback with no guarantee it will be right)
Try some weird IP geolocation hack
Have a user profile that allows the user to set their timezone (again, if they travel this won't always be right either)
Try some funkly page redirect to force the postback, (but some browsers disable page redirects)
Have the user explicitly set the TZ
Do the tz formatting in Javascript
None of these are ideal, it seems to me to be info the Browser should be providing the server. Does anyone have any other suggestions?
If possible, display times relatively. Rather than showing a particular time, use prose like, "5 minutes ago," or "Last week."
If you must display an absolute time in the client's time zone, based on your comments I'd go with option #5, sending UTC time down to the browser and then displaying local time using JavaScript. From your description it sounds like users can visit the page(s) that need to display the time in their time zone without having logged in, so storing it in the user profile seems inadequate.
I discuss the relative time display concept in more detail in Advice for Storing and Displaying Dates and Times Across Different Time Zones, as well as provide a simple extension method on the DateTime structure for adding a ToRelativeDateString method so that you can write code like:
string relativeTime = myDateTimeVariable.ToRelativeDateString();
Hope this helps...
I would use a mixed strategy:
Users can set the timezone in their profiles
Default is "auto" which means: format with JavaScript
Keep the timezone in the user profile however on each page that you display it (or in the master page) give the user the ability to adjust it. Once its adjusted allow it to persist for the remainder of the session and if they want it set then they will need to set it in their profile.
5, 2, 3, 4, 1 is probably the best order of your options.
Just output all times in UTC and then transform to local time at client side.
I would have to agree with Scott Michael. Display relative time, if you need absolute times your browser already knows how to localise them from UTC.
But if you're looking for detecting timezones robustly with javascript (for use server side); check out jsTimezoneDetect. It will give you an Olsen timezone key that you can use with server side normalizations of datetimes.
I thought I'd give you an update. I did take up the various suggestions of formatting the date on the client side (or more specifically reformatting it.) As google fodder I have put a full explanation of this at the end of this post.
However, the problem is that Date.toLocaleString takes no parameters to control the formatting, and so, in my US locale anyway, I get a big bulky string "Saturday, November 27, 2010 3:58:38 PM" This is way too bulky, I want a compact format like Sat 11/27/10 3:58PM" but there is not way to control it AFAIK.
So I am going to modify to try to cache the time zone in the session based on input from the various key pages posting back the timezone offset, and include the ability to modify the tz in the user's profile. It is not nice, but it is the best I can come up with. Like I say, this really should be included in the browser's http headers.
----- Formatting on the client side ------------
So I have labels like this (in a ListView FWIW):
<asp:Label ID="TimeLabel" runat="server" class="UTCTimeCell Hidden">
<%# Eval("when") %> UTC
</asp:Label>
Note you have to include UTC for the timezone since the default ASP.NET formatter does not include it. (Here I am assuming you are storing your dates as UTC, which in nearly all cases you should.) Note Hidden is a standard css class I used with display:none.
Then I define the following functions in my utilties javascript (obviously I use jQuery...)
function timeFormatLocal(timeStr) {
var dt = new Date(timeStr);
return dt.toLocaleString();
}
function timeReformatLocal(selector) {
$(selector).each(function () {
$(this).html(timeFormatLocal($(this).html()));
});
}
then in my page ready event I use something like this:
timeReformatLocal(".UTCTimeCell");
$(".UTCTimeCell").removeClass("Hidden");
This reformats those label cells to the locale based format.
I have set a deadline in UTC, as shown below, and I'm wondering what exactly the toLocaleString() method will do to it on user's local machines. For instance, will it account for daylight savings if they are in a timezone that recognizes it? Or will I need to insert additional code that checks where the user is, and then fixes the displayed time?
http://javascript.about.com/library/bldst.htm
var deadline = new Date('5/1/2013 ' + "16:15" + ' UTC');
alert(deadline.toLocaleString());
In general, the answer is yes. JavaScript will represent the UTC value at the appropriate local time based on the time zone settings of the computer it is running on. This includes adjustment for DST. However, as others have pointed out, the details are implementation specific.
If you want a consistent output, I would use a library to format your dates instead of relying on the default implementation. The best library (IMHO) for this is moment.js. The live examples on their main page will give you an idea of what it can do.
UPDATE
If you are passing UTC values that you want converted to the correct local time, and that time falls into a period where the time zone rules are different than the current one - then the results will be invalid. This is crazy, but true - and by design in the ECMA spec. Read - JavaScript Time Zone is wrong for past Daylight Saving Time transition rules
We don't know what exactly the toLocaleString method does (§15.9.5.5):
This function returns a String value. The contents of the String are
implementation-dependent, but are intended to represent the Date in
the current time zone in a convenient, human-readable form that
corresponds to the conventions of the host environment’s current
locale.
But yes, most implementations will consider DST if it is active in the current local timezone. For your example I'm getting "Mittwoch, 1. Mai 2013 18:15:00" - CEST.
Will I need to insert additional code that checks where the user is, and then fixes the displayed time?
I think you can trust toLocaleString - the browser should respect the user's settings. If you want to do it manually, check out timezone.js.
As you use "UTC" the date itself will be UTC format, but the toLocaleString() takes client's locale into account, which means it'll return the date in string updated with all and every changes typical to client's regional and locale settings (DST, date/time format, etc).As JS documentation describes this: "The toLocaleString() method converts a Date object to a string, using locale settings.".If you want to avoid this, use the toUTCString() method instead.I'd also recommend reading the accepted solution for the question Javascript dates: what is the best way to deal with Daylight Savings Time? to avoid (at least, to try to avoid :) future issues related to JS, browsers and locales.Hope this helps!