
What every programmer should know about time - enneff
http://unix4lyfe.org/time/
======
dirtyaura
> Timezones are a presentation-layer problem!

I want to correct this common misconception that UTC is enough. Calendar time
with all human traditions involved is more complex than a simple timestamp.

The advice above is incorrect for calendar and scheduling apps, or anything
that has a concept of a repeating event.

An example: we have a weekly meeting occurring 9AM Monday in San Francisco.
You are in London and want to attent the meeting over Skype. When is it in
London time?

It depends.

On 7 Mar 2011 it's at 5pm

On 14 Mar 2011 it's at 6pm

On 29 Mar 2011 it's at 5pm

To make these calculations, you need to know timezone & daylight saving time
(DST) rules of both your current location and the home location of the event.

A "DST zone" of a home location of a repeating event has to be saved together
with a time and thus it's not just presentation-layer issue.

~~~
jrockway
The article should add a caveat: use UNIX time when you are recording the
current time to store for later use. That can always be formatted in the
user's current timezone to display back.

When you're inventing a rule system based on local times, as you are above, of
course you need to track the rules in the local time zone. That's because the
rule is: "do this thing at 9am in my particular local time zone", not "do this
thing every 86400 seconds". Keep in mind that this is hard, though, due to the
fact that in many local time zones, one hour is missing on one day ("spring
forward"), and one hour occurs twice on one day ("fall back"). If you have
some event that should be triggered at 1:30am, which 1:30am do you mean? The
first 1:30am or the second 1:30am? What about on the "spring forward" day,
when 1:30am doesn't occur at all?

~~~
angstrom
And that doesn't even get into the problem of the DST dates changing at the
whim of legislation like it did recently in the US about 5 years ago. If you
are attempting to track timezone instead of UTC you've now have to check date
ranges when different DST was in effect. Very messy stuff. Better to just keep
it in UTC or Unix if you need the offset it was recorded in as you mentioned.

~~~
JohnLBevan
Talking of the DST point, how do you manage this in your apps? Say we're in
the UK, you schedule something to run at 9am GMT. In the summer, the timezone
changes to BST, so 9am GMT is still 9am UTC. I've never seen a scheduling app
where you say 9am UK, and have it automatically switch GMT to BST. The closest
I've seen is "use server time" where you have to setup the server to
automatically apply the DST rules - but then you have issues when working with
out of sync DST rules, such as those of the US.

------
geuis
"Timezones are a presentation-layer problem! Most of your code shouldn't be
dealing with timezones or local time, it should be passing Unix time around."

I can attest to this. At a previous job our entire API used UTC. It was clean
and worked at every layer of the app, from django to our client-side
javascript. When we needed to display a human readable version, we did the
translation at render time. All interactions with time as data was done with
the UTC timestamp and saved much headache.

A couple months before I left, one of the engineers proposed switching
everything over to a textual representation according to ISO_8601. I forget
the nature of the argument, but it was inane(to me). This actually led an
extensive back/forth email exchange between various members of engineering, me
as one of the frontend engineers, and even the engineering manager who seemed
to favor the idea.

I argued, "why change the entire stack which works just fine, etc etc".
Fortunately, in this instance a heavy workload and group apathy about taking
on unnecessary additional work allowed this entire concept to wither and
disappear after a couple days.

~~~
wvenable
Storing all your time as UTC can create problems depending on what you're
doing with the time. If your application is a calendaring application and
people can book things well into the future, you can have problems with
daylight saving time and timezones this way.

For my most recent app, timestamps are UTC and everything else is stored local
time.

~~~
barrkel
You'll need to store the time zone along with the local time, otherwise you
won't be able to handle the situation where you have multiple users in
different time zones. About the only reason this is preferable to storing UTC
along with time zone, is because there are sometimes political decisions made
to change daylight savings time (i.e. the mere fact of DST/TZs etc. isn't
enough).

~~~
wvenable
Yes, I store the timezone (associated with the user) along with the local
time. All date operations in the application are done related to their
timezone.

Storing it this way is preferable because it makes working with times across
DST boundaries a non-existent problem. DST is a pain in the ass and you want
to use whatever language / database facilities to exist to make this as smooth
as possible -- storing local time (and setting the timezone appropriately)
makes it not your problem. Also users frequently set their own timezone
incorrectly, and when they fix their timezone, they don't want all their
appointments to be at the wrong time.

------
tseabrooks
As someone working working on time sensitive code on embedded systems (DVRs
that get UTC from the broadcast), I can certainly agree with the issues laid
out in the post.

As an example: We have some certifications our product must pass and the
certification body plays a 4 minute looping broadcast stream with the test
condition in it. It turns out I handled the time jump hat occurred when the
stream would loop around poorly and this caused about 1 week worth of
headaches and delays in getting our certification. None of my code expects
time to be ever increasing now.

~~~
andrewcooke
just to add to the examples here: last week i was writing code to handle
calibration data from seismic detectors. these are connected to GPS receivers
and so have pretty accurate times. yet when i triggered a calibration it would
start 1 minute in the past. somehow the receiver was moving back in time
before starting the calibration....

...or ntpd on the test computer had failed and the machine was a minute fast
:o) so the code to search for data now looks backwards in time as well as
forwards.

