What is the timezone in which the current steps are calculated in healthKit? Is it UTC or the device timezone? What if the user changes timezones? How will it impact the healthkit data?
The startDate and endDate of HKSample objects are NSDate values, and thus contain no time zone information (see the overview of NSDate documentation for more info). Technically I wouldn't say that NSDate values are UTC dates, but you can think of them that way.
This means that, looking at just the startDate/endDate of a sample, you cannot tell what the local time was for the user when the sample was recorded. For example, if the user has moved around across time zones, you may not be able to determine whether a sample was actually recorded 11:30 pm Friday local time or 12:30 am Saturday in some other location.
There is a standard key HKMetadataKeyTimeZone that can be used to store the original time zone in sample's metadata dictionary. This would give you exactly the information you need, but you can't rely on it actually being present. Apple doesn't even populate the time zone metadata for health data recorded natively by the iPhone or Apple Watch (see this Stack Overflow post for further discussion).
I'm working on a system that will be used in a single time zone only, but integrates with other systems that exposes dates and times in UTC, so we thought that we go UTC all the way as well. We've also heard from before that storing your times in UTC is the way to go anyway, so it felt like the easiest path to minimize troubles.
Recently though, we ran into some trouble. We are logging events in the system which are of value to the user, so we let the user search and view them. Sweden is in a +1 timezone so an event at 0900 local time will be stored as 0800 UTC time. When showing the events to the user we can successfully transform them back to local time until very recently when daylight savings kicked in. Translating 0800 UTC to local time will now add 2 hours. The logged event now appears to have happened at 10:00. How should I handle this?
In this case, where the stored time is the same time as the time it was actually saved to DB, I could just look at the date and adjust it depending on if DST was on or off at that particular time. However, I think I need a generic solution for this, since there will be timestamps created at various times (at other places) in the system that need to represent future and past points in time. To me it looks like I have 2 options.
Go back to storing local times and just do some extra work when I integrate with other systems that use UTC.
Along with each UTC timestamp store some data that can tell me if a timestamp was created during DST or not.
Am I wrong? Right? Missing something?
You can always get the client timezone offset using the getTimezoneOffset method. Now all that's left is to apply this timezone offset to the UTC date stored in your database and display the correct date to the end user. If on the other hand you need to display the timezone offset used by the user when the event was recorded in your database then you definitely an additional column in your DB to record this offset. Things get tricky when you want to handle multiple timezones: what happens when you want to display a record to a user in India that was submitted by a user in Sweden?
The main thing you are missing is that you cannot just think of Sweden as a +1 time zone. A time zone and a time zone offset are two very different things. Read the timezone tag wiki for more details on this.
Instead, you can take one of the two following approaches:
Think about the time zone in terms of it's IANA tzdb identifier. For Sweden, use Europe/Stockholm. Do your conversions between UTC and local time using this time zone, using a language, library, or platform that implements the tz database.
Instead of figuring out what the client-side time zone is, rely on the client-side operating system to do the conversions to local time. Most environment (including JavaScript in a web browser) can convert from UTC to local time and vice-versa. With this approach, transmit only UTC times between the client and the server.
Also, you didn't ask in the question, but in your title you mentioned future events. That is a very different scenario, and often requires you capture the local time and IANA time zone. See this answer for more details.
You may also wish to read Daylight saving time and time zone best practices.
I am having a miserable time with dates/times in one particular app. It's an event booking app, where I don't even want to know that there is such a thing as timezones. I want one time and only one time, regardless of where the user is currently located. I don't EVER want the time converted to any other locale/timezone. There is no such thing as "local" time in this app, as everything is based on the time for the location where you booked the event. It needs to always be expressed in that time, not the time where you currently are. As such, I don't really need any timezone features.
For example, you are in New York and you book an event/appointment in London for 10:30 pm on March 15. Now, regardless of whether you are in New York, London, or any other city in the world, that event is still at 10:30 pm on March 15 in London. If you're on vacation in Los Cabos, you DO NOT want to know that your event is at 3:30 pm Los Cabos time.
Before anyone explains to me that NSDate does not contain timezone data, I am completely aware of that, and that info is useless to me. An NSDate may have no timezone info, but the dates get converted thousands of times, and every conversion takes the timezone into account, causing me great misery. I have about 30 extensions on NSDate, trying to make sure it NEVER returns a local time (try to keep everything at UTC). Thought I had it beat, but apparently the DatePicker has it's own date formatter, so all of the date pickers now screw up.
There MUST be a way to deal with this in a relatively simple way. I tried dealing with everything as UTC dates, from the remote database to the web services to everything in the iOS app, making sure that everything converted to/from strings, etc. stays in UTC format. Still not having much luck. I can create an elaborate animation in minutes, but I've been fighting with these stupid dates for weeks.
What is the best way to approach this?
Everything in one time zone (e.g. UTC)
Force app local time zone to be same for everyone?
Store time in time zone of event location, then always try to display it based on that timezone? This sounds complicated but I'm afraid it's the direction I should take, even though it's overkill.
Create date formatter and reset locale every time I touch a date?
Other?
Here's the thing. Ignore timezones except for two actions in your app:
When showing dates/times to a user.
When getting dates/times from a user.
Once you have an NSDate, forget timezones exist. Persist NSDate as-is. Do calculations with NSDate as-is. In a sense, this means everything is done in UTC time. It's all consistent. It's all uncomplicated.
You only worry about timezones when showing those dates to a user or when getting them from a user. That's it.
If you want the user's locale time, just use NSDateFormatter and its default timezone to show or get local times.
If you want to show or get times specific to an event, use an NSDateFormatter with its timezone set to the timezone of the event.
It's not any more complicated than this.
It always seems more complicated I think because people start logging NSDate and see what looks like the wrong time because they don't realize the output of the NSLog is in UTC time, not local time.
For example, you have a UIDatePicker for an event in London. Set the date picker's timezone to London time. Store the resulting NSDate. When you want to show the event's time to the user, set the timezone of the NSDateFormatter to London time. Then, no matter where the user is, it will show the proper London time.
I have to write some code working with timezones. Is there a good introduction to the subject to get me started?
Also answered at What every developer should know about time (which includes the referenced screenshots).
With daylight savings time ending today, I thought this was a good time for a post. How to handle time is one of those tricky issues where it is all too easy to get it wrong. So let's dive in. (Note: We learned these lessons when implementing the scheduling system in Windward Reports.)
First off, using UTC (also known as Greenwich Mean Time) is many times not the correct solution. Yet many programmers think if they store everything that way, then they have it covered. (This mistake is why several years ago when Congress changed the start of DST in the U.S. you had to run a hotfix on Outlook for it to adjust reoccurring events.)
So let's start with the key question – what do we mean by time? When a user says they want something to run at 7:00 am, what do they mean? In most cases they mean 7:00 am where they are located – but not always. In some cases, to accurately compare say web server statistics, they want each "day" to end at the same time, unadjusted for DST. At the other end, someone who takes medicine at certain times of the day and has that set in their calendar, will want that to always be on local time so a 3:00pm event is not 3:00am when they have travelled half way around the world.
So we have three main use cases here (there are some others, but they can generally be handled by the following):
1.The same absolute (for lack of a better word) time.
2.The time in a given time zone, shifting when DST goes on/off (including double DST which occurs in some regions).
3.The local time.
The first is trivial to handle – you set it as UTC. By doing this every day of the year will have 24 hours. (Interesting note, UTC only matches the time in Greenwich during standard time. When it is DST there, Greenwich and UTC are not identical.)
The second requires storing a time and a time zone. However, the time zone is the geographical zone, not the present offset (offset is the difference with UTC). In other words, you store "Mountain Time," not "Mountain Standard Time" or "Mountain Daylight Savings Time." So 7:00 am in "Mountain Time" will be 7:00 am in Colorado regardless of the time of year.
The third is similar to the second in that it has a time zone called "Local Time." However, it requires knowing what time zone it is in in order to determine when it occurs.
Outlook now has a means to handle this. Click the Time Zones button:
And you can now set the time zone for each event:
When I have business trips I use this including my flight times departing in one zone and arriving in another. Outlook displays everything in the local timezone and adjusts when that changes. The iPhone on the other hand has no idea this is going on and has everything off when I'm on a trip that is in another timezone (and when you live in Colorado, almost every trip is to another timezone).
Putting it to use
Ok, so how do you handle this? It's actually pretty simple. Every time needs to be stored one of two ways:
1.As UTC. Generally when stored as UTC, you will still set/display it in local time.
2.As a datetime plus a geographical timezone (which can be "local time").
Now the trick is knowing which to use. Here are some general rules. You will need to figure this out for additional use cases, but most do fall in to these categories.
1.When something happened – UTC. This is a singular event and regardless of how the user wants it displayed, when it occurred is unchangeable.
2.When the user selects a timezone of UTC – UTC.
3.An event in the future where the user wants it to occur in a timezone – datetime plus a timezone. Now it might be safe to use UTC if it will occur in the next several months (changing timezones generally have that much warning - although sometimes it's just 8 days), but at some point out you need to do this, so you should do it for all cases. In this case you display what you stored.
4.For a scheduled event, when it will next happen – UTC. This is a performance requirement where you want to be able to get all "next events" where their runtime is before now. Much faster to search against dates than recalculate each one. However, this does need to recalculate all scheduled events regularly in case the rules have changed for an event that runs every quarter.
1.For events that are on "local time" the recalculation should occur anytime the user's timezone changes. And if an event is skipped in the change, it needs to occur immediately.
.NET DateTime
Diving in to .NET, this means we need to be able to get two things which the standard library does not provide:
1.Create a DateTime in any timezone (DateTime only supports your local timezone and UTC).
2.For a given Date, Time, and geographical timezone, get the UTC time. This needs to adjust based on the DST rules for that zone on that date.
Fortunately there's a solution to this. We have open sourced out extensions to the DateTime timezone functionality. You can download WindwardTimeZone here. This uses registry settings in Windows to perform all calculations for each zone and therefore should remain up to date.
Browser pain
The one thing we have not figured out is how to know a user's location if they are using a browser to hit our web application. For most countries the locale can be used to determine the timezone – but not for the U.S. (6 zones), Canada, or Russia (11 zones). So you have to ask a user to set their timezone – and to change it when they travel. If anyone knows of a solution to this, please let me know.
Update: I received the following from Justin Bonnar (thank you):
document.getElementById('timezone_offset').value = new Date().getTimezoneOffset();
Using that plus the suggestion of the geo location for the IP address mentioned below will get you close. But it's not 100%. The time offset does not tell you if you for example if you are in Arizona (they & Hawaii do not observer daylight savings time) vs Pacific/Mountain (depending on DST) time zone. You also depend on javascript being on although that is true for 99% of the users out there today.
The geo location based on IP address is also iffy. I was at a hotel in D.C. when I got a report of our demo download form having a problem. We pre-populate the form with city, state, & country based on the geo of the IP address. It said I was in Cleveland, OH. So again, usually right but not always.
My take is we can use the offset, and for cases where there are multiple timezones with that offset (on that given day), follow up with the geo of the IP address. But I sure wish the powers that be would add a tz= to the header info sent with an HTML request.
Store everything in GMT?
Store everything the way it was entered with an embedded offset?
Do the math everytime you render?
Display relative Times "1 minutes ago"?
You have to store in UTC - if you don't, your historic reporting and behaviour during things like Daylight Savings goes... funny. GMT is a local time, subject to Daylight Savings relative to UTC (which is not).
Presentation to users in different time-zones can be a real bastard if you're storing local time. It's easy to adjust to local if your raw data is in UTC - just add your user's offset and you're done!
Joel talked about this in one of the podcasts (in a round-about way) - he said to store your data in the highest resolution possible (search for 'fidelity'), because you can always munge it when it goes out again. That's why I say store it as UTC, as local time you need to adjust for anyone who's not in that timezone, and that's a lot of hard work. And you need to store whether, for example, daylight savings was in effect when you stored the time. Yuk.
Often in databases in the past I've stored two - UTC for sorting, local time for display. That way neither the user nor the computer get confused.
Now, as to display: Sure, you can do the "3 minutes ago" thing, but only if you store UTC - otherwise, data entered in different timezones is going to do things like display as "-4 hours ago", which will freak people out. If you're going to display an actual time, people love to have it in their local time - and if data's being entered in multiple timezones you can only do that with ease if you're storing UTC.
The answer, as always, is "depends".
It depends on what you are describing with the time, and how the data was provided to you.
The key to deciding how to store time values is deciding if you are losing information by dropping the timezone, as well as not surprising your users.
There are definite benefits in storing data in a UTC time_t - it is a single int, allowing quick sorting and easy storage.
I see the problem as being broken down into specific areas:
Historical Data
Future, Short Term Data
Future, Long Term Data
With the following subclasses on each:
System Provided
User Provided
Let's look at them one at a time.
System Provided: I would recommend running systems in UTC, then you avoid the timezone problem and again, no information loss is seen (it's always UTC).
Historical Data: These are things like system log files, process statistics, tracing, comment dates/times, etc. The data isn't going to change, and the timezone descriptor isn't going to change retroactively. For this type of data, there is no information lost by storing the information in UTC regardless of the timezone it was provided in. So, drop the timezone.
Future, Long Term Data: These are events that are either far enough in the future or will keep happening. If they are kept around long enough, the timezone descriptors are guaranteed change. A good example of this type of data is, "The Weekly Management Meeting". This is data that is entered once, and expected to keep working into perpetuity. For these values, it is important to determine if it is system or user provided. For user-provided data, the time should be stored with the creator's timezone, anything else results in information loss. This information loss becomes apparent when the timezone definition changes and the time is displayed to the creator as having an entirely different value!
As Bwooce has indicated, there is some confusion where the creator and viewer are in different timezones. In that case, I would expect the application to indicate which time values have moved due to a timezone shift from their previous locations.
Future, Short Term Data: This is data that is quickly going to become historical, or is only valid for a short period of time. Examples could be interval timers, rating transitions, etc. For this data, since the likelihood is low that the definition will change between the creation of the value and the time it becomes historical, it might be possible to get away with dropping the timezone. However, I have found that these values have a bad habit of becoming "Future, Long Term Data".
Once you have decided to store the timezone, care must be taken with how it is stored.
Don't store the timezone as an offset, or the full descriptor.
If you store a timezone as an offset, what do you do if the timezone changes? Do you go through the system and do a blanket change on the existing data? If you do, you've now made any historical values incorrect. Good examples of this fault are Oracle and iCal. Oracle stores timezone information as an offset from UTC, and iCal includes the full descriptor for the creation timezone.
Do store it as a name.
This allows the definition of the timezone to change without having to modify the existing values you have. It does make sorting more difficult, since any index that is generated may be invalid if the timezone data changes.
If developers continue to store everything in UTC, irrespective of timezone, we will continue to see the problems that we've seen with the last batch of timezone changes.
At one organisation, the secretaries had to print out the calendars for their teams before the daylight savings date, and then print them out again after the change. Finally, they compared the two and re-created all of the appointments that had moved. Of course, they missed several, and there were several weeks of pain until the old daylight savings date was reached and the times became correct again.
Josh is completely correct above, but I have one subtle caveat to explain. This is a case with no correct answer regarding future events and timezones.
Consider the case of a repeating appointment. It occurs at GMT 0000 (for simplicity), which is 1200 NZST (New Zealand Standard Time) and 1000 AEST in Sydney Australia.
When Daylight Savings comes into effect in one zone, what should occur to the appointment? Should it:
1a. If the TZ change is in the zone of
the appointment's "owner" (who
booked it) then attempt to remain at
the same desk clock time (eg 10:00am)?
1b. If the
TZ change is in one of the other
meeting attendee's zones then no
change
Consequences: It moves for
everyone else, unexpectedly, due to
the owners TZ change, but it stays
"the 10am meeting" as far as the
owner is concerned.
'2. As above, but reversed.
Consequences: It moves for the meeting owner (the 10am meeting becomes the 9am meeting, or v/v), which may be expected but inconvenient. It stays at the same desk clock time for the other attendees until they go through their own TZ transition.
Neither is perfect. Consider the case of two appointments, one booked by Person A that occurs at 10am local time, the other booked by Person B with Person A as an attendee that occurs at 9am. If Person A and Person B are in different TZ's then a DST change could easily cause them to become double-booked.
If your mind is a bit bent at this point then I quite understand.
The point behind this example is that to do either of these behaviors properly you need to know not just the UTC version of the local time, but the TZ (and not the offset) that the owner was in when they booked it. Otherwise you have no choice but to take option 2, silently, without even informing anyone that things have changed since GMT times don't change and only the presentation changes...right? (no, this is the trap, presentation matters when your 10am meeting moves by itself)
I have to credit my colleague and friend Jason Pollock for this insight. Read his view here, and the follow-up discussing iCal and VTIMEZONE here.
Storing everything in GMT/UTC seems most logical to me. You can then show the date and time in every timezone you want.
A few ceveats:
If a time is only specified as a
wall clock time and that is the
leading representation, then it is
not an absolutely specified time.
You should (and cannot) convert it
in any GMT representation. E.G. 9:00
AM every morning. In other words:
this is no (date)time.
If you
save a date and time of a future
appointment, you should use the
offset to GMT specified by the input
timezone and the the moment in time
itself. So if it is an appointment
in summer made in winter in e.g.
western europe, it is +2:00,
allthough the normal (winter time)
offset is +1:00. This will solve the
calender problem that Bwooce
mentioned.
Of course, the same
that applies to using the right
offset while converting to GMT
applies when converting back to a
date and time in any particular
timezone.
Luckily, when used correctly, the (.NET) DateTime type takes care of all the gory details of keeping calendars etc. for you and all of this should be very easy when you know how it works.
Personally, I can't see any reason not to store everything in GMT and then use the users local timezone to display the time as it relates to them.
If you want to display relative time, you obviously still need the time and do a translation, but if you do want to do the translation I think GMT is still your best option.
So I ran a little experiment with MSSQL server.
I created a table and added a row with the current localized timezone (Australia).
Then I changed my datetime to be GMT and added another row.
Even tho those rows were added around 10 seconds apart, they appear in SQL server as tho they're 10 hours apart.
If nothing else, it at least tells me that I should be storing dates in a conisitent manner, which for me, adds weight to the argument for storing them as GMT.
MS Dynamics stores GMT and then at a user level knows your times zone relative to GMT. Then it displays items to you in your time zone.
Just thought I'd throw that out there as that's a pretty big group at MS and this is how they decided to handle it.
i prefer to store everything with the timezone.
the client can decide, which way it should be presented later.
my favorite library for converting is the PostgreSQL-Database.
Have a look here, the w3c have done an excellent job answering the question.
Look at the use cases.
http://www.w3.org/TR/timezone/
Note that they recommend storing datetimes as UTC not GMT, GMT is subject to daylight savings time.
I like storing in GMT and showing only relative ("about 10 seconds ago", "5 months ago"). Users don't need to see actual timestamps for most use cases.
There are certainly exceptions, and an individual application might have many of them, so it can't be a 'one-true-way' answer. Things that need strong audit-ability (e.g. voting), and systems where time is part of the domain of discourse (astronomy, scientific research) might demand true timestamps to be shown to the user.
Most apps, though, are easier to understand with a simple relative time.
I usually just use Unix time. not necessarily future safe, but it works pretty well.
Always store in GMT (or UTC). From there it is easy to convert to any local time zone value.
Dates should be stored as UTC UNLESS it is user provided data and you CANNOT know what timezone the user intended that data to be in. Sometimes (very very rarely) you need to just store the hour, minute, second, day, month and year components without any timezone so you can spit it out back to the user. Now for new developers or if you're unsure, store UTC and you will be 99% correct.
But don't be fooled by believing this works 100% of the time for all cases all the time. It does not.