How would I add support for timezone in my application? - timezone

We're currently storing local datetime of Pacific/Hawaii in the database. Assuming that I cannot change these dates to UTC, what information do I need to add to support timezone?
My thoughts are:
First, add a timezone field to indicate which timezone the user is viewing from. (The user will select this from a dropdown)
Second, add timezone field to indicate the timezone (Pacific/Hawaii) of the current datetimes values in the database.
Third, add offset to cover DST hours
So say a user from America/Los_Angeles views the site, it would pull the datetime from the database, append the offset and apply the timezone of Hawaii before converting it to Los Angeles time. For any calculation or comparison I would convert the Hawaii time to UTC first, then convert the UTC result to Los Angeles. Am I missing anything?

Your question is very broad, and without knowing more about your application, the platform, how you use collect dates and times, what they represent, etc., I can only speak in generalities.
Storing in UTC is recommended, but that is just by convention. The main necessities are that the time zone you are storing data in does not have DST (which Hawaii hasn't since 1947), and that you do not rely on your computer's operating system or environment settings to determine what time zone to use. You can use the Hawaiian time zone if you must. Be sure you document it somewhere though! It will surely be a surprise to anyone else that comes along in the lifecycle of the application.
While it would wolk, there is absolutely no advantage to doing this. You could just as easily convert your data to UTC when you roll out these changes and use UTC going forward. (That would be the preferred approach.)
The IANA time zone ID for Hawaii is "Pacific/Honolulu". If you're on Windows/.Net, the TimeZoneInfo ID is "Hawaiian Standard Time". Either way, they must be spelled, cased, and punctuated in exactly that manner.
Make sure you understand that a Time Zone Offset and a Time Zone are two different concepts. While Hawaii may use a fixed offset of -10:00, that's not guaranteed for most time zones. Please read the timezone tag wiki for further details.
You should probably not attempt to implement your own time zone logic. There are libraries for this in almost every language. Look to see what is appropriate for your platform. (If you provide details, I can offer suggestions.)

It would be a more robust solution to store the times as UTC time as time zone is local to the specific PC that is displaying the data. In your case if you store time plus offset how can you decide which offset to store? Not a workable solution if multiple time zones are involved.

Related

Rails, Moment, and Timezones (abbreviations + offsets)

I am creating a Rails API that will be consumed by a Javascript framework. Time display and manipulation will be controlled with MomentJS. It is important for the front-end to be able to display the dates along with the time zone abbreviations (e.g. 1/1/2010 11:00 PST).
From what I understand, an offset (e.g. -0700) is not enough to determine the actual timezone, and the timezone abbreviations aren't always unique.
I can think of only two options to solve this:
Return all times in UTC and have an extra field for each time specifying the timezone (e.g. { pick_up: "17-06-08T18:59:21.215Z", pick_up_tz: 'America/New_York' } (or pick_up_tz: 'PST')
Use a non-standard datetime format, something that includes both the timezone abbreviation and the offset (e.g. { pick_up: "17/09/06 13:34:00 CDT -05:00")
Are these reasonable solutions or is there a better way?
Use a non-standard datetime format
Never do this. An API should always return time in ISO 8601.
Return all times in UTC and have an extra field for each time specifying the timezone
You are correct that an offset is insufficient to identify time zone, so you do need to include that in the API response, ideally as an IANA time zone.
Whether you convert to UTC or include an offset is a matter of preference; 2017-06-08T18:59:21.215Z and 2017-06-08T11:59:21.215-0700 mean the same time, regardless of the time zone you convert to for display. Including the offset can be useful to identify if the stored offset is different from the time zone, as you might only show the time zone qualifier if the offset is different.

timeZone in checkin

Looking at the docs there is a descrepancy between the data in a checkin object for the query API s the push API with regards to timeZone.
According to https://developer.foursquare.com/overview/realtime a sample push will contain the name of the tz eg America/New_York
However according to https://developer.foursquare.com/docs/responses/checkin (and the API explorer) a checkin object will contain the timeZone offset eg 60 for GMT+1
I havn't managed to confirm whats in the Push API myself yet as I hav to setup the SSL certs, can anyone confirm of the docs are correct and we do indeed have 2 type of tz format. I would have thought that including the timeZone rather than the offset would be better as this doesn't vary with Daylight Savings unlike the figure. Europe/London will always be a constant where as the offset will switch between 0 and 60 mins
I'm not directly familiar with FourSquare's API, so I can't confirm or deny this for you. But I can tell you there are often cases where you would use both.
It is ok to only present an offset, if the data represents a particular time. Since the checkin response provides a createdAt date/time as an integer seconds since epoch (aka a "Unix Timestamp"), then it is appropriate to provide a separate offset. (Although I find it interesting that they provide the offset as a string and not as an integer number of minutes.) The other way you might do this would be with a single DateTimeOffset values, usually presented in ISO8601 format, as in 2013-06-02T01:23:45-07:00. Either are acceptable.
But as you may be aware, an offset does not uniquely identify a time zone. In the case of a single event, it doesn't need to. But if it were a recurring event, or if there was a possibility that you might want to modify the time value, then an offset alone would not suffice. That's when you need the full zone identifier.
If you have a zone identifier such as America/New_York, then you can always find out what the correct offset for any date/time would be. But not everyone has a TZDB implementation readily available. For example, in .Net on Windows, you get Microsoft's clumsy time zone database by default, and you have to find a library (like NodaTime) if you want to use the TZDB zones.
It does seem strange that the push and pull for the same type of action (a check-in) would have different values just because they were going through different APIs. My advice (to Foursquare) would be threefold:
Be consistent about the data for the same activity, regardless of push vs pull.
Provide both the TZDB identifier, and the the UTC offset associated with the event.
Provide the event's timestamp and offset in a single value, as an ISO8601 formatted string, rather than a unix time integer.
The Foursquare documentation is correct but a bit incomplete (as of time of posting). The check-in response contains a timeZoneOffset field. The real-time push response has a timeZone field and a timeZoneOffset field—the timeZone field is still there for legacy purposes.
Thanks for pointing this out; we'll update the docs to reflect that timeZoneOffset is the preferred method at this point. As Matt mentioned, the offset method is a better way to identify a particular time from createdAt.

Is timezone just an offset number or "more information"?

I live in a country where they change the time twice a year. That is: there is a period in the year when the offset from UTC is -3 hours (-180 mins) and other period where the offset is -4 hours (-240 mins)
Grafically:
|------- (offset = -3) -------|------- (offset is -4) -------|
start of year mid end of year
My question is:
the "timezone" is just the number representing the offset? that is: my country has two timezones? or the timezone includes this information?
This is important because I save every date in UTC timezone (offset = 0) in my database.
Should I, instead, be saving the dates with local timezone and saving their offset (at the moment of saving) too?
Here is an example of a problem I see by saving the dates with timezone UTC:
Lets say I have a system where people send messages.
I want to have a statistics section where I plot "messages sent v/s hour" (ie: "Messages sent by hour in a regular day")
Lets say there are just two messages in the whole database:
Message 1, sent in march 1, at UTC time 5 pm (local time 2 pm)
Message 2, sent in august 1, at UTC time 5 pm (local time 1 pm)
Then, if I create the plot on august 2, converting those UTC dates to local would give me: "2 messages where sent at 1 pm", which is erratic information!
From the timezone tag wiki here on StackOverflow:
TimeZone != Offset
A time zone can not be represented solely by an offset from UTC. Many
time zones have more than one offset due to "daylight savings time" or
"summer time" rules. The dates that offsets change are also part of
the rules for the time zone, as are any historical offset changes.
Many software programs, libraries, and web services disregard this
important detail, and erroneously call the standard or current offset
the "zone". This can lead to confusion, and misuse of the data. Please
use the correct terminology whenever possible.
There are two commonly used database, the Microsoft Windows time zone db, and the IANA/Olson time zone db. See the wiki for more detail.
Your specific questions:
the "timezone" is just the number representing the offset? that is: my country has two timezones? or the timezone includes this information?
You have one "time zone". It includes two "offsets".
Should I, instead, be saving the dates with local timezone and saving their offset (at the moment of saving) too?
If you are recording the precise moment an event occurred or will occur, then you should store the offset of that particular time with it. In .Net and SQL Server, this is represented using a DateTimeOffset. There are similar datatypes in other platforms. It only contains the offset information - not the time zone that the offset originated from. Commonly, it is serialized in ISO8601 format, such as:
2013-05-09T13:29:00-04:00
If you might need to edit that time, then you cannot just store the offset. Somewhere in your system, you also need to have the time zone identifier. Otherwise, you have no way to determine what the new offset should be after the edit is made. If you desire, you can store this with the value itself. Some platforms have objects for exactly this purpose - such as ZonedDateTime in NodaTime. Example:
2013-05-09T13:29:00-04:00 America/New_York
Even when storing the zone id, you still need to record the offset. This is to resolve ambiguity during a "fall-back" transition from a daylight offset to a standard offset.
Alternatively, you could store the time at UTC with the time zone name:
2013-05-09T17:29:00Z America/New_York
This would work just as well, but you'd have to apply the time zone before displaying the value to anyone. TIMESTAMP WITH TIME ZONE in Oracle and PostgreSQL work this way.
You can read more about this in this post, while .Net focused - the idea is applicable to other platforms as well. The example problem you gave is what I call "maintaining the perspective of the observer" - which is discussed in the same article.
that is: my country has two timezones? or the timezone includes this information?
The term "timezone" usually includes that information. For example, in Java, "TimeZone represents a time zone offset, and also figures out daylight savings" (link), and on Unix-like systems, the tz database contains DST information.
However, for a single timestamp, I think it's more common to give just a UTC offset than a complete time-zone identifier.
[…] in my database.
Naturally, you should consult your database's documentation, or at least indicate what database you're using, and what tools (e.g., what drivers, what languages) you're using to access it.
Here's an example of a very popular format for describing timezones (though not what Windows uses).
You can see that it's more than a simple offset. More along the lines of offsets and the set of rules (changing over time) for when to use which offset.

How to get the timezone name from numeric timezone value in Android

I am basically trying to read a .vcs file in Android. It has timezone value in the below format:
TZ:+05:30
Now I want to get the timezone name corresponding to this value. Means in this case it would be Kolkata(India).
Is there any code to achieve this in android?
TimeZone tz = TimeZone.getTimeZone("GMT-06:00");
String tzarr[] = TimeZone.getAvailableIDs(tz.getRawOffset());
for(int i=0;i<tzarr.length;i++)
(I'm assuming you can parse the text into an offset easily enough.)
In general, you can't. Something like "+05:30" just represents an offset from UTC at one particular time. It doesn't express how the offset changes within the time zone across the year (or across history). For example, for some of the time the Europe/London time zone has the same offset as Africa/Casablanca - but not always.
Assuming this is associated with a specific date/time, you could use TimeZone.getAvailableIDs, iterate over all the time zones, check what the offset from UTC is at that particular instant (using TimeZone.getOffset(long)) and see which time zones have the right offset at the right time. There could be many such zones though.
If you don't have a specific date/time, it's even more ambiguous. You can use getRawOffset and getDSTSavings to see whether the target offset is either the standard or DST offset for any particular zone - although note that these calls assume that for a particular time zone, the DST offset and standard offset remain the same across history (which isn't always true).

How is the result of the Delphi NOW function affected by the option to "Adjust clock for daylight saving changes"

I realise this question could have been answered by writing some test code. I'm not lazy, I just thought that the answer might be generally useful.
I have an app that has generated a large amount of data with records that were stamped with the local time (as returned by the NOW routine). We have run into a snag with transitions in and out of daylight savings time - namely that there is an hour missing when we change to DST, and an hour repeated when we exit from DST. This causes problems with manipulations that assume date ordered records.
The app has been altered therefore to work with all datetimes in UTC, but I will have the ability to display datetimes in UTC or in local time. I also have to deal with datetimes that were stored in local time, and make sure they are correctly shifted to UTC. This is tricky, as the datetime might have been stored while DST was in effect, so in the general case I need to be able to determine if any random date is within or outside a DST period. There is of course a period of one hour where a datetime is ambiguous and could be in the last hour before daylight savings ended, or in the first hour after it ended. There is no way of resolving this.
In coding the changes, I wondered about the result of NOW calls. Internally it calls GetLocalTime. What does GetLocalTime (and NOW) return when you are inside a DST period, but the option to "Adjust clock for daylight saving changes" is turned off?
How do I write a routine that returns the current datetime inside a DST period (with the DST bias applied) regardless of whether "Adjust clock for daylight saving changes" is off or on?
I don't think you can solve your problem easily.
There are too many variables:
the stored timestamp
the time zone you are in
the ever changing time zone rules
confirmation that these time zone rules are accurate on all the equipment you use (i.e. everyone always applied their patches)
the inaccuracy of your clock
There is a Delphi TZDB project that can help you with the time zone rules.
I think it is much more practical to not rely on all the above variables, but store three fields:
the timestamp in your local format
the current timezone
the timestamp in UTC format
You perform the sorting on the third field, and the first two fields for displaying.
--jeroen
Use TzSpecificLocalTimeToSystemTime (and its obvious inverse). These allow you to convert between UTC and local date/time based on the daylight savings settings in effect at the local date/time. If you want your app to run on anything earlier than XP, load this (from kernel32) with the 'delayed' function attribute:
function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation;
var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall;
function TzSpecificLocalTimeToSystemTime; external kernel32 name 'TzSpecificLocalTimeToSystemTime' delayed;

Resources