incidentally, _does anyone know of a really good API for time (including
calendars etc)_? python's (which is largely a thin layer over C) is a horrible
mess, for example.

~~~
rvkennedy
Watch out for GPS time: it ignores leap seconds, and is currently, _exactly_
fifteen seconds ahead of UTC.

~~~
andrewcooke
thanks. currently everything is as insensitive to time as possible (during
calibration the data are tagged, so i look for the block of tagged data near
the correct time).

------
lysol
I like to rip on MySQL as much as the next guy, but the article is incorrect
about MySQL DATETIMEs:

DATETIME: Eight bytes: A four-byte integer packed as YYYY×10000 + MM×100 + DD
A four-byte integer packed as HH×10000 + MM×100 + SS

Storing UNIX time as an integer would be silly, considering:

TIMESTAMP: A four-byte integer representing seconds UTC since the epoch
('1970-01-01 00:00:00' UTC)

~~~
troels
MySql's datetime fields are not timezone aware. If one client has set one
timezone and inserts a value in a datetime field and another client has a
different timezone, the value will not be converted.

------
dkarl
Backwards jumps in time burned me once. The user was running my software on
machines that had a bug specific to certain Opteron multiprocessor chipsets
where a process migrating from one processor to another would sometimes see a
backwards jump in time, even when the system's time was marching forward
predictably on each processor. It just goes to show that you're always doing
distributed computing, even if you don't know it.

------
projectileboy
I'd like to add one to the list - store your Unix time as a 64-bit value, to
save your client/employer some headaches in 2032. I doubt I'm the only HN user
who was spent a lot of time in '98 and '99 fixing Y2K problems.

~~~
mambodog
*2038

<http://en.wikipedia.org/wiki/Year_2038_problem>

~~~
projectileboy
D'oh! I misfired typing. Thanks for the correction.

------
psykotic
Erik Naggum's paper The Long, Painful History of Time is a must-read:
<http://naggum.no/lugm-time.html>

------
kamagmar
> UTC (which is an arbitrary human invention)

Hmm, i wouldn't call it totally arbitrary. UTC = TAI + LS, such that |UTC -
UT1| < 1 second, where:

* LS are leap seconds,

* TAI is "physicist" time, based on the ticking of atomic clocks at mean sea level. The length of a second is constant.

* UT1 is "astronomer" time, the rotation angle of the Earth with respect to the quasar reference frame. The length of a second is not constant.

The Earth's rotation is slowing down, so UT1 is gradually drifting away from
TAI. UTC is a pretty natural scheme to reconcile these two systems.

------
petercooper
_UTC used to be called Greenwich Mean Time (GMT)_

Sort of. This could be misleading because GMT and UTC are still two different
things with different definitions. Wikipedia is a good source of info on this,
but for starters:

 _UTC is closely related to Universal Time and Greenwich Mean Time (GMT) and
