Handling timezones and dates - php

I am having an issue getting my head around storing and retrieving information based on a date (no time) and dealing with multiple timezones.
By default my application uses UTC, so create/update times are all in UTC and PHP functions such as date etc all use UTC.
My problem is this:
I allow users to create a news item, the news item has a date (no time, just date).
The application uses UTC, my user is in Sydney, so what I do is when the form loads I pre-populate the date field based of jS M Y for the Australia/Sydney timezone, this way it shows as today for him. All good so far.
When I save the record into the database (into a DATE field) I use the date they entered so if they said 3rd March 2016, then it goes in as 2016-03-03.
When it gets pulled out again it displays fine for them, but if I do a report saying "How many news items published today?", in my report (cron job) it might be looking for a different date, because if this person entered it in early morning, then 3rd March 2016 for Sydney is still going to be 2nd March 2016 in UTC so there will be 0 for today.
The solution it appears would be to convert the date back to UTC when you store it, but how will that work?.. Since it's just a date with no time.
2nd March 2016 00:00:00 UTC would be 2nd March 2016 10:00:00 Sydney
So.. I am not sure how to solve this without them having to also enter a time, which seems redundant.

Always remember that savings time rules vary between countries, such as the USA and EU. Not just when the clocks change but timings of changes across time zones.
In the past I forced a local hour of 12:00 (noon). With a time value the standard conversion routines be used. Choosing noon kept everything well away from any midnight and savings time issues as an hour slip either way would still be in the same day.

The simplest way is to ALWAYS work with full UTC timestamps under the hood.
Convert incoming dates to these straight away, and only convert back to readable, localized formats when rendering.
This way you have a single, solid, point of reference. Everything in your database has logged exactly when it was created (relative to the 1st of January 1970 - UTC).
Then it becomes trivial to order articles in order of creation (regardless of where their authors posted from). It's also much easier to count how many articles were added in the last 24 hours, or on a specific day (for example; seven days ago) -- notice how these examples don't require a date, just ranges of seconds.
This also makes it easy to show "user A" when "user B" added an article, relative to user A's timezone -- you don't need to look up user B's timezone to do the conversion.
Also, give your user the option to add a time to their articles, but don't make it mandatory. Have a sensible default (ideally a dynamic "now"). This is more natural, and should smooth out the midnight and DST anomalies highlighted by Gilbert, when building reports.

It actually sounds like you are doing things correctly already.
The concepts of "today" and a "date" are calendering concepts, covered by the domain of civil time. You can fly around the world with a printed calendar, and you don't need to adjust it for UTC or time zones. A date itself can't be "in UTC".
However, you can say that in the domain of absolute time, that a date in time zone A does not cover the same instantaneous moments of time that are covered by time zone B. At any given time, there could be two different "todays" in effect on the Earth.
By the perspective of your Sydney user, March 3rd was the publishing date. You might have another user in Hawaii publishing simultaneously at March 2nd.
Inherently then, your posting date is the civil date that the item was posted. When you query for all items posted "today", that is based on the civil date of wherever you're at when you're asking.
If this isn't the desired behavior, then change the question. Instead of asking "what was posted today", ask "what was posted in the last 24 hours?" For that, you would indeed need to store the full UTC-based date and time (not just date) of the post. Then you would query it by UTC time from now less 24 hours.
A thought exercise that will help: What should you do if a user posts at 23:59 UTC, and you run a query one minute later? Should it include the result - or not? Does your answer change if it's 23:59 local time and you run the query one minute later in the same time zone? Thinking this through will help you decide what you should actually be storing and querying.
I'll also say that in most cases you should indeed store a UTC based timestamp, but you may want to also store the local date (or datetime) in a separate field. This gives you the ability to do both types of queries.

Related

