Client Timezone in ASP.NET - javascript

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.

Related

how to get clients actual time and timezone to perform system time check

This might be a very vague question but please bear with me.
I am working on an application that requires me to perform a system time check on clients machine. The issue I am trying to address is, when clients travel across timezones and change their system time instead of changing the timezone it creates problems during the oauth negotiation. How should I go about addressing this problem in such a way that this issue can be self-detected when a client tries to login to the app rather than having to manually detect this kind of issue?
You can call toUtc() on a new DateTime.now() to convert it to UTC. It shouldn't be affected by time zones if it's in UTC, and the string representation will look like "2013-10-18 08:52:16.861Z" (the Z at the end means UTC).
You should be able to use a DateTime in UTC for OAuth negotiation. If not, please share more details; it's probably a bug in either Dart or your OAuth client.
It sounds like your timezones are pretty important so you shouldn't trust JavaScript system time with a 10 foot stick.
If I were you I would use PHP to geo-locate them and apply the timezone based on their location.
You will want to check out Get PHP Timezone Name from Latitude and Longitude?

Get client's timezone offset in ExpressJS

I'm searching for a way to get client's timezone offset in ExpressJS (with req object, for example, would be really great).
If you control the client, you can do this with client-side JavaScript.
If you don't (e.g. you're building a server-side component like an API), then you can't pull it out of the HTTP request (unless you're using sessions, but even that's not necessarily reliable).
On the upside, if it's only server-side, you shouldn't worry about it either: set all your date objects as UTC or a Unix timestamp and leave it to the client developer to handle timezones.
As others have mentioned, getting the client-side browser/OS timezone offset is not available via HTTP, so you need to send this data from the client side.
In my case I have an app that requires login...so I can store a user's preferences. The default is to use browser timezone, but the user can also configure a specific timezone to use all the time instead which is stored in their user profile (e.g. America/Dallas or Europe/Amsterdam).
I don't trust browser time to be correct. The user may have also screwed up their OS timezone setting...so timezone offset may also not be correct. However most modern OSes set timezone automatically based on Geo-IP implied location...so for many users the convenience of being able to travel around the world and login to the app and see date/time in whatever local timezone they happen to be in is worth the effort for the user experience. Users that always want to see a specific timezone can configure that and we will use that preference instead.
The way I do this is the following... on the login form add a hidden field and set the value with javascript. When the user logs in, store this timezone offset in the session. If the user hasn't set a preferred timezone, then we use this offset when rendering date/time. This means that if you have long sessions and a user can travel around between countries...they will still show the old timezone offset until the next logout/login. You can of course get this data more frequently or even on every request if you want...but for my purposes getting this on login is enough. My sessions are expired on IP address change anyway...so yeah. Of course if their session crosses a daylight savings switch then the offset won't be accurate until the next login (assuming their OS/browser TZ is correct in the first place).
Client Side
<input type="hidden" name="tzOffset" id="tzOffset">
<!-- ... -->
<script>
var tzOffset = new Date().getTimezoneOffset(),
tzInput = document.getElementById('tzOffset');
tzInput.value = tzOffset*(-1);
</script>
Note that I multiple it by -1 because I am going to use moment.js for formatting on the express end and the offset is backwards (utc offset from local vs local offset from utc). You could also do this on the server end. You should probably validate this number as well before using it...just minimal example code here.
Server Side
Then on the server side (express) if there is a successful login, I stick that tzOffset value in the session.
Then when formatting dates in express with moment-timezone I can do something like the following. This function is a "formatter" which I can expose to pug/views and then format any random date object with the right timezone/formats for the user.
function formatDateTimeForUser (date) {
var userTZ, // user specified TZ like Europe/Berlin
userTZoffset, // tzOffset we got from login form
userDateFormat, // user specified date format (or default)
userTimeFormat; // user specified time format (or default)
if (userTZ)
return moment(date).tz(userTZ).format(userDateFormat+' '+userTimeFormat+' zz');
else
return moment(date).utcOffset(userTZoffset).format(userDateFormat+' '+userTimeFormat+' ZZ');
}
The ZZ format is for showing timezone in numeric offset format (relevant when we use a fixed numeric offset from client.
The zz format is for showing timezone in character format (e.g. PDT, PST, EST, etc) which is relevant when we have a timezone like Europe/Berlin instead of a fixed numerical offset.
Another approach
Push raw dates to client and do client-side formatting. Downside is less control and consistency and more js to push to the browser. moment will also run client side if you like.
I just configure my formatters server-side based on user locale and user prefs and then expose those formatters for use in my pug templates in express. So far it works pretty well for me.
Funny Story
I had a co-worker that manually set the wrong timezone on their computer and so the time was wrong. Instead of fixing the timezone they disabled network time and manually set the time to be the "correct" time.
Then they got grumpy when everyone was showing up to meetings they scheduled an hour late.
So yeah...no guarantees the client-side time or timezone offset will be correct.
The reality is, even if you have got the timezone offset, it doesn't mean you have the the correct time on client side, considering some area have "daylight saving time".
But, you could "guess" which timezone the user is in, considering the following data:
req.get('Accept-Language'), for which country is the user may live in now;
req.ip, to search in a database and find out the approximate location;
client-side (new Date).getTimezoneOffset(), for timezone offset;
Finally, through the calculation of the above result, your guess should be almost there. The timezone should be stored in string like 'America/New_York' but not a timezone offset number.
http://momentjs.com/timezone/ should be a good tool to deal with timezone.
After you save the "almost correct" timezone, don't forget to leave a place where user can change it.
Some people like using the library momentJS for anything dealing with time, but I believe the Date object in Javascript suffices what you are looking for and does not require a library. The getTimezoneOffset is what you will need. I hope this helps! Let me know if you have other questions!

Enforce timezone for angular.js application

I'd like to use one single timezone for an angular.js application. I'm aware that angular.js currently uses browsers timezone settings for date formatting, but I'd like to override this setting so that I can enforce a specific timezone for a user so that it doesn't depend on a browser settings.
It is a business application in question so there is no need for user specific timezones. Everything happens in a company's specified timezone and this is why I'd like to enforce it for every user. Data is saved in UTC, but it needs to be shown in company timezone for every user without depending on user location/locale/browser settings.
Is there any way I can accomplish this that anyone is aware of? And if there is, it'd be greatly appreciated to point me to correct way to do it :) So far I've had zero luck with it.
You can use a library such as timezone.js, or moment.js. I've used timezone successfully, and I've heard moment.js works pretty well. You'll likely want to make an injectable factory..
angular.module('date', [])
.config(function () {
timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.init();
})
.service('dateConverter', function () {
return {
toDisplayDate: function (utcDateIn) {
return new timezoneJS.Date(utcDateIn, 'America/Los_Angeles')
}
}
});
That's just off the top of my head, but it's an example of what you'll probably have to do - convert dates from native JS to the library dates.
Sorry, but it's not possible to change the time zone behavior of the JavaScript Date object. It will always use the time zone of the computer that it's running on.
The best you can do is work around it with one of the libraries listed here. Stephen's answer shows how you can integrate one of them in to Angular.
Also, I'd consider very carefully when you say "there is no need for user specific timezones". Sometimes, that is the case, but very rarely. Often, companies have locations in multiple time zones, or they have employees that travel, or they interact with customers or partners that are in different time zones.
Besides, if what you say is true - that users are always in the single time zone of the company, then wouldn't that already be the local time zone for their computer? If so, then there's not much to do.
If you have users in other time zones, but you wish them to use the company's primary time zone, then that would be a case that would require one of these libraries. But consider carefully the impact of that. Depending on how far away a user is, even their current date might be different than the company's date.

Rails Time Zone Mapping for browser detected Timezones

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!

Javascript date object in different locale and timezone

I need to write a web application that show events of people in different locale. I almost finished it, but there're 2 problems with date:
using date javascript object, the date depends on user computer settings and it's not reliable
if there's an event in a place with dfferent timezone respect user current position, i have to print it inside (). Is it possible in javascript to build a date object with a given timezone and daylight settings?
I also find some workaround, such as jsdate and date webservices, but they don't overcome the problem of having a javascript object with the correct timezone and daylight settings (for date operation such as adding days and so on).
A couple of things to keep in mind.
Store all event datetimes in UTC time
Yes, there is no getting around this.
Find out all the timezones...
...of all the users in the system. You can use the following detection script: http://site.pageloom.com/automatic-timezone-detection-with-javascript. It will hand you a timezone key such as for example "America/Phoenix".
In your case you need to store the timezone together with the event, since a user may switch timezone - but the event will always have happened in a specific one. (argh)
Choose your display mechanism
If you want to localize your event dates with Javascript, there is a nifty library for that too (which can use the keys supplied with the previous script). Here: https://github.com/mde/timezone-js.
with that library you can for example do this:
var dt = new timezoneJS.Date(UTC_TIMESTAMP, 'America/New_York');
or
var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');
where UTC_TIMESTAMP for example could be 1193855400000. And America/New_Yorkis the timezone you have detected when the event took place.
The dt object that you get from this will behave as a normal JavaScript Date object. But will automatically "correct" itself to the timezone you have specified (including DST).
If you want to, you can do all the corrections in the backend - before you serve the page. Since I don't know what programming language you are using there, I cannot give you any immediate tips. But basically it follows the same logic, if you know the timezone, and the UTC datetime -> you can localize the datetime. All programming languages have libraries for that.
You're missing the point of a Date object. It represents a particular point in time. As I speak, it is 1308150623182 all over the world. Timezone only comes into play when you want to display the time to the user. An operation like "adding a day" does not involve the time zone at all.
One possibility might be to use UTC date and time for everything. That way, there is nothing to convert.
Another is to have your server provide the time and date. Then you don't have to depend on the user to have it set correctly, and you don't have to worry about where your user's timezone is.
Use getUTCDate(), getUTCHours(), ... instead of getDate(), getHours(),...
getTimetoneOffset() could be useful, too.

Categories