within informal or casual contexts where sub-second precision is not required,
it can be used interchangeably._

So not strictly, but practically.. ;-)

------
roel_v
Don't blindly follow the advice at the end of this article! The issues he
identifies are real, but the 'solution' only work in a small subset of use
cases. When one needs a longer time span than [1970-2038], Unix timestamp is
horrible - how are you going to represent a date of birth in it for people
born before 1970 (yes they do still exist!)? There is no guarantee that
negative timestamps will work!

Also it doesn't take different calendars into account, _still_ doesn't work
with leap seconds, doesn't deal well with time spans (t1 - t2 specified in
seconds can be a lot things in reality), ...

Use a proper date time library to deal with dates and store them in your
database in a string format, including the time zone. It depends on your
application which time zone (UTC or local), but in general UTC is best, and
the local time zone could be a second column if you need the info (or it could
be a property of the user, but e.g. many calendaring application then screw it
up in the UI layer...)

I'd like to read a book on the UI issues associated with dates and times,
anyone know of something like that?

------
oasisbob
_Unix time: Measured as the number of seconds since epoch (the beginning of
1970 in UTC). Unix time is not affected by time zones or daylight saving._

I don't think this is strictly correct. This implies that someone could start
an atomic stopwatch at midnight on Jan 1, 1970, and it would match Unix time.
It won't.

Because Unix time is non-linear and will either slew or repeat seconds when
UTC has leap seconds, the hypothetical stopwatch would be ahead of Unix time
by 34 seconds.

... at least this is how I understand it. Every time I try and wrap by head
around the differences between UTC/TAI/UT1, my head really starts to hurt.

~~~
kijinbear
You're right. It should say: _Unix time is the number of seconds since epoch,
not counting leap seconds._

~~~
bluedanieru
Any idea why it was done this way? It seems like counting leap seconds belongs
in the same layer as sorting out timezones, i.e. not here.

~~~
thristian
Because people working with timestamps like to write code that says things
like:

    
    
        // schedule another run for tomorrow
        schedule_event(now() + 86400)
    

...which doesn't actually work when leap-seconds are involved (things start to
drift by a second). If you specify that leap seconds get replayed, it works.

~~~
shaggyfrog
An article previously linked on Hacker News goes into leap seconds in much
greater detail and is a good read:

[http://cacm.acm.org/magazines/2011/5/107699-the-one-
second-w...](http://cacm.acm.org/magazines/2011/5/107699-the-one-second-
war/fulltext)

------
sgerrand
As per gakman's comment in the Google+ crosspost[1], be wary of the Unix
millenium bug[2] if you use integers for timestamp storage.

[1]
[https://plus.google.com/106356964679457436995/posts/Hzq2P7V6...](https://plus.google.com/106356964679457436995/posts/Hzq2P7V6KUw)
[2] <http://en.wikipedia.org/wiki/Year_2038_problem>

~~~
yoyar
I wonder about storing the timestamp in a varchar field of sufficient size to
avoid all of these headaches? Although I guess 64 bit will suffice for a very
long time.

~~~
caf
As a point of reference, the universe is estimated at less than 2^59 seconds
old.

------
jen_h
"The system clock can, and will, jump backwards and forwards in time due to
things outside of your control. Your program should be designed to survive
this."

This is one of my favorite go-to test cases. I've found some really
fantastically interesting, catastrophic network halting badness with this
really simple test.

~~~
wladimir
This literally just happened to a VPS of mine. Time was jumping forwards and
back, every second the time could jump an hour ahead and back. Everything
screwed up, from log rotation to sessions.

My first thought was that this was some kind of prank :-) but seems it was a
hardware issue on the parent machine combined with ntpd trying to compensate.

~~~
justincormack
You should read this article (also applies to other VMs)
[http://www.vmware.com/files/pdf/Timekeeping-In-
VirtualMachin...](http://www.vmware.com/files/pdf/Timekeeping-In-
VirtualMachines.pdf)

There are a lot of issues that can happen because of this...

