On time

What every programmer should know about time

Joeri Sebrechts / @joeri_s

why time zones suck

Every day has 24 hours.

Australia, Lord Howe's Island, April 2nd 2017
24.5 hours

Every non-DST day is 24 hours.

Russia, Kamchatka, March 28th 2010
Putin kills 2 time zones.

In GMT a day is 24 hours.

Greenwich observes British Summer Time.

In UTC a day is 24 hours.

Except if there is a leap second.

DST transitions twice a year.

Morocco, 2014

March 30+1h
June 28-1h
August 2+1h
October 26-1h

If you know the local time, you know the UTC time.

With DST the same hour occurs twice.

Every time between 0:00 and 24:00 is valid.

With DST, some hours don't exist.

Every date exists (in recent times).

Samoa, december 30th 2011

But at least we know what the rules are.

In 2014 the IANA TZ db changed 10 times.

We get proper notice of changes.

Turkey, October 2015
DST rules change with 3 weeks notice.

The date libraries handle all of that.

I

What is time

13.0.4.17.19

6th of Kislev, 5778

III Id. Nov. MMDCCLXX

Martius31
Aprilis30
Maius31
Junius30
Quintilis31
Sextilis30
September30
October31
November30
December30
Intercalary51
Ianuarius29
Februarius28
(Intercalary)23
Martius31
Aprilis29
Maius31
Iunius29
Quintilis31
Sextilis29
September29
October31
November29
December29
Ianuarius31
Februarius28/29
Martius31
Aprilis30
Maius31
Iunius30
Iulius31
Augustus31
September30
October31
November30
December31

AD

Gregorian Calendar

Thu, 4 October 1582 → Fri, 15 October 1582

YearAdoptedDays
1582France (mostly), Italy, Poland, Portugal, Spain10
1583Austria, Germany (Catholic states)10
...
1923Greece13
1927Turkey13
diesdaegday
SoliiSunnanSun
LunaeMonanMon
MartisTiwesTue
MercuriiWodanWed
IovisThorThu
VenerisFreyaFri
SaturniiSæternSat

gotcha

Twitter, December 29, 2014

ISO weekfromuntil
2014-5222 dec. 201428 dec. 2014
2015-0129 dec. 20144 jan. 2015
strftimevalue
%G4 digit ISO week year
%Y4 digit calendar year

10 + 2

5 × 12

9 192 631 770

TAI

Leap seconds

CUT TUC UTC

Time zones

$$t_{local} = tz(t_{utc})$$

local date and time- offset= UTC
2017-11-24 T 12:00:00+01:002017-11-24 T 11:00:00 Z

II

keeping time

(in computers)

Gotcha

August 2013, Deep Impact spacecraft lost

January 2010, Bank of Queensland terminals break

August 1999, GPS navigation devices broke

C time_t

Nov. 1971Unix 1st ed.32-bit signed counting 60ths of a second
Nov. 1973Unix 4th ed.32-bit signed counting seconds

Y2K38

January 19 2038, 03:14:07 UTC

System time

RTC / IRQ 8 - seconds

HPET - nanoseconds

Gotcha

VM clock drift

Network time

NTP

GPS

time representation

wall clock time !== coordinated time

range !== precision

java.util.Date

The good:
292 million BC - 292 million CE

The ugly:

  • not a date
  • not a value
  • not TZ aware
  • no leap seconds
  • imprecise
  • months to 11

java date api


  Date();

  @Deprecated
  Date(int year, int month, int date, int hrs, int min, int sec)

  long getTime();
  void setTime(long time);

  @Deprecated long parse(String s);
  @Deprecated int getDate();
  @Deprecated int getDay();
  // ...
          

java.time

does not suck

  • Local and zoned time

    
      ZonedDateTime z = 
        ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]")
        .withZoneSameInstant(ZoneId.of("IST"));
                    
  • Parse and display

    
      System.out.println(
        z.format(new DateTimeFormatter(ISO_OFFSET_DATE_TIME))
      );
      // 2007-12-03T14:45:30+05:30
                    

JavaScript Date


  Date(year, month, date, hours, minutes, seconds, milliseconds)

  getTime() // number
  setTime(timeValue)

  parse(dateString) // number
  getDay()
  getUTCDay()
  // ...
          

PHP

legacy date is bad (32-bit)

DateTime is ok

PHP DateTime

does not suck

  • Local and zoned time

    
      $dt = new DateTimeImmutable("2017-05-31 20:00:00.000123",
          new DateTimeZone("Europe/Brussels"));
      echo $dt->format("Y-m-d H:i:s.u P"); // 2017-05-31 20:00:00.000123 +02:00
                  
  • UTC time

    
      $dt = (new DateTimeImmutable("20:00Z"))
          ->setDate(1000000, 5, 31);
      echo $dt->format("Y-m-d H:i:s P"); // 1000000-05-31 20:00:00 +00:00
                  

ANSI SQL92

does not suck

typestoresshows
TIMESTAMPUTCsession TZ
TS WITH TIME ZONElocal date/time + offset
DATElocal date
TIMElocal time

MySQL

sucks

typestoresshows
TIMESTAMPUTC (32-bit)session TZ
DATETIMElocal date+time (no TZ)
DATElocal date (0001 - 9999)
TIMElocal time (+ microsecs.)

Postgres

almost doesn't suck

typestoresshows
TIMESTAMPUTC (64-bit)session TZ
TS WITH TIME ZONEUTC (64-bit)session TZ
DATElocal date
TIMElocal time

Oracle

doesn't suck?

typestoresshows
TIMESTAMPlocal date & time (11 byte)
TS WITH TIME ZONETS TZTS TZ
TS WITH LOCAL TZUTCsession TZ
DATElocal date & time
TIME 

Gotcha

Burundi passport birth date

the letter "x" is sometimes used instead of the day and month of birth

III

programming time

Strategies

  • Always coordinated
  • Local + offset for wall clock
  • Single source of time
  • DRY, pure and tested
  • 2017-05-31T21:00:00+02:00
  • 1496257200

SQL Strategies

  • TIMESTAMP
  • TS w/ (LOCAL) TZ or VARCHAR (ISO 8601)
  • CURRENT_TIMESTAMP()
  • set session time zone

PHP Strategies

  • DateTimeImmutable
  • Now from the DB
  • date_default_timezone_set()

JavaScript strategies

  • Avoid when possible
  • moment-timezone instead of Date
  • Now from the server
  • window.performance.now() for profiling

Testing strategies

  • Inject now
  • Test the future in the past
  • Use interesting dates

Thank you

for your time

questions?