Sql server and browser timezone calculation - javascript

Following are the timezone values :
SELECT * FROM sys.time_zone_info
In Javascript, how to populate and match the timezone at DB for calculation? I also have multiple timezones, also need to work in all browsers
Daylight saving also needs to be considered.
I need a dropdown at client side for timezone and that timezone should work with SQL server timezone info, so I can use the following query,
SELECT CONVERT(datetime,'20160101 00:00') AT TIME ZONE 'Cen. Australia Standard Time';
How can I auto select drop down base on browser timezone ?

To get the client's time zone name in javascript, one method is with Intl.DateTimeFormat().resolvedOptions().timeZone as detailed in this thread. See this for browser support.
You'll also need a mapping table to associate the IANA timezone canonical name to the Windows time zone name in sys.time_zone_info for use in the AT TIME ZONE clause of the T-SQL CONVERT function. This mapping table can be used for the dropdown as well.

Related

Autodetect and prompt when device timezone is changed in angular7

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
}

PHP dates and timezones

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.

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!

For a given hour, how to get the timezone where the hour is

So to clarify why I want to do this: I need to send push notifications to users when it's 7pm in their timezone.
For each registered device, I have a timezone string, like "Europe/Paris".
I'm creating a background job which will run every hour. It should fetch the list of users for which it's 7pm, and send them a notification.
So the question I'd like to answer is:
"Where in the world is it 7pm now"
Edit The important thing is to get the timezone, even if it's not formatted like "Europe/Paris", I can do that conversion manually with an array.
There's no built-in support in Javascript for converting the "standard" timezone names (e.g. Europe/London) to timezone offsets.
You mention push notifications so that suggests you're not running in a browser. If you're using Node.js there's a good library I've used called timezone which uses a local set of timezone spec files to handle conversion between timezones.
Note that timezone specs do sometimes change, for example when a national government decides with little notice that they're not doing daylight savings this year. It's vital that your local mappings are kept up to date accordingly.
There may be an easier way to do this, but have a database of users, who have a timezone. Then have a hour difference between your notification server, and that time zone. So your server is in pacific time, and the timezone is eastern, it will have a difference of 3.
Use the difference of the time you want, and what it is on your server, to determine the timezone. You want 16:xx it is 13:xx you get +3 hour difference, use that to look up the time zone, then push to all users associated with that time zone.
There may be an easier way, but that way is real simple solution with a db and a little sql knowledge.
EDIT: Also if you dont mind the time delay of using a web api, you should check this out: https://developers.google.com/maps/documentation/timezone/
Whoops numbers were off with the time-zones, Thanks Trent

moment.js, timezones and daylight savings

I return a list of UTC dates/times from a .Net service, formatted like so:
"2013-07-09 19:48:07 +00:00".
On the client, I convert each of these string values into a corresponding UTC-based moment, like so
var fooUtc = new moment.utc(serverDateTimeString)
On the page, there is a droop-down containing a list of time-zones that the user can change. These are tied to a collection of time-zone objects like the following:
{
id: "Central Standard Time",
label: "(UTC-06:00) Central Time (US & Canada)",
observesDaylightSavings: true,
baseUtcOffset: {
asHours: -6,
asMinutes: -360,
asText: "-06:00"
}
I then display each moment passing in the selected time-zone offset, like so:
fooUtc.local().zone(selectedTimeZone.baseUtcOffset.asMinutes).format()
However, the result does not take into account daylight savings, as the timezone data coming from .Net does not differentiate between dst and non dst offsets.
Is there a way to make this work with moment.js or the new moment-timezone bits? I think it could be possible if I could map the standard UTC offset names (ex: "Central Standard Time") to a given timezone's Olson DB identifier (ex: "America/Chicago"), but if there is an easier way, please let me know.
You should explore using Noda Time on the .Net side, and moment-timezone on the client, passing the IANA/Olson time zone id.
If you want to stick to the Windows time zone ids in your drop-down list, then you can do conversions with the CLDR data embedded in Noda Time. I have documented how to do it in this post: How to translate between Windows and IANA time zones?
But the better solution would be to avoid the Windows zones all together. You can populate a list of IANA/Olson ids using the technique I describe in this post: How should I populate a list of IANA / Olson time zones from Noda Time?
Better yet, you can replace your drop-down list with a control (inline or modal) that displays a map of the world, so your users can easily select their time zone. The best control for this that I have seen is this one, but there are a few others out there also.
If you can deal strictly in IANA/Olson zones, then there's no need for conversion. You can give up the Windows TimeZoneInfo object and just use Noda Time instead. If you want, you can replace just your time zone conversion functions and leave the rest intact. Or, you could go all-out and replace all of your DateTime and DateTimeOffset uses with Noda Time types. It's up to you.

Categories