------
rmc
Another thing to add: When asking people to put in the timezones, don't ask
them for a UTC/GMT offset, and the dates that DST starts/ends. Instead ask
them for the tzdata format (e.g. "Europe/London"). Then you can localize that
wherever you want.

------
MarkMc
The problem with time-based bugs is that they are often subtle. I've had time-
based bugs that only appear between 11pm and midnight; or only during daylight
savings time; or only where the client is in a different timezone to the
server.

Also, it is very common for business applications to deal with 'dates in the
calendar', for example: a) John's birthday is 26 August 1966 b) The loan was
borrowed on 16 January 2006 and repaid on 9 September 2009.

I suspect most programmers will disagree with me, but in my experience it is
NOT good practice to use a timestamp class to represent such things. It's
better to use a class specifically designed to represent a date in the
(Gregorian) calendar. In fact, I created an open-source Java class for this
purpose: <http://calendardate.sourceforge.net/>

------
sehugg
Also beware storing milliseconds in 32-bit quantities (as if you'd ever! but
it happens).

GetTickCount is the poster child for this class of bugs:
<http://en.wikipedia.org/wiki/GetTickCount>

In fact some versions of Windows CE intentionally set this value to
(0xffffffff - 10 minutes) before bootup so that bugs were more likely to come
out in testing, rather than showing up 42 days after bootup.

Also, don't store time intervals as floating point, especially if you're
working on a missile system: <http://apps.ycombinator.com/item?id=1667060>

~~~
CamperBob
You can store milliseconds in 32-bit quantities all you want, if you remember
the One True Axiom of Time: never _compare_ tick counts, always _subtract_ and
compare to the difference you were looking for. If you do it that way, you
can't screw it up, at least in C.

~~~
cbr
Really? What if it wraps around? ts1=MAX_INT-40, ts2=20, ts2-ts1 < 0\. Or does
that actually work out correctly with signed integers in C?

~~~
wnoise
Technically, overflow of signed integers invokes undefined behavior (or
possibly implementation defined. In my copy of a draft standard overflow is
given as an example of undefined behavior, but 6.3.1.3 say implementation
defined). In practice, it's the same bit values as unsigned integers, which
does the right thing in this case.

------
melvinmt
One notable addition: relative time is the same for everyone.

What I mean by this is that instead of messing with timezones (by trying to
guess the user's timezone or even worse, asking for it) in most cases it is
sufficient to tell the user something has happened x hours ago, or y days ago.

If you're programming in PHP, I can recommend this book:
[http://www.amazon.com/architects-Guide-Date-Time-
Programming...](http://www.amazon.com/architects-Guide-Date-Time-
Programming/dp/0981034500)

~~~
codyrobbins
Ugh, I feel that this is one of the single poorest time-related pratices—from
a UX perspective—short of not displaying the time at all. Please don’t follow
this advice. It makes it really easy for the developer because there’s no need
to deal with time zones and things like DST. However, showing a relative time
in many situations is completely opaque. If something happened ‘14 hours ago’,
did it happen at lunch time or 3 PM? A lot of times people want to know the
time of day something happened, not just how long ago it occurred. Here you
can do some arithmetic in your head to figure it out, but that’s a major
annoyance. And once the relative time flips over to ‘X days ago’ the time
information is completely lost. Similarly if it says ‘About 3 months ago’ it’s
impossible to know if that means March 15 or April 1 or April 15 or anywhere
in between, never mind the time of day. At the very least the full date and
time should be displayed in a tooltip so that it’s available if needed.
Ideally relative times shouldn’t be used alone except in situations where the
relative time is absolutely, unarguably the only information that could ever
need to be known.

~~~
wvenable
I agree! And one of the more useful things you can do with a web app is render
time using JavaScript (with an appropriate fallback) and then it will show the
timestamp in the user's timezone automatically.

------
aaavw
Other little know facts about time:

The first day of the week can be sunday or monday depending on where you are.

The way to count the weeks isn't the same everywhere.

Some advice:

Default to using ISO 8601 whenever possible
<http://en.wikipedia.org/wiki/ISO_8601>

Don't ask for more precision then you actually need (Don't ask date & time
when you only need year & week)