PHP / Carbon timezone convert getting 1 hour wrong when converting future date time, why? [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I am hoping to make this question and the answers to it the definitive guide to dealing with daylight saving time, in particular for dealing with the actual change overs.
If you have anything to add, please do
Many systems are dependent on keeping accurate time, the problem is with changes to time due to daylight savings - moving the clock forward or backwards.
For instance, one has business rules in an order taking system that depend on the time of the order - if the clock changes, the rules might not be as clear. How should the time of the order be persisted? There are of course an endless number of scenarios - this one is simply an illustrative one.
How have you dealt with the daylight saving issue?
What assumptions are part of your solution? (looking for context here)
As important, if not more so:
What did you try that did not work?
Why did it not work?
I would be interested in programming, OS, data persistence and other pertinent aspects of the issue.
General answers are great, but I would also like to see details especially if they are only available on one platform.
Summary of answers and other data: (please add yours)
Do:
Whenever you are referring to an exact moment in time, persist the time according to a unified standard that is not affected by daylight savings. (GMT and UTC are equivalent with this regard, but it is preferred to use the term UTC. Notice that UTC is also known as Zulu or Z time.)
If instead you choose to persist a (past) time using a local time value, include the local time offset for this particular time from UTC (this offset may change throughout the year), such that the timestamp can later be interpreted unambiguously.
In some cases, you may need to store both the UTC time and the equivalent local time. Often this is done with two separate fields, but some platforms support a datetimeoffset type that can store both in a single field.
When storing timestamps as a numeric value, use Unix time - which is the number of whole seconds since 1970-01-01T00:00:00Z (excluding leap seconds). If you require higher precision, use milliseconds instead. This value should always be based on UTC, without any time zone adjustment.
If you might later need to modify the timestamp, include the original time zone ID so you can determine if the offset may have changed from the original value recorded.
When scheduling future events, usually local time is preferred instead of UTC, as it is common for the offset to change. See answer, and blog post.
When storing whole dates, such as birthdays and anniversaries, do not convert to UTC or any other time zone.
When possible, store in a date-only data type that does not include a time of day.
If such a type is not available, be sure to always ignore the time-of-day when interpreting the value. If you cannot be assured that the time-of-day will be ignored, choose 12:00 Noon, rather than 00:00 Midnight as a more safe representative time on that day.
Remember that time zone offsets are not always an integer number of hours (for example, Indian Standard Time is UTC+05:30, and Nepal uses UTC+05:45).
If using Java, use java.time for Java 8 and later.
Much of that java.time functionality is back-ported to Java 6 & 7 in the ThreeTen-Backport library.
Further adapted for early Android (< 26) in the ThreeTenABP library.
These projects officially supplant the venerable Joda-Time, now in maintenance-mode. Joda-Time, ThreeTen-Backport, ThreeTen-Extra, java.time classes, and JSR 310 are led by the same man, Stephen Colebourne.
If using .NET, consider using Noda Time.
If using .NET without Noda Time, consider that DateTimeOffset is often a better choice than DateTime.
If using Perl, use DateTime.
If using Python 3.9 or later, use the built-in zoneinfo for working with time zones. Otherwise, use dateutil or arrow. The older pytz library can generally be avoided.
If using JavaScript, avoid using the older moment.js or moment-timezone libraries, as they are no longer actively maintained. See the Moment.js project status for more details. Instead, consider Luxon, date-fns, day.js, or js-joda.
If using PHP > 5.2, use the native time zones conversions provided by DateTime, and DateTimeZone classes. Be careful when using DateTimeZone::listAbbreviations() - see answer. To keep PHP with up to date Olson data, install periodically the timezonedb PECL package; see answer.
If using C++, be sure to use a library that uses the properly implements the IANA timezone database. These include cctz, ICU, and Howard Hinnant's "tz" library. In C++20 the latter is adopted into the standard <chrono> library.
Do not use Boost for time zone conversions. While its API claims to support standard IANA (aka "zoneinfo") identifiers, it crudely maps them to POSIX-style data, without considering the rich history of changes each zone may have had. (Also, the file has fallen out of maintenance.)
If using Rust, use chrono.
Most business rules use civil time, rather than UTC or GMT. Therefore, plan to convert UTC timestamps to a local time zone before applying application logic.
Remember that time zones and offsets are not fixed and may change. For instance, historically US and UK used the same dates to 'spring forward' and 'fall back'. However, in 2007 the US changed the dates that the clocks get changed on. This now means that for 48 weeks of the year the difference between London time and New York time is 5 hours and for 4 weeks (3 in the spring, 1 in the autumn) it is 4 hours. Be aware of items like this in any calculations that involve multiple zones.
Consider the type of time (actual event time, broadcast time, relative time, historical time, recurring time) what elements (timestamp, time zone offset and time zone name) you need to store for correct retrieval - see "Types of Time" in this answer.
Keep your OS, database and application tzdata files in sync, between themselves and the rest of the world.
On servers, set hardware clocks and OS clocks to UTC rather than a local time zone.
Regardless of the previous bullet point, server-side code, including web sites, should never expect the local time zone of the server to be anything in particular. see answer.
Prefer working with time zones on a case-by-case basis in your application code, rather than globally through config file settings or defaults.
Use NTP services on all servers.
If using FAT32, remember that timestamps are stored in local time, not UTC.
When dealing with recurring events (weekly TV show, for example), remember that the time changes with DST and will be different across time zones.
Always query date-time values as lower-bound inclusive, upper-bound exclusive (>=, <).
Don't:
Do not confuse a "time zone", such as America/New_York with a "time zone offset", such as -05:00. They are two different things. See the timezone tag wiki.
Do not use JavaScript's Date object to perform date and time calculations in older web browsers, as ECMAScript 5.1 and lower has a design flaw that may use daylight saving time incorrectly. (This was fixed in ECMAScript 6 / 2015).
Never trust the client's clock. It may very well be incorrect.
Don't tell people to "always use UTC everywhere". This widespread advice is shortsighted of several valid scenarios that are described earlier in this document. Instead, use the appropriate time reference for the data you are working with. (Timestamping can use UTC, but future time scheduling and date-only values should not.)
Testing:
When testing, make sure you test countries in the Western, Eastern, Northern and Southern hemispheres (in fact in each quarter of the globe, so 4 regions), with both DST in progress and not (gives 8), and a country that does not use DST (another 4 to cover all regions, making 12 in total).
Test transition of DST, i.e. when you are currently in summer time, select a time value from winter.
Test boundary cases, such as a timezone that is UTC+12, with DST, making the local time UTC+13 in summer and even places that are UTC+13 in winter
Test all third-party libraries and applications and make sure they handle time zone data correctly.
Test half-hour time zones, at least.
Reference:
The detailed timezone tag wiki page on Stack Overflow
Olson database, aka Tz_database
IETF draft procedures for maintaining the Olson database
Sources for Time Zone and DST
ISO format (ISO 8601)
Mapping between Olson database and Windows Time Zone Ids, from the Unicode Consortium
Time Zone page on Wikipedia
StackOverflow questions tagged dst
StackOverflow questions tagged timezone
Dealing with DST - Microsoft DateTime best practices
Network Time Protocol on Wikipedia
Other:
Lobby your representative to end the abomination that is DST. We can always hope...
Lobby for Earth Standard Time
I'm not sure what I can add to the answers above, but here are a few points from me:
Types of times
There are four different times you should consider:
Event time: eg, the time when an international sporting event happens, or a coronation/death/etc. This is dependent on the timezone of the event and not of the viewer.
Television time: eg, a particular TV show is broadcast at 9pm local time all around the world. Important when thinking about publishing the results (of say American Idol) on your website
Relative time: eg: This question has an open bounty closing in 21 hours. This is easy to display
Recurring time: eg: A TV show is on every Monday at 9pm, even when DST changes.
There is also Historic/alternate time. These are annoying because they may not map back to standard time. Eg: Julian dates, dates according to a Lunar calendar on Saturn, The Klingon calendar.
Storing start/end timestamps in UTC works well. For 1, you need an event timezone name + offset stored along with the event. For 2, you need a local time identifier stored with each region and a local timezone name + offset stored for every viewer (it's possible to derive this from the IP if you're in a crunch). For 3, store in UTC seconds and no need for timezones. 4 is a special case of 1 or 2 depending on whether it's a global or a local event, but you also need to store a created at timestamp so you can tell if a timezone definition changed before or after this event was created. This is necessary if you need to show historic data.
Storing times
Always store time in UTC
Convert to local time on display (local being defined by the user looking at the data)
When storing a timezone, you need the name, timestamp and the offset. This is required because governments sometimes change the meanings of their timezones (eg: the US govt changed DST dates), and your application needs to handle things gracefully... eg: The exact timestamp when episodes of LOST showed both before and after DST rules changed.
Offsets and names
An example of the above would be:
The soccer world cup finals game
happened in South Africa (UTC+2--SAST)
on July 11, 2010 at 19:00 UTC.
With this information, we can historically determine the exact time when the 2010 WCS finals took place even if the South African timezone definition changes, and be able to display that to viewers in their local timezone at the time when they query the database.
System Time
You also need to keep your OS, database and application tzdata files in sync, both with each other, and with the rest of the world, and test extensively when you upgrade. It's not unheard of that a third party app that you depend on did not handle a TZ change correctly.
Make sure hardware clocks are set to UTC, and if you're running servers around the world, make sure their OSes are configured to use UTC as well. This becomes apparent when you need to copy hourly rotated apache log files from servers in multiple timezones. Sorting them by filename only works if all files are named with the same timezone. It also means that you don't have to do date math in your head when you ssh from one box to another and need to compare timestamps.
Also, run ntpd on all boxes.
Clients
Never trust the timestamp you get from a client machine as valid. For example, the Date: HTTP headers, or a javascript Date.getTime() call. These are fine when used as opaque identifiers, or when doing date math during a single session on the same client, but don't try to cross-reference these values with something you have on the server. Your clients don't run NTP, and may not necessarily have a working battery for their BIOS clock.
Trivia
Finally, governments will sometimes do very weird things:
Standard time in the Netherlands was
exactly 19 minutes and 32.13 seconds
ahead of UTC by law from 1909-05-01
through 1937-06-30. This time zone
cannot be represented exactly using
the HH:MM format.
Ok, I think I'm done.
This is an important and surprisingly tough issue. The truth is that there is no completely satisfying standard for persisting time. For example, the SQL standard and the ISO format (ISO 8601) are clearly not enough.
From the conceptual point of view, one usually deals with two types of time-date data, and it's convenient to distinguish them (the above standards do not) : "physical time" and "civil time".
A "physical" instant of time is a point in the continuous universal timeline that physics deal with (ignoring relativity, of course). This concept can be adequately coded-persisted in UTC, for example (if you can ignore leap seconds).
A "civil" time is a datetime specification that follows civil norms: a point of time here is fully specified by a set of datetime fields (Y,M,D,H,MM,S,FS) plus a TZ (timezone specification) (also a "calendar", actually; but lets assume we restrict the discussion to Gregorian calendar). A timezone and a calendar jointly allow (in principle) to map from one representation to another. But civil and physical time instants are fundamentally different types of magnitudes, and they should be kept conceptually separated and treated differently (an analogy: arrays of bytes and character strings).
The issue is confusing because we speak of these types events interchangeably, and because the civil times are subject to political changes. The problem (and the need to distinguish these concepts) becomes more evident for events in the future. Example (taken from my discussion here.
John records in his calendar a reminder for some event at datetime
2019-Jul-27, 10:30:00, TZ=Chile/Santiago, (which has offset GMT-4,
hence it corresponds to UTC 2019-Jul-27 14:30:00). But some day
in the future, the country decides to change the TZ offset to GMT-5.
Now, when the day comes... should that reminder trigger at
A) 2019-Jul-27 10:30:00 Chile/Santiago = UTC time 2019-Jul-27 15:30:00 ?
or
B) 2019-Jul-27 9:30:00 Chile/Santiago = UTC time 2019-Jul-27 14:30:00 ?
There is no correct answer, unless one knows what John conceptually meant
when he told the calendar "Please ring me at 2019-Jul-27, 10:30:00
TZ=Chile/Santiago".
Did he mean a "civil date-time" ("when the clocks in my city tell
10:30")? In that case, A) is the correct answer.
Or did he mean a "physical instant of time", a point in the continuus
line of time of our universe, say, "when the next solar eclipse
happens". In that case, answer B) is the correct one.
A few Date/Time APIs get this distinction right: among them, Jodatime, which is the foundation of the next (third!) Java DateTime API (JSR 310).
Make clear architectural separation of concerns - to know exactly which tier interacts with users, and has to change date-time for/from canonical representation (UTC). Non-UTC date-time is presentation (follows users local timezone), UTC time is model (remains unique for back-end and mid tiers).
Also, decide what's your actual audience, what you don't have to serve and where do you draw the line. Don't touch exotic calendars unless you actually have important customers there and then consider separate user-facing server(s) just for that region.
If you can acquire and maintain user's location, use location for systematic date-time conversion (say .NET culture or a SQL table) but provide a way for end-user to choose overrides if date-time is critical for your users.
If there are historical audit obligations involved (like telling exactly when Jo in AZ paid a bill 2 yrs ago in September) then keep both UTC and local time for the record (your conversion tables will change in a course of time).
Define the time referential time zone for data that comes in bulk - like files, web services etc. Say East Coast company has data center in CA - you need to ask and know what they use as a standard instead of assuming one or the other.
Don't trust time-zone offsets embedded in textual representation of the date-time and don't accept to parse and follow them. Instead always request that time zone and/or reference zone have to be explicitly defined. You can easily receive time with PST offset but the time is actually EST since that's the client's reference time and records were just exported at a server which is in PST.
You need to know about the Olson tz database, which is available from ftp://elsie.nci.nih.gov/pub http://iana.org/time-zones/. It is updated multiple times per year to deal with the often last-minute changes in when (and whether) to switch between winter and summer (standard and daylight saving) time in different countries around the world. In 2009, the last release was 2009s; in 2010, it was 2010n; in 2011, it was 2011n; at the end of May 2012, the release was 2012c. Note that there is a set of code to manage the data and the actual time zone data itself, in two separate archives (tzcode20xxy.tar.gz and tzdata20xxy.tar.gz). Both code and data are in the public domain.
This is the source of time zone names such as America/Los_Angeles (and synonyms such as US/Pacific).
If you need to keep track of different zones, then you need the Olson database. As others have advised, you also want to store the data in a fixed format — UTC is normally the one chosen — along with a record of the time zone in which the data was generated. You may want to distinguish between the offset from UTC at the time and the time zone name; that can make a difference later. Also, knowing that it is currently 2010-03-28T23:47:00-07:00 (US/Pacific) may or may not help you with interpreting the value 2010-11-15T12:30 — which is presumably specified in PST (Pacific Standard Time) rather than PDT (Pacific Daylight Saving Time).
The standard C library interfaces are not dreadfully helpful with this sort of stuff.
The Olson data has moved, in part because A D Olson will be retiring soon, and in part because there was a (now dismissed) law suit against the maintainers for copyright infringement. The time zone database is now managed under the auspices of IANA, the Internet Assigned Numbers Authority, and there's a link on the front page to 'Time Zone Database'. The discussion mailing list is now tz#iana.org; the announcement list is tz-announce#iana.org.
In general, include the local time offset (including DST offset) in stored timestamps: UTC alone is not enough if you later want to display the timestamp in its original timezone (and DST setting).
Keep in mind that the offset is not always an integer number of hours (e.g. Indian Standard Time is UTC+05:30).
For example, suitable formats are a tuple (unix time, offset in minutes) or ISO 8601.
Crossing the boundary of "computer time" and "people time" is a nightmare. The main one being that there is no sort of standard for the rules governing timezones and daylight saving times. Countries are free to change their timezone and DST rules at any time, and they do.
Some countries e.g. Israel, Brazil, decide each year when to have their daylight saving times, so it is impossible to know in advance when (if) DST will be in effect. Others have fixed(ish) rules as to when DST is in effect. Other countries do not use DST as all.
Timezones do not have to be full hour differences from GMT. Nepal is +5.45. There are even timezones that are +13. That means that:
SUN 23:00 in Howland Island (-12)
MON 11:00 GMT
TUE 00:00 in Tonga (+13)
are all the same time, yet 3 different days!
There is also no clear standard on the abbreviations for timezones, and how they change when in DST so you end up with things like this:
AST Arab Standard Time UTC+03
AST Arabian Standard Time UTC+04
AST Arabic Standard Time UTC+03
The best advice is to stay away from local times as much as possible and stick to UTC where you can. Only convert to local times at the last possible moment.
When testing make sure you test countries in the Western and Eastern hemispheres, with both DST in progress and not and a country that does not use DST (6 in total).
For PHP:
The DateTimeZone class in PHP > 5.2 is already based on the Olson DB which others mention, so if you are doing timezone conversions in PHP and not in the DB, you are exempt of working with (the hard-to-understand) Olson files.
However, PHP is not updated as frequently as the Olson DB, so just using PHPs time zone conversions may leave you with outdated DST information and influence the correctness of your data. While this is not expected to happen frequently, it may happen, and will happen if you have a large base of users worldwide.
To cope with the above issue, use the timezonedb pecl package. Its function is to update PHP's timezone data. Install this package as frequently as it is updated. (I'm not sure if the updates to this package follow Olson updates exactly, but it seems to be updated at a frequency which is at least very close to the frequency of Olson updates.)
If your design can accommodate it, avoid local time conversion all together!
I know to some this might sound insane but think about UX: users process near, relative dates (today, yesterday, next Monday) faster than absolute dates (2010.09.17, Friday Sept 17) on glance. And when you think about it more, the accuracy of timezones (and DST) is more important the closer the date is to now(), so if you can express dates/datetimes in a relative format for +/- 1 or 2 weeks, the rest of the dates can be UTC and it wont matter too much to 95% of users.
This way you can store all dates in UTC and do the relative comparisons in UTC and simply show the user UTC dates outside of your Relative Date Threshold.
This can also apply to user input too (but generally in a more limited fashion). Selecting from a drop down that only has { Yesterday, Today, Tomorrow, Next Monday, Next Thursday } is so much simpler and easier for the user than a date picker. Date pickers are some of the most pain inducing components of form filling. Of course this will not work for all cases but you can see that it only takes a little clever design to make it very powerful.
I recently had a problem in a web application where on an Ajax post-back the datetime coming back to my server-side code was different from the datetime served out.
It most likely had to do with my JavaScript code on the client that built up the date for posting back to the client as string, because JavaScript was adjusting for time zone and daylight savings, and in some browsers the calculation for when to apply daylight savings seemed to be different than in others.
In the end I opted to remove date and time calculations on the client entirely, and posted back to my server on an integer key which then got translated to date time on the server, to allow for consistent transformations.
My learning from this:
Do not use JavaScript date and time calculations in web applications unless you ABSOLUTELY have to.
While I haven't tried it, an approach to time zone adjustments I would find compelling would be as follows:
Store everything in UTC.
Create a table TZOffsets with three columns: RegionClassId, StartDateTime, and OffsetMinutes (int, in minutes).
In the table, store a list of dates and times when the local time changed, and by how much. The number of regions in the table and the number of dates would depend on what range of dates and areas of the world you need to support. Think of this as if it is "historical" date, even though the dates should include the future to some practical limit.
When you need to compute the local time of any UTC time, just do this:
SELECT DATEADD('m', SUM(OffsetMinutes), #inputdatetime) AS LocalDateTime
FROM TZOffsets
WHERE StartDateTime <= #inputdatetime
AND RegionClassId = #RegionClassId;
You might want to cache this table in your app and use LINQ or some similar means to do the queries rather than hitting the database.
This data can be distilled from the public domain tz database.
Advantages and footnotes of this approach:
No rules are baked into code, you can adjust the offsets for new regions or date ranges readily.
You don't have to support every range of dates or regions, you can add them as needed.
Regions don't have to correspond directly to geopolitical boundaries, and to avoid duplication of rows (for instance, most states in the US handle DST the same way), you can have broad RegionClass entries that link in another table to more traditional lists of states, countries, etc.
For situations like the US where the start and end date of DST has changed over the past few years, this is pretty easy to deal with.
Since the StartDateTime field can store a time as well, the 2:00 AM standard change-over time is handled easily.
Not everywhere in the world uses a 1-hour DST. This handles those cases easily.
The data table is cross-platform and could be a separate open-source project that could be used by developers who use nearly any database platform or programming language.
This can be used for offsets that have nothing to do with time zones. For instance, the 1-second adjustments that happen from time to time to adjust for the Earth's rotation, historical adjustments to and within the Gregorian calendar, etc.
Since this is in a database table, standard report queries, etc. can take advantage of the data without a trip through business logic code.
This handles time zone offsets as well if you want it to, and can even account for special historical cases where a region is assigned to another time zone. All you need is an initial date that assigns a time zone offset to each region with a minimal start date. This would require creating at least one region for each time zone, but would allow you to ask interesting questions like: "What is the difference in local time between Yuma, Arizona and Seattle, Washington on February 2, 1989 at 5:00am?" (Just subtract one SUM() from the other).
Now, the only disadvantage of this approach or any other is that conversions from local time to GMT are not perfect, since any DST change that has a negative offset to the clock repeats a given local time. No easy way to deal with that one, I'm afraid, which is one reason storing local times is bad news in the first place.
I have hit this on two types of systems, “shift planning systems (e.g. factory workers)” and “gas depend management systems)…
23 and 25 hour long days are a pain to cope with, so are 8hr shifts that take 7hr or 9hr. The problem is you will find that each customers, or even department of the customer have different rules they have created (often without documenting) on what they do in these special cases.
Some questions are best not asked of the customer’s until after they have paid for your “off the shelf” software. It is very rare to find a customer that thinks about this type of issue up front when buying software.
I think in all cases you should record time in UTC and convert to/from local time before storing the date/time. However even know which take a given time is in can be hard with Daylight saving and time zones.
For the web, the rules aren't that complicated...
Server-side, use UTC
Client-side, use Olson
Reason: UTC-offsets are not daylight savings-safe (e.g. New York is EST (UTC - 5 Hours) part of the year, EDT (UTC - 4 Hours) rest of the year).
For client-side time zone determination, you have two options:
1) Have user set zone (Safer)
Resources: Web-ready Olson tz HTML Dropdown and JSON
2) Auto-detect zone
Resource: jsTimezoneDetect
The rest is just UTC/local conversion using your server-side datetime libraries. Good to go...
When it comes to applications that run on a server, including web sites and other back-end services, the time zone setting of the server should be ignored by the application.
The common advice is to set the server's time zone to UTC. This is indeed a good best practice, but it's there as a band-aid for applications that do not follow other best practices. For example, a service might be writing to log files with local timestamps instead of UTC-based timestamps, thus creating ambiguities during the daylight saving time fall-back transition. Setting the server's time zone to UTC will fix that application. However the real fix would be for the application to log using UTC to begin with.
Server-side code, including web sites, should never expect the local time zone of the server to be anything in particular.
In some languages, the local time zone can easily creep in to application code. For example, the DateTime.ToUniversalTime method in .NET will convert from the local time zone to UTC, and the DateTime.Now property returns the current time in the local time zone. Also, the Date constructor in JavaScript uses the computer's local time zone. There are many other examples like this. It is important to practice defensive programming, avoiding any code that uses the computer's local time zone setting.
Reserve using the local time zone for client-side code, such as desktop applications, mobile applications, and client-side JavaScript.
Keep your servers set to UTC, and make sure they all are configured for ntp or the equivalent.
UTC avoids daylight savings time issues, and out-of-sync servers can cause unpredictable results that take a while to diagnose.
Be careful when dealing with timestamps stored in the FAT32 filesystem - it is always persisted in local time coordinates (which include DST - see msdn article). Got burned on that one.
One other thing, make sure the servers have the up to date daylight savings patch applied.
We had a situation last year where our times were consistently out by one hour for a three-week period for North American users, even though we were using a UTC based system.
It turns out in the end it was the servers. They just needed an up-to-date patch applied (Windows Server 2003).
PHP's DateTimeZone::listAbbreviations() output
This PHP method returns an associative array containing some 'major' timezones (like CEST), which on their own contain more specific 'geographic' timezones (like Europe/Amsterdam).
If you're using these timezones and their offset/DST information, it's extremely important to realize the following:
It seems like all different offset/DST configurations (including historical configurations) of each timezone are included!
For example, Europe/Amsterdam can be found six times in the output of this function. Two occurrences (offset 1172/4772) are for the Amsterdam time used until 1937; two (1200/4800) are for the time that was used between 1937 and 1940; and two (3600/4800) are for the time used since 1940.
Therefore, you cannot rely on the offset/DST information returned by this function as being currently correct/in use!
If you want to know the current offset/DST of a certain timezone, you'll have to do something like this:
<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>
If you happen to maintain database systems that are running with DST active, check carefully whether they need to be shut down during the transition in fall. Mandy DBS (or other systems as well) don't like passing the same point in (local) time twice, which is exactly what happens when you turn back the clock in fall. SAP has solved this with a (IMHO really neat) workaround - instead of turning back the clock, they just let the internal clock run at half the usual speed for two hours...
Are you using the .NET framework?
If so, let me introduce you to the DateTimeOffset type, added with .NET 3.5.
This structure holds both a DateTime and an Offset (TimeSpan), which specifies the difference between the DateTimeOffset instance's date and time and Coordinated Universal Time (UTC).
The DateTimeOffset.Now static method will return a DateTimeOffset
instance consisting of the current (local) time, and the local offset
(as defined in the operating system's regional info).
The DateTimeOffset.UtcNow static method will return a
DateTimeOffset instance consisting of the current time in UTC (as
if you were in Greenwich).
Other helpful types are the TimeZone and TimeZoneInfo classes.
For those struggling with this on .NET, see if using DateTimeOffset and/or TimeZoneInfo are worth your while.
If you want to use IANA/Olson time zones, or find the built in types are insufficient for your needs, check out Noda Time, which offers a much smarter date and time API for .NET.
Business rules should always work on civil time (unless there's legislation that says otherwise). Be aware that civil time is a mess, but it's what people use so it's what is important.
Internally, keep timestamps in something like civil-time-seconds-from-epoch. The epoch doesn't matter particularly (I favour the Unix epoch) but it does make things easier than the alternative. Pretend that leap-seconds don't exist unless you're doing something that really needs them (e.g., satellite tracking). The mapping between timestamps and displayed time is the only point where DST rules should be applied; the rules change frequently (on a global level, several times a year; blame politicians) so you should make sure that you do not hard-code the mapping. Olson's TZ database is invaluable.
Just one example to prove that handling time is the huge mess described, and that you can never be complacent. In several spots on this page leap-seconds have been ignored.
Several years ago, the Android operating system used GPS satellites to get a UTC time reference, but ignored the fact that GPS satellites do not use leap-seconds. No one noticed until there was confusion on New Year's Eve, when the Apple phone users and Android phone users did their count-downs about 15 seconds apart.
I think it has since been fixed, but you never know when these 'minor details' will come back to haunt you.
Just wanted to point out two things that seem inaccurate or at least confusing:
Always persist time according to a unified standard that is not
affected by daylight savings. GMT and UTC have been mentioned by
different people, though UTC seems to be mentioned most often.
For (almost) all practical computing purposes, UTC is, in fact, GMT. Unless you see a timestamps with a fractional second, you're dealing with GMT which makes this distinction redundant.
Include the local time offset as is (including DST offset) when
storing timestamps.
A timestamp is always represented in GMT and thus has no offset.
Here is my experience:-
(Does not require any third-party library)
On server-side, store times in UTC format so that all date/time values in database are in a single standard regardless of location of users, servers, timezones or DST.
On the UI layer or in emails sent out to user, you need to show times according to user. For that matter, you need to have user's timezone offset so that you can add this offset to your database's UTC value which will result in user's local time. You can either take user's timezone offset when they are signing up or you can auto-detect them in web and mobile platforms. For websites, JavaScript's function getTimezoneOffset() method is a standard since version 1.0 and compatible with all browsers. (Ref: http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp)
Tom Scott's video about timezones on YouTube on the Computerphile channel has also a nice and entertaining description of the topic.
Examples include:
Samoa (an island in the Pacific Ocean) shifting its time zone forward by 24 hours to make trading easier with Australia and New Zealand,
West Bank, where 2 populations of people are following different time zones,
18th century changes from the Julian calendar to the Gregorian
calendar (which happened in the 20th century in Russia).
Actually, kernel32.dll does not export SystemTimeToTzSpecificLocation. It does however export the following two: SystemTimeToTzSpecificLocalTime and TzSpecificLocalTimeToSystemTime...
Never rely only on constructors like
new DateTime(int year, int month, int day, int hour, int minute, TimeZone timezone)
They can throw exceptions when a certain date time does not exist due to DST. Instead, build your own methods for creating such dates. In them, catch any exceptions that occur due to DST, and adjust the time is needed with the transition offset. DST may occur on different dates and at different hours (even at midnight for Brazil) according to the timezone.
Never, ever store local time without its UTC offset (or a reference to the time zone)—examples of how not to do it include FAT32 and struct tm in C.¹
Understand that a time zone is a combination of
a set of UTC offsets (e.g. +0100 in winter, +0200 in summer)
rules for when the switchover happens (which may change over time: for example, in the 1990s the EU harmonized the switchover as being on the last Sundays in March and October, at 02:00 standard time/03:00 DST; previously this differed between member states).
¹ Some implementations of struct tm do store the UTC offset, but this has not made it into the standard.
In dealing with databases (in particular MySQL, but this applies to most databases), I found it hard to store UTC.
Databases usually work with server datetime by default (that is, CURRENT_TIMESTAMP).
You may not be able to change the server timezone.
Even if you are able to change the timezone, you may have third-party code that expects server timezone to be local.
I found it easier to just store server datetime in the database, then let the database convert the stored datetime back to UTC (that is, UNIX_TIMESTAMP()) in the SQL statements. After that you can use the datetime as UTC in your code.
If you have 100% control over the server and all code, it's probably better to change server timezone to UTC.

How to handle DST time shifts in a PHP application?

I have to maintain some old browsergame and in this game the user has planets which produce ressources. When an user opens the planet view, the amount of ressources is calculated by building the the diffence between the last update of the planet and the current time, like this:
$secondsBetweenUpdate = time() - $lastUpdate; // Timestamps
This night there was time shift (in at least Germany from daylight saving time to normal time - or as we say in German from "summer time" to "winter time") and so between the "new" 2AM and "new" 3AM the above difference is negative and so the player looses ressources instead of getting them.
For sure I can avoid the loosing by setting $secondsBetweenUpdate to zero if it is getting negative but is there a way to handle the shift correctly? To be honest I'm not even sure what would be right - regardless the change from daylight saving time to normal time in autum or the change from normal time to daylight saving time.
Can anyone give me some advise to handle such time shifts?
I saw this SO Thread about Daylight saving time and time zone best practices and one advise is to store all times as Zulu time. How would I do that and how can I show the time for a user correctly - meaning the time he sees is the same as on his e.g. watch?
We use PHP (with of course CSS and JavaScript), Mysql and are partly migrated to cakePHP framework.
Use the GMT timezone on your server, which doesn't have time shifts.
The manner of doing this varies system-by-system. In Ubuntu, for example, you would do the following:
sudo dpkg-reconfigure tzdata
And select the GMT option.
Then, if you need to display dates, you can use PHP's date library to change timezone to suit your client's preferences, e.g. (for Eastern Standard Time):
$date = new DateTime($lastUpdate);
$date->setTimezone(new DateTimeZone('EST'));
PHP will handle time shifts, e.g. due to DST in the US

How to store repeating dates keeping in mind Daylight Savings Time

I'm storing events in my database. I have 'start' and 'end' date times, 'tickets_start' and 'tickets_end' (for when ticket sales actually start/end - as opposed to the start/end of the actual event).
So far, I've built methods that do all the fun stuff like converting the date/times to GMT before saving, then back to their respective timezone for display.
I'm storing the timezone in a varchar field with values like "America/New_York".
But - now I need to start dealing with if the user wants to allow repeating events. I've done it before, and it's not that big a deal, but never across multiple timezones.
At first, I thought it'd be no big deal, but then realized that - if the initial start date was in July (as example), and it repeats every month for a year, at some point, Daylight Savings Time will make it so that the conversion from GMT will change a time differently. One month, when converting 12:00, it would change it to -5, and the next, it would change it to -4 because of DST.
My current thought is that I'll store a 'dst' tinyint(1) for whether the start/end dates were entered during DST, and then make a method to alter the time by an hour if/when necessary.
But - figured I'd ask here in hopes maybe there's a "normal" for this or an easy something that I'm not thinking of.
(cakephp 2.4.x)
First, please recognize that in modern terminology you should say UTC instead of GMT. They are mostly equivalent, except that UTC is more precisely defined. Reserve the term GMT to refer to the portion of the time zone in the United Kingdom that is in effect during the winter months having the offset UTC+0.
Now to your question. UTC is not necessarily the best way to store all date and time values. It works particularly well for past events, or for future absolute events, but it doesn't work so great for future local events - especially future recurring events.
I wrote about this on another answer recently, and is one of the few exception cases where local time makes more sense than UTC. The main argument is the "alarm clock problem". If you set your alarm clock by UTC, you'll be waking up an hour early or late on the day of the DST transitions. This is why most folks set their alarm clocks by local time.
Of course, you can't just store a local time if you are working with data from all over the world. You should store a few different things:
The local time of the recurring event, such as "08:00"
The time zone that the local time is expressed in, such as "America/New_York"
The recurrence pattern, in whatever format makes sense for your application, such as daily, bi-weekly, or the third Thursday of the month, etc.
The next immediate UTC date and time equivalent, to the best that you can project it.
Perhaps, but not always, a list of future event UTC date and times, projected out some predefined period into the future (perhaps a week, perhaps 6 months, perhaps a year or two, depending on your needs).
For the last two, understand that the UTC equivalent of any local date/time can change if the government responsible for that time zone decides to change anything. Since there are multiple time zone database updates every year, you will want to have a plan to subscribe to announcements of updates and update your timezone database regularly. Whenever you update your timezone data, you'll need to recalculate the UTC equivalent times of all future events.
Having the UTC equivalents is important if you plan to show any kind of list of events spanning more than one time zone. Those are the values you'll query to build that list.
Another point to consider is that if an event is scheduled for a local time that occurs during a DST fall-back transition, you will have to decide whether the event occurs on the first instance (usually), or the second instance (sometimes), or both (rarely), and build into your application a mechanism to ensure the event doesn't fire twice unless you want it to.
If you were looking for a simple answer - sorry, but there isn't one. Scheduling future events across time zones is a complicated task.
Alternative Approach
I've had a few people show me a technique where they do use UTC time for scheduling, which is that they pick a starting date in local time, convert that to UTC to be stored, and store the time zone ID as well. Then at runtime, they apply the time zone to convert the original UTC time back to local time, then use that local time to compute the other recurrences, as if it were the one originally stored as above.
While this technique will work, the drawbacks are:
If there's a time zone update that changes the local time before the first instance is run, it will throw the whole schedule off. This can be mitigated by choosing a time in the past for the "first" instance, such that the second instance is really the first one.
If the time is really a "floating time" that should follow the user around (such as in an alarm clock on a cell phone), you'd still have to store time zone information for the zone it was originally created in - even if that's not the zone you want to run in.
It adds additional complexity without any benefit. I'd reserve this technique for situations where you may have had a UTC-only scheduler that you're trying to retrofit time zone support into.

Displaying date and time according to location [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I am hoping to make this question and the answers to it the definitive guide to dealing with daylight saving time, in particular for dealing with the actual change overs.
If you have anything to add, please do
Many systems are dependent on keeping accurate time, the problem is with changes to time due to daylight savings - moving the clock forward or backwards.
For instance, one has business rules in an order taking system that depend on the time of the order - if the clock changes, the rules might not be as clear. How should the time of the order be persisted? There are of course an endless number of scenarios - this one is simply an illustrative one.
How have you dealt with the daylight saving issue?
What assumptions are part of your solution? (looking for context here)
As important, if not more so:
What did you try that did not work?
Why did it not work?
I would be interested in programming, OS, data persistence and other pertinent aspects of the issue.
General answers are great, but I would also like to see details especially if they are only available on one platform.
Summary of answers and other data: (please add yours)
Do:
Whenever you are referring to an exact moment in time, persist the time according to a unified standard that is not affected by daylight savings. (GMT and UTC are equivalent with this regard, but it is preferred to use the term UTC. Notice that UTC is also known as Zulu or Z time.)
If instead you choose to persist a (past) time using a local time value, include the local time offset for this particular time from UTC (this offset may change throughout the year), such that the timestamp can later be interpreted unambiguously.
In some cases, you may need to store both the UTC time and the equivalent local time. Often this is done with two separate fields, but some platforms support a datetimeoffset type that can store both in a single field.
When storing timestamps as a numeric value, use Unix time - which is the number of whole seconds since 1970-01-01T00:00:00Z (excluding leap seconds). If you require higher precision, use milliseconds instead. This value should always be based on UTC, without any time zone adjustment.
If you might later need to modify the timestamp, include the original time zone ID so you can determine if the offset may have changed from the original value recorded.
When scheduling future events, usually local time is preferred instead of UTC, as it is common for the offset to change. See answer, and blog post.
When storing whole dates, such as birthdays and anniversaries, do not convert to UTC or any other time zone.
When possible, store in a date-only data type that does not include a time of day.
If such a type is not available, be sure to always ignore the time-of-day when interpreting the value. If you cannot be assured that the time-of-day will be ignored, choose 12:00 Noon, rather than 00:00 Midnight as a more safe representative time on that day.
Remember that time zone offsets are not always an integer number of hours (for example, Indian Standard Time is UTC+05:30, and Nepal uses UTC+05:45).
If using Java, use java.time for Java 8 and later.
Much of that java.time functionality is back-ported to Java 6 & 7 in the ThreeTen-Backport library.
Further adapted for early Android (< 26) in the ThreeTenABP library.
These projects officially supplant the venerable Joda-Time, now in maintenance-mode. Joda-Time, ThreeTen-Backport, ThreeTen-Extra, java.time classes, and JSR 310 are led by the same man, Stephen Colebourne.
If using .NET, consider using Noda Time.
If using .NET without Noda Time, consider that DateTimeOffset is often a better choice than DateTime.
If using Perl, use DateTime.
If using Python 3.9 or later, use the built-in zoneinfo for working with time zones. Otherwise, use dateutil or arrow. The older pytz library can generally be avoided.
If using JavaScript, avoid using the older moment.js or moment-timezone libraries, as they are no longer actively maintained. See the Moment.js project status for more details. Instead, consider Luxon, date-fns, day.js, or js-joda.
If using PHP > 5.2, use the native time zones conversions provided by DateTime, and DateTimeZone classes. Be careful when using DateTimeZone::listAbbreviations() - see answer. To keep PHP with up to date Olson data, install periodically the timezonedb PECL package; see answer.
If using C++, be sure to use a library that uses the properly implements the IANA timezone database. These include cctz, ICU, and Howard Hinnant's "tz" library. In C++20 the latter is adopted into the standard <chrono> library.
Do not use Boost for time zone conversions. While its API claims to support standard IANA (aka "zoneinfo") identifiers, it crudely maps them to POSIX-style data, without considering the rich history of changes each zone may have had. (Also, the file has fallen out of maintenance.)
If using Rust, use chrono.
Most business rules use civil time, rather than UTC or GMT. Therefore, plan to convert UTC timestamps to a local time zone before applying application logic.
Remember that time zones and offsets are not fixed and may change. For instance, historically US and UK used the same dates to 'spring forward' and 'fall back'. However, in 2007 the US changed the dates that the clocks get changed on. This now means that for 48 weeks of the year the difference between London time and New York time is 5 hours and for 4 weeks (3 in the spring, 1 in the autumn) it is 4 hours. Be aware of items like this in any calculations that involve multiple zones.
Consider the type of time (actual event time, broadcast time, relative time, historical time, recurring time) what elements (timestamp, time zone offset and time zone name) you need to store for correct retrieval - see "Types of Time" in this answer.
Keep your OS, database and application tzdata files in sync, between themselves and the rest of the world.
On servers, set hardware clocks and OS clocks to UTC rather than a local time zone.
Regardless of the previous bullet point, server-side code, including web sites, should never expect the local time zone of the server to be anything in particular. see answer.
Prefer working with time zones on a case-by-case basis in your application code, rather than globally through config file settings or defaults.
Use NTP services on all servers.
If using FAT32, remember that timestamps are stored in local time, not UTC.
When dealing with recurring events (weekly TV show, for example), remember that the time changes with DST and will be different across time zones.
Always query date-time values as lower-bound inclusive, upper-bound exclusive (>=, <).
Don't:
Do not confuse a "time zone", such as America/New_York with a "time zone offset", such as -05:00. They are two different things. See the timezone tag wiki.
Do not use JavaScript's Date object to perform date and time calculations in older web browsers, as ECMAScript 5.1 and lower has a design flaw that may use daylight saving time incorrectly. (This was fixed in ECMAScript 6 / 2015).
Never trust the client's clock. It may very well be incorrect.
Don't tell people to "always use UTC everywhere". This widespread advice is shortsighted of several valid scenarios that are described earlier in this document. Instead, use the appropriate time reference for the data you are working with. (Timestamping can use UTC, but future time scheduling and date-only values should not.)
Testing:
When testing, make sure you test countries in the Western, Eastern, Northern and Southern hemispheres (in fact in each quarter of the globe, so 4 regions), with both DST in progress and not (gives 8), and a country that does not use DST (another 4 to cover all regions, making 12 in total).
Test transition of DST, i.e. when you are currently in summer time, select a time value from winter.
Test boundary cases, such as a timezone that is UTC+12, with DST, making the local time UTC+13 in summer and even places that are UTC+13 in winter
Test all third-party libraries and applications and make sure they handle time zone data correctly.
Test half-hour time zones, at least.
Reference:
The detailed timezone tag wiki page on Stack Overflow
Olson database, aka Tz_database
IETF draft procedures for maintaining the Olson database
Sources for Time Zone and DST
ISO format (ISO 8601)
Mapping between Olson database and Windows Time Zone Ids, from the Unicode Consortium
Time Zone page on Wikipedia
StackOverflow questions tagged dst
StackOverflow questions tagged timezone
Dealing with DST - Microsoft DateTime best practices
Network Time Protocol on Wikipedia
Other:
Lobby your representative to end the abomination that is DST. We can always hope...
Lobby for Earth Standard Time
I'm not sure what I can add to the answers above, but here are a few points from me:
Types of times
There are four different times you should consider:
Event time: eg, the time when an international sporting event happens, or a coronation/death/etc. This is dependent on the timezone of the event and not of the viewer.
Television time: eg, a particular TV show is broadcast at 9pm local time all around the world. Important when thinking about publishing the results (of say American Idol) on your website
Relative time: eg: This question has an open bounty closing in 21 hours. This is easy to display
Recurring time: eg: A TV show is on every Monday at 9pm, even when DST changes.
There is also Historic/alternate time. These are annoying because they may not map back to standard time. Eg: Julian dates, dates according to a Lunar calendar on Saturn, The Klingon calendar.
Storing start/end timestamps in UTC works well. For 1, you need an event timezone name + offset stored along with the event. For 2, you need a local time identifier stored with each region and a local timezone name + offset stored for every viewer (it's possible to derive this from the IP if you're in a crunch). For 3, store in UTC seconds and no need for timezones. 4 is a special case of 1 or 2 depending on whether it's a global or a local event, but you also need to store a created at timestamp so you can tell if a timezone definition changed before or after this event was created. This is necessary if you need to show historic data.
Storing times
Always store time in UTC
Convert to local time on display (local being defined by the user looking at the data)
When storing a timezone, you need the name, timestamp and the offset. This is required because governments sometimes change the meanings of their timezones (eg: the US govt changed DST dates), and your application needs to handle things gracefully... eg: The exact timestamp when episodes of LOST showed both before and after DST rules changed.
Offsets and names
An example of the above would be:
The soccer world cup finals game
happened in South Africa (UTC+2--SAST)
on July 11, 2010 at 19:00 UTC.
With this information, we can historically determine the exact time when the 2010 WCS finals took place even if the South African timezone definition changes, and be able to display that to viewers in their local timezone at the time when they query the database.
System Time
You also need to keep your OS, database and application tzdata files in sync, both with each other, and with the rest of the world, and test extensively when you upgrade. It's not unheard of that a third party app that you depend on did not handle a TZ change correctly.
Make sure hardware clocks are set to UTC, and if you're running servers around the world, make sure their OSes are configured to use UTC as well. This becomes apparent when you need to copy hourly rotated apache log files from servers in multiple timezones. Sorting them by filename only works if all files are named with the same timezone. It also means that you don't have to do date math in your head when you ssh from one box to another and need to compare timestamps.
Also, run ntpd on all boxes.
Clients
Never trust the timestamp you get from a client machine as valid. For example, the Date: HTTP headers, or a javascript Date.getTime() call. These are fine when used as opaque identifiers, or when doing date math during a single session on the same client, but don't try to cross-reference these values with something you have on the server. Your clients don't run NTP, and may not necessarily have a working battery for their BIOS clock.
Trivia
Finally, governments will sometimes do very weird things:
Standard time in the Netherlands was
exactly 19 minutes and 32.13 seconds
ahead of UTC by law from 1909-05-01
through 1937-06-30. This time zone
cannot be represented exactly using
the HH:MM format.
Ok, I think I'm done.
This is an important and surprisingly tough issue. The truth is that there is no completely satisfying standard for persisting time. For example, the SQL standard and the ISO format (ISO 8601) are clearly not enough.
From the conceptual point of view, one usually deals with two types of time-date data, and it's convenient to distinguish them (the above standards do not) : "physical time" and "civil time".
A "physical" instant of time is a point in the continuous universal timeline that physics deal with (ignoring relativity, of course). This concept can be adequately coded-persisted in UTC, for example (if you can ignore leap seconds).
A "civil" time is a datetime specification that follows civil norms: a point of time here is fully specified by a set of datetime fields (Y,M,D,H,MM,S,FS) plus a TZ (timezone specification) (also a "calendar", actually; but lets assume we restrict the discussion to Gregorian calendar). A timezone and a calendar jointly allow (in principle) to map from one representation to another. But civil and physical time instants are fundamentally different types of magnitudes, and they should be kept conceptually separated and treated differently (an analogy: arrays of bytes and character strings).
The issue is confusing because we speak of these types events interchangeably, and because the civil times are subject to political changes. The problem (and the need to distinguish these concepts) becomes more evident for events in the future. Example (taken from my discussion here.
John records in his calendar a reminder for some event at datetime
2019-Jul-27, 10:30:00, TZ=Chile/Santiago, (which has offset GMT-4,
hence it corresponds to UTC 2019-Jul-27 14:30:00). But some day
in the future, the country decides to change the TZ offset to GMT-5.
Now, when the day comes... should that reminder trigger at
A) 2019-Jul-27 10:30:00 Chile/Santiago = UTC time 2019-Jul-27 15:30:00 ?
or
B) 2019-Jul-27 9:30:00 Chile/Santiago = UTC time 2019-Jul-27 14:30:00 ?
There is no correct answer, unless one knows what John conceptually meant
when he told the calendar "Please ring me at 2019-Jul-27, 10:30:00
TZ=Chile/Santiago".
Did he mean a "civil date-time" ("when the clocks in my city tell
10:30")? In that case, A) is the correct answer.
Or did he mean a "physical instant of time", a point in the continuus
line of time of our universe, say, "when the next solar eclipse
happens". In that case, answer B) is the correct one.
A few Date/Time APIs get this distinction right: among them, Jodatime, which is the foundation of the next (third!) Java DateTime API (JSR 310).
Make clear architectural separation of concerns - to know exactly which tier interacts with users, and has to change date-time for/from canonical representation (UTC). Non-UTC date-time is presentation (follows users local timezone), UTC time is model (remains unique for back-end and mid tiers).
Also, decide what's your actual audience, what you don't have to serve and where do you draw the line. Don't touch exotic calendars unless you actually have important customers there and then consider separate user-facing server(s) just for that region.
If you can acquire and maintain user's location, use location for systematic date-time conversion (say .NET culture or a SQL table) but provide a way for end-user to choose overrides if date-time is critical for your users.
If there are historical audit obligations involved (like telling exactly when Jo in AZ paid a bill 2 yrs ago in September) then keep both UTC and local time for the record (your conversion tables will change in a course of time).
Define the time referential time zone for data that comes in bulk - like files, web services etc. Say East Coast company has data center in CA - you need to ask and know what they use as a standard instead of assuming one or the other.
Don't trust time-zone offsets embedded in textual representation of the date-time and don't accept to parse and follow them. Instead always request that time zone and/or reference zone have to be explicitly defined. You can easily receive time with PST offset but the time is actually EST since that's the client's reference time and records were just exported at a server which is in PST.
You need to know about the Olson tz database, which is available from ftp://elsie.nci.nih.gov/pub http://iana.org/time-zones/. It is updated multiple times per year to deal with the often last-minute changes in when (and whether) to switch between winter and summer (standard and daylight saving) time in different countries around the world. In 2009, the last release was 2009s; in 2010, it was 2010n; in 2011, it was 2011n; at the end of May 2012, the release was 2012c. Note that there is a set of code to manage the data and the actual time zone data itself, in two separate archives (tzcode20xxy.tar.gz and tzdata20xxy.tar.gz). Both code and data are in the public domain.
This is the source of time zone names such as America/Los_Angeles (and synonyms such as US/Pacific).
If you need to keep track of different zones, then you need the Olson database. As others have advised, you also want to store the data in a fixed format — UTC is normally the one chosen — along with a record of the time zone in which the data was generated. You may want to distinguish between the offset from UTC at the time and the time zone name; that can make a difference later. Also, knowing that it is currently 2010-03-28T23:47:00-07:00 (US/Pacific) may or may not help you with interpreting the value 2010-11-15T12:30 — which is presumably specified in PST (Pacific Standard Time) rather than PDT (Pacific Daylight Saving Time).
The standard C library interfaces are not dreadfully helpful with this sort of stuff.
The Olson data has moved, in part because A D Olson will be retiring soon, and in part because there was a (now dismissed) law suit against the maintainers for copyright infringement. The time zone database is now managed under the auspices of IANA, the Internet Assigned Numbers Authority, and there's a link on the front page to 'Time Zone Database'. The discussion mailing list is now tz#iana.org; the announcement list is tz-announce#iana.org.
In general, include the local time offset (including DST offset) in stored timestamps: UTC alone is not enough if you later want to display the timestamp in its original timezone (and DST setting).
Keep in mind that the offset is not always an integer number of hours (e.g. Indian Standard Time is UTC+05:30).
For example, suitable formats are a tuple (unix time, offset in minutes) or ISO 8601.
Crossing the boundary of "computer time" and "people time" is a nightmare. The main one being that there is no sort of standard for the rules governing timezones and daylight saving times. Countries are free to change their timezone and DST rules at any time, and they do.
Some countries e.g. Israel, Brazil, decide each year when to have their daylight saving times, so it is impossible to know in advance when (if) DST will be in effect. Others have fixed(ish) rules as to when DST is in effect. Other countries do not use DST as all.
Timezones do not have to be full hour differences from GMT. Nepal is +5.45. There are even timezones that are +13. That means that:
SUN 23:00 in Howland Island (-12)
MON 11:00 GMT
TUE 00:00 in Tonga (+13)
are all the same time, yet 3 different days!
There is also no clear standard on the abbreviations for timezones, and how they change when in DST so you end up with things like this:
AST Arab Standard Time UTC+03
AST Arabian Standard Time UTC+04
AST Arabic Standard Time UTC+03
The best advice is to stay away from local times as much as possible and stick to UTC where you can. Only convert to local times at the last possible moment.
When testing make sure you test countries in the Western and Eastern hemispheres, with both DST in progress and not and a country that does not use DST (6 in total).
For PHP:
The DateTimeZone class in PHP > 5.2 is already based on the Olson DB which others mention, so if you are doing timezone conversions in PHP and not in the DB, you are exempt of working with (the hard-to-understand) Olson files.
However, PHP is not updated as frequently as the Olson DB, so just using PHPs time zone conversions may leave you with outdated DST information and influence the correctness of your data. While this is not expected to happen frequently, it may happen, and will happen if you have a large base of users worldwide.
To cope with the above issue, use the timezonedb pecl package. Its function is to update PHP's timezone data. Install this package as frequently as it is updated. (I'm not sure if the updates to this package follow Olson updates exactly, but it seems to be updated at a frequency which is at least very close to the frequency of Olson updates.)
If your design can accommodate it, avoid local time conversion all together!
I know to some this might sound insane but think about UX: users process near, relative dates (today, yesterday, next Monday) faster than absolute dates (2010.09.17, Friday Sept 17) on glance. And when you think about it more, the accuracy of timezones (and DST) is more important the closer the date is to now(), so if you can express dates/datetimes in a relative format for +/- 1 or 2 weeks, the rest of the dates can be UTC and it wont matter too much to 95% of users.
This way you can store all dates in UTC and do the relative comparisons in UTC and simply show the user UTC dates outside of your Relative Date Threshold.
This can also apply to user input too (but generally in a more limited fashion). Selecting from a drop down that only has { Yesterday, Today, Tomorrow, Next Monday, Next Thursday } is so much simpler and easier for the user than a date picker. Date pickers are some of the most pain inducing components of form filling. Of course this will not work for all cases but you can see that it only takes a little clever design to make it very powerful.
I recently had a problem in a web application where on an Ajax post-back the datetime coming back to my server-side code was different from the datetime served out.
It most likely had to do with my JavaScript code on the client that built up the date for posting back to the client as string, because JavaScript was adjusting for time zone and daylight savings, and in some browsers the calculation for when to apply daylight savings seemed to be different than in others.
In the end I opted to remove date and time calculations on the client entirely, and posted back to my server on an integer key which then got translated to date time on the server, to allow for consistent transformations.
My learning from this:
Do not use JavaScript date and time calculations in web applications unless you ABSOLUTELY have to.
While I haven't tried it, an approach to time zone adjustments I would find compelling would be as follows:
Store everything in UTC.
Create a table TZOffsets with three columns: RegionClassId, StartDateTime, and OffsetMinutes (int, in minutes).
In the table, store a list of dates and times when the local time changed, and by how much. The number of regions in the table and the number of dates would depend on what range of dates and areas of the world you need to support. Think of this as if it is "historical" date, even though the dates should include the future to some practical limit.
When you need to compute the local time of any UTC time, just do this:
SELECT DATEADD('m', SUM(OffsetMinutes), #inputdatetime) AS LocalDateTime
FROM TZOffsets
WHERE StartDateTime <= #inputdatetime
AND RegionClassId = #RegionClassId;
You might want to cache this table in your app and use LINQ or some similar means to do the queries rather than hitting the database.
This data can be distilled from the public domain tz database.
Advantages and footnotes of this approach:
No rules are baked into code, you can adjust the offsets for new regions or date ranges readily.
You don't have to support every range of dates or regions, you can add them as needed.
Regions don't have to correspond directly to geopolitical boundaries, and to avoid duplication of rows (for instance, most states in the US handle DST the same way), you can have broad RegionClass entries that link in another table to more traditional lists of states, countries, etc.
For situations like the US where the start and end date of DST has changed over the past few years, this is pretty easy to deal with.
Since the StartDateTime field can store a time as well, the 2:00 AM standard change-over time is handled easily.
Not everywhere in the world uses a 1-hour DST. This handles those cases easily.
The data table is cross-platform and could be a separate open-source project that could be used by developers who use nearly any database platform or programming language.
This can be used for offsets that have nothing to do with time zones. For instance, the 1-second adjustments that happen from time to time to adjust for the Earth's rotation, historical adjustments to and within the Gregorian calendar, etc.
Since this is in a database table, standard report queries, etc. can take advantage of the data without a trip through business logic code.
This handles time zone offsets as well if you want it to, and can even account for special historical cases where a region is assigned to another time zone. All you need is an initial date that assigns a time zone offset to each region with a minimal start date. This would require creating at least one region for each time zone, but would allow you to ask interesting questions like: "What is the difference in local time between Yuma, Arizona and Seattle, Washington on February 2, 1989 at 5:00am?" (Just subtract one SUM() from the other).
Now, the only disadvantage of this approach or any other is that conversions from local time to GMT are not perfect, since any DST change that has a negative offset to the clock repeats a given local time. No easy way to deal with that one, I'm afraid, which is one reason storing local times is bad news in the first place.
I have hit this on two types of systems, “shift planning systems (e.g. factory workers)” and “gas depend management systems)…
23 and 25 hour long days are a pain to cope with, so are 8hr shifts that take 7hr or 9hr. The problem is you will find that each customers, or even department of the customer have different rules they have created (often without documenting) on what they do in these special cases.
Some questions are best not asked of the customer’s until after they have paid for your “off the shelf” software. It is very rare to find a customer that thinks about this type of issue up front when buying software.
I think in all cases you should record time in UTC and convert to/from local time before storing the date/time. However even know which take a given time is in can be hard with Daylight saving and time zones.
For the web, the rules aren't that complicated...
Server-side, use UTC
Client-side, use Olson
Reason: UTC-offsets are not daylight savings-safe (e.g. New York is EST (UTC - 5 Hours) part of the year, EDT (UTC - 4 Hours) rest of the year).
For client-side time zone determination, you have two options:
1) Have user set zone (Safer)
Resources: Web-ready Olson tz HTML Dropdown and JSON
2) Auto-detect zone
Resource: jsTimezoneDetect
The rest is just UTC/local conversion using your server-side datetime libraries. Good to go...
When it comes to applications that run on a server, including web sites and other back-end services, the time zone setting of the server should be ignored by the application.
The common advice is to set the server's time zone to UTC. This is indeed a good best practice, but it's there as a band-aid for applications that do not follow other best practices. For example, a service might be writing to log files with local timestamps instead of UTC-based timestamps, thus creating ambiguities during the daylight saving time fall-back transition. Setting the server's time zone to UTC will fix that application. However the real fix would be for the application to log using UTC to begin with.
Server-side code, including web sites, should never expect the local time zone of the server to be anything in particular.
In some languages, the local time zone can easily creep in to application code. For example, the DateTime.ToUniversalTime method in .NET will convert from the local time zone to UTC, and the DateTime.Now property returns the current time in the local time zone. Also, the Date constructor in JavaScript uses the computer's local time zone. There are many other examples like this. It is important to practice defensive programming, avoiding any code that uses the computer's local time zone setting.
Reserve using the local time zone for client-side code, such as desktop applications, mobile applications, and client-side JavaScript.
Keep your servers set to UTC, and make sure they all are configured for ntp or the equivalent.
UTC avoids daylight savings time issues, and out-of-sync servers can cause unpredictable results that take a while to diagnose.
Be careful when dealing with timestamps stored in the FAT32 filesystem - it is always persisted in local time coordinates (which include DST - see msdn article). Got burned on that one.
One other thing, make sure the servers have the up to date daylight savings patch applied.
We had a situation last year where our times were consistently out by one hour for a three-week period for North American users, even though we were using a UTC based system.
It turns out in the end it was the servers. They just needed an up-to-date patch applied (Windows Server 2003).
PHP's DateTimeZone::listAbbreviations() output
This PHP method returns an associative array containing some 'major' timezones (like CEST), which on their own contain more specific 'geographic' timezones (like Europe/Amsterdam).
If you're using these timezones and their offset/DST information, it's extremely important to realize the following:
It seems like all different offset/DST configurations (including historical configurations) of each timezone are included!
For example, Europe/Amsterdam can be found six times in the output of this function. Two occurrences (offset 1172/4772) are for the Amsterdam time used until 1937; two (1200/4800) are for the time that was used between 1937 and 1940; and two (3600/4800) are for the time used since 1940.
Therefore, you cannot rely on the offset/DST information returned by this function as being currently correct/in use!
If you want to know the current offset/DST of a certain timezone, you'll have to do something like this:
<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>
If you happen to maintain database systems that are running with DST active, check carefully whether they need to be shut down during the transition in fall. Mandy DBS (or other systems as well) don't like passing the same point in (local) time twice, which is exactly what happens when you turn back the clock in fall. SAP has solved this with a (IMHO really neat) workaround - instead of turning back the clock, they just let the internal clock run at half the usual speed for two hours...
Are you using the .NET framework?
If so, let me introduce you to the DateTimeOffset type, added with .NET 3.5.
This structure holds both a DateTime and an Offset (TimeSpan), which specifies the difference between the DateTimeOffset instance's date and time and Coordinated Universal Time (UTC).
The DateTimeOffset.Now static method will return a DateTimeOffset
instance consisting of the current (local) time, and the local offset
(as defined in the operating system's regional info).
The DateTimeOffset.UtcNow static method will return a
DateTimeOffset instance consisting of the current time in UTC (as
if you were in Greenwich).
Other helpful types are the TimeZone and TimeZoneInfo classes.
For those struggling with this on .NET, see if using DateTimeOffset and/or TimeZoneInfo are worth your while.
If you want to use IANA/Olson time zones, or find the built in types are insufficient for your needs, check out Noda Time, which offers a much smarter date and time API for .NET.
Business rules should always work on civil time (unless there's legislation that says otherwise). Be aware that civil time is a mess, but it's what people use so it's what is important.
Internally, keep timestamps in something like civil-time-seconds-from-epoch. The epoch doesn't matter particularly (I favour the Unix epoch) but it does make things easier than the alternative. Pretend that leap-seconds don't exist unless you're doing something that really needs them (e.g., satellite tracking). The mapping between timestamps and displayed time is the only point where DST rules should be applied; the rules change frequently (on a global level, several times a year; blame politicians) so you should make sure that you do not hard-code the mapping. Olson's TZ database is invaluable.
Just one example to prove that handling time is the huge mess described, and that you can never be complacent. In several spots on this page leap-seconds have been ignored.
Several years ago, the Android operating system used GPS satellites to get a UTC time reference, but ignored the fact that GPS satellites do not use leap-seconds. No one noticed until there was confusion on New Year's Eve, when the Apple phone users and Android phone users did their count-downs about 15 seconds apart.
I think it has since been fixed, but you never know when these 'minor details' will come back to haunt you.
Just wanted to point out two things that seem inaccurate or at least confusing:
Always persist time according to a unified standard that is not
affected by daylight savings. GMT and UTC have been mentioned by
different people, though UTC seems to be mentioned most often.
For (almost) all practical computing purposes, UTC is, in fact, GMT. Unless you see a timestamps with a fractional second, you're dealing with GMT which makes this distinction redundant.
Include the local time offset as is (including DST offset) when
storing timestamps.
A timestamp is always represented in GMT and thus has no offset.
Here is my experience:-
(Does not require any third-party library)
On server-side, store times in UTC format so that all date/time values in database are in a single standard regardless of location of users, servers, timezones or DST.
On the UI layer or in emails sent out to user, you need to show times according to user. For that matter, you need to have user's timezone offset so that you can add this offset to your database's UTC value which will result in user's local time. You can either take user's timezone offset when they are signing up or you can auto-detect them in web and mobile platforms. For websites, JavaScript's function getTimezoneOffset() method is a standard since version 1.0 and compatible with all browsers. (Ref: http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp)
Tom Scott's video about timezones on YouTube on the Computerphile channel has also a nice and entertaining description of the topic.
Examples include:
Samoa (an island in the Pacific Ocean) shifting its time zone forward by 24 hours to make trading easier with Australia and New Zealand,
West Bank, where 2 populations of people are following different time zones,
18th century changes from the Julian calendar to the Gregorian
calendar (which happened in the 20th century in Russia).
Actually, kernel32.dll does not export SystemTimeToTzSpecificLocation. It does however export the following two: SystemTimeToTzSpecificLocalTime and TzSpecificLocalTimeToSystemTime...
Never rely only on constructors like
new DateTime(int year, int month, int day, int hour, int minute, TimeZone timezone)
They can throw exceptions when a certain date time does not exist due to DST. Instead, build your own methods for creating such dates. In them, catch any exceptions that occur due to DST, and adjust the time is needed with the transition offset. DST may occur on different dates and at different hours (even at midnight for Brazil) according to the timezone.
Never, ever store local time without its UTC offset (or a reference to the time zone)—examples of how not to do it include FAT32 and struct tm in C.¹
Understand that a time zone is a combination of
a set of UTC offsets (e.g. +0100 in winter, +0200 in summer)
rules for when the switchover happens (which may change over time: for example, in the 1990s the EU harmonized the switchover as being on the last Sundays in March and October, at 02:00 standard time/03:00 DST; previously this differed between member states).
¹ Some implementations of struct tm do store the UTC offset, but this has not made it into the standard.
In dealing with databases (in particular MySQL, but this applies to most databases), I found it hard to store UTC.
Databases usually work with server datetime by default (that is, CURRENT_TIMESTAMP).
You may not be able to change the server timezone.
Even if you are able to change the timezone, you may have third-party code that expects server timezone to be local.
I found it easier to just store server datetime in the database, then let the database convert the stored datetime back to UTC (that is, UNIX_TIMESTAMP()) in the SQL statements. After that you can use the datetime as UTC in your code.
If you have 100% control over the server and all code, it's probably better to change server timezone to UTC.

Online International Meeting Planner

More I think about this, more it gets difficult
The idea is to have a form where each person chooses his timezone and a time range and days of week available
ex.
Timezone
USA eastern
10pm-11pm sunday(checked) thursday (checked)
Now, someone searching the db from france will set his timezone to be 6hours later
any simple way to do this in php?
every use could be in a different timezone. so hours and maybe day of week will be different.
My personal recommendation would be to do all the storing and processing in the same time-zone (for example, GMT). Then, based on the user's settings simply display the times differently when outputting them to him by adjusting them by the necessary amount.

Categories