Don't store dates and times with more precision then was actually entered
(e.g. Don't ask for year & week, and then store the (calculated) first day of
the week.

On my first large project I made the mistake of asking for the year & week
while storing the calculated first day of the week, however using the wrong
first day of the week and the wrong numbering of weeks…

------
jorangreef
In the future, the world will use UTC and sunrise and sunset will happen at
different times, relative to where you are.

~~~
adestefan
No they won't. The idea that 12am is night and 12pm is day is pretty well
entrenched in society.

~~~
georgefox
While I understand your point, I find that a surprising number of people have
issues with 12am vs. 12pm, often confusing the two. These same people tend to
think midnight occurs at the end of the day.

~~~
tomjen3
Everybody who isn't American or British has issues with am/pm. It is so
counter intuitive it is not even funny.

------
maurycy
For a much more detailed perspective about time, and still rather accessible,
check Poul-Henning Kamp's work:

<http://phk.freebsd.dk/pubs/timecounter.pdf> <http://people.freebsd.org/~phk/>

------
laut
"Other timezones can be written as an offset from UTC. Australian Eastern
Standard Time is UTC+1000. e.g. 10:00 UTC is 20:00 EST on the same day."

Every programmer should know about DST. Offsets are not always enough.

When it's winter north of the equator, some countries are on summer time (DST)
south of the equator.

------
JohnLBevan
It's about time someone posted about this. Great summary - when I first
started working on an international system I was hunting for this kind of
article. Now if someone could only do one on languages, regional settings,
character sets and encodings. . .

------
altrego99
MySQL (at least 4.x and 5.x) stores DATETIME columns as a "YYYY-MM-DD
HH:MM:SS" string

Wow that's terrible!

~~~
ReturnTheGift
And false. See lysol's reply or the 5.0 reference manual's section on storage
requirements:

[http://dev.mysql.com/doc/refman/5.0/en/storage-
requirements....](http://dev.mysql.com/doc/refman/5.0/en/storage-
requirements.html)

"YYYY-MM-DD HH:MM:SS" is the _format_ of the DATETIME datatype. That's all.

------
JonnieCache
For anyone else who has just learned about UT1 time and wants to know what
it's current value is, here's the link:

<http://tf.nist.gov/pubs/bulletin/leapsecond.htm>

Today, UT1 - UTC = 82ms.

------
wooptoo
> When storing time, store Unix time. It's a single number.

This is BS. ISO-8601 (MySQL time) is way better and is not prone to the 2038
bug. Unix time has 'scalability' issues.

------
nivertech
The most important thing a programmer need to know about time: "Don't use t+1
or t+N in your timeseries backtesting code ;)"

------
rvkennedy
Julian Date FTW! Seriously, JD is much smaller than Unix time, so it's less
wasteful of numeric range for most practical purposes. And its use would
eliminate a barrier between the computing world and that of science.
<http://en.wikipedia.org/wiki/Julian_day>

------
tintin
Does NIST (and other sync tools) keep in mind the round-trip of a request (RTD
/ RTT)?

~~~
derobert
NTPd does. However, in order the eliminate it, it assumes the RTT is
symmetric, that is half is on the journey to the remote, half on the journey
back. Asymmetric links do lead to systemic error in NTP.

(It assumes symmetry because there isn't any way to measure the asymmetry
without first having time sync, and obvious catch-22. If you need better than
10ms accuracy, you'll need a GPS, etc.)

------
lacerus
How can I make Ruby on Rails use unix timestamps instead of MySQL DATETIMEs?

~~~
Confusion
Use the TIMESTAMP datatype for those columns. Also see the comment by lysol
(currently two above you) that indicates that the article is wrong about
MySQL.

------
closedbracket
I thought this was some productivity spiel.

------
rubashov
Fails to mention the distinction between Zulu and Solar time. All the times
mentioned are based on cesium atomic clocks. Satellite and military
applications are often instead based on when the Sun is exactly opposite the
Greenwich Meridian, re-synced daily.

