Adding Time Zone Support to VA Smalltalk

Adding Time Zone Support to
VA Smalltalk
Donald MacQueen [|]
Instantiations, Inc.
A bad day in [] is better than a good day in {}
Copyright © 2013 Instantiations, Inc.
Why Time Zones are Important
•
Duration calculations that span Daylight Savings Time
(DST) transitions will be wrong otherwise.
•
•
Offsets from UTC will be incorrect without time zone
data.
•
•
America/New_York is UTC –5 in the winter, but UTC –4 when DST is in effect.
Time zones allow you to ask questions like "What time is
it now in Moscow?"
•
•
For example, DST started at 2am March 9th 2013. The duration between 8am 3/8/2013 and
8am 3/9/2013 would be incorrectly calculated as 24 hours without time zone data.
DateAndTime now transformToTimeZoneNamed: ‘Europe/Moscow’
Historical offsets have changed for some places
•
For example, Hawaii was UTC-9:30 until 1947, when it changed to UTC-10:30
Copyright © 2013 Instantiations, Inc.
Short History of Time Zones
•
•
•
First used in Great Britain in 1847 by railroads
International Time Zones codified late 1800s
DST first used in WWI by Germany to save coal
Copyright © 2013 Instantiations, Inc.
Time Zones are Political
•
•
•
•
•
•
A perfect world would have each time zone be a 'perfect'
15 degrees of longitude wide
China has just one time zone even though it spans 9
'perfect' time zones
Newfoundland Standard Time (NST) subtracts 3½ hours
from Coordinated Universal Time (UTC) aka GMT
Nepal (NPT) is UTC+5:45
Hawaii was UTC-10:30 until 1947. It is now UTC-10:00
The Chatham Islands in the Pacific are UTC+13:45
Copyright © 2013 Instantiations, Inc.
DST is Political
•
•
•
•
Arizona, Puerto Rico, Hawaii, the U.S. Virgin Islands and
American Samoa never go on DST
The US Congress expanded DST in 2007 to ‘save
energy’
Farmers dislike DST; retailers like it
Not clear that it saves energy
Copyright © 2013 Instantiations, Inc.
Time Zone Data
•
•
•
•
•
Most OSs use some form of the IANA Time Zone
Database also called the zoneinfo database or Olson
Database after its founder Arthur David Olson.
In zoneinfo, a time zone is any national region where
local clocks have all agreed since 1970.
Time zones have unique names in the form
Area/Location, e.g. 'America/New_York' or ‘Pacific/Fiji’.
The zoneinfo data is published as text files which are
then compiled to a platform independent binary format.
The text files contains time zone rules for DST
transitions, leap seconds, and changes to time zone
offsets such as Hawaii mentioned above.
Copyright © 2013 Instantiations, Inc.
Time Zone Data on *nix Platforms
•
zoneinfo ships with most *nix OSs, but 'lives' in different
places
•
•
•
•
Linux - /usr/share/zoneinfo
AIX - /usr/share/lib/zoneinfo
Solaris - /usr/share/lib/zoneinfo
The directory structure reflects the names of the time
zone files
•
/usr/share/zoneinfo/
•
America/
New_York
• Chicago, etc.
•
•
Pacific/
Guam
• Tokyo, etc.
•
•
Prior to 6.1, AIX used a non-standard binary format
Copyright © 2013 Instantiations, Inc.
Windows is Different
•
•
•
•
Keeps the 2 most current DST transitions in the registry.
Has no historical knowledge.
Uses non-standard names - 'Eastern/New York' instead
of 'America/New_York‘.
We ship the latest zoneinfo data in each release and
install it on Windows.
Copyright © 2013 Instantiations, Inc.
How Other Smalltalks Handle Time Zones
•
•
•
•
VW - supports 2 annually recurring transitions, same as
Windows.
Pharo – has time zones, but no DST info.
Dolphin - none in stock image.
Gemstone - uses Olson zoneinfo
Copyright © 2013 Instantiations, Inc.
Candidates for Ideas
•
Alan Lovejoy's Chronos Date/Time Library
•
•
•
•
overkill
60k+ lines of code
Does things like the Mayan calendar
David T. Lewis's Squeak package
•
•
•
•
Small
time zone only
lots of tests
supports leap seconds
Copyright © 2013 Instantiations, Inc.
Implementation
•
Created an EsTimeZoneDatabase class
Object subclass: #EsTimeZoneDatabase
instanceVariableNames: 'defaultLocation defaultTimeZone
ruleSetCache ruleCache '
classVariableNames: 'PlatformToOlsonKeysTable Singleton
TzInfoDir TzReader '
•
The singleton of this class
•
•
•
•
sets the defaultTimeZone and defaultLocation on startup
knows how to read binary zoneinfo data
caches recently used rules and ruleSets
has a Windows to Olson keys mapping
Copyright © 2013 Instantiations, Inc.
Implementation II
•
The DateAndTime class previously had two instance
variables:
•
•
•
milliseconds: the UTC number of milliseconds since January 1, 1901
offset: the number of seconds difference from UTC
The new DateAndTime class replaces offset with
timeZone:
•
•
milliseconds: the UTC number of milliseconds since January 1, 1901
timeZone: an instance of EsTimeZone
Copyright © 2013 Instantiations, Inc.
EsTimeZone
•
The EsTimeZone class has two instance variables:
•
•
timeZoneRule - an instance of EsTimeZoneRule
timeZoneRuleSet - an instance of EsTimeZoneRuleSet
Copyright © 2013 Instantiations, Inc.
EsTimeZoneRuleSet
Copyright © 2013 Instantiations, Inc.
EsTimeZoneRule
Copyright © 2013 Instantiations, Inc.
What you can't do with zoneinfo data
•
•
You can't reliably get the time zone from an abbreviation,
because of duplicates. For example, EST is Eastern
Standard Time in the US, and Eastern Summer Time in
Australia.
You can't reliably get the time zone from the offset when
creating a DateAndTime object. For example, UCT-5:00
is the offset for America/New_York in the winter and also
for America/Chicago in the summer when DST is in
effect.
Copyright © 2013 Instantiations, Inc.
Getting the System Time Zone - Windows
•
•
•
•
•
•
Get the name of the time zone from the registry, e.g.,
'Eastern/New York‘.
Find the Olson equivalent name in the
PlatformToOlsonKeysTable class variable of
EsTimeZoneDatabase, e.g. 'America/New_York'.
Read the binary zoneinfo data.
Create an instance of EsTimeZoneRuleSet from it.
Put that instance in the EsTimeZoneDatabase singleton
variable defaultTimeZone.
Set the EsTimeZoneDatabase singleton variable
defaultLocation to 'America/New_York‘.
Copyright © 2013 Instantiations, Inc.
PlatformToOlsonKeysTable
Copyright © 2013 Instantiations, Inc.
Getting the System Time Zone - Linux
•
•
•
•
•
•
•
/etc/timezone should have a valid Olson name, but it does not have
to or the name could have been manually changed.
We cannot rely on /etc/timezone, but we do not really need the
name.
/etc/localtime is a binary copy of the zoneinfo file that is currently
selected as the system time zone, but the file does not know its
name.
Read the binary zoneinfo data in /etc/localtime
Create an instance of EsTimeZoneRuleSet from it.
Put that instance in the EsTimeZoneDatabase singleton variable
defaultTimeZone
Set the EsTimeZoneDatabase singleton variable defaultLocation to
'/etc/localtime' since we don't know the name
Copyright © 2013 Instantiations, Inc.
Getting the System Time Zone - Solaris
•
•
•
•
•
/usr/lib/zoneinfo/localtime should be a binary copy of the
zoneinfo file that is currently selected as the system time
zone, but the file does not know its name.
Read the binary zoneinfo data in
/usr/lib/zoneinfo/localtime.
Create an instance of EsTimeZoneRuleSet from it.
Put that instance in the EsTimeZoneDatabase singleton
variable defaultTimeZone.
Set the EsTimeZoneDatabase singleton variable
defaultLocation to '/usr/lib/zoneinfo/localtime' since we
don't know the name
Copyright © 2013 Instantiations, Inc.
Getting the System Time Zone - AIX
•
•
•
•
•
•
AIX does not maintain a binary copy of the zoneinfo file
that is the currently selected system time zone.
The name of the time zone file currently selected is in
the file /etc/environment in a line that starts with 'TZ=‘.
Read the binary zoneinfo data for that name in
/usr/share/lib/zoneinfo.
Create an instance of EsTimeZoneRuleSet from it.
Put that instance in the EsTimeZoneDatabase singleton
variable defaultTimeZone.
Set the EsTimeZoneDatabase singleton variable
defaultLocation to the name we found in
/etc/environment
Copyright © 2013 Instantiations, Inc.
What Can Go Wrong
•
It is possible that we cannot find:
•
•
•
•
•
•
•
the zoneinfo data (bad path)
the binary zoneinfo data named by Windows & AIX
the binary copy of the currently selected system time zone (Linux & Solaris)
Create a dummy EsTimeZone object using the OSs
offset from UTC.
Name the object, for an offset of -5:00:00, Tz-05:00:00.
It will have one timeZoneRule specifying that DST is off
as of 01/01/1901. It will have no DST transitions.
We will warn the user using log4s (Yay!):
[log4s]
createLogger=timeZones
consoleAppender=timeZones, All, EsPatternLayout, '%c %-5p %l %16m'
Copyright © 2013 Instantiations, Inc.
Deprecated APIs
•
ANSI requires that we support these class APIs:
•
•
•
•
year: year day: dayOfYear hour: hour minute: minute second: second offset: anOffset.
year: year month: month day: dayOfMonth hour: hour minute: minute second: second offset:
aDuration.
Since we can't reliably get the time zone from the system
offset, we will create a dummy EsTimeZone object using
the OSs offset from UTC as above.
These DateAndTime objects will work fine, but they have
no DST transitions.
Copyright © 2013 Instantiations, Inc.
Optimization
•
•
•
•
•
"We should forget about small efficiencies, say about
97% of the time: premature optimization is the root of all
evil" - Donald Knuth
Optimization was done at the end using the VAST
profiler.
Supporting leap seconds made everything too slow, so it
was removed
DateAndTime now with time zone support averaged
7ms, just 1 ms slower than the previous implementation
using offsets
Added rule and ruleSet caches to the
EsTimeZoneDatabase singleton to speed things up.
Copyright © 2013 Instantiations, Inc.
Testing
•
Over 100 SUnit tests looking for things like:
•
•
Attempts to create DateAndTime objects in the hour just after the transition to
DST. In other words, if DST starts at 2:00:00am, then the time immediately
changes to 3:00:00am, and there are no valid DateAndTimes between
2:00:00am and 3:00:00am.
Similarly, adding a Duration of 10 minutes to 1:59:00am when DST starts at
2:00:00am must throw an error.
Copyright © 2013 Instantiations, Inc.
What went wrong - AAAAAAARGH!
•
•
•
•
Testing went fine on Windows 7 and XP, Linux, Solaris,
and AIX.
Yet less than a week after release, a German user
(thanks, Marten!) reported that the time zone data could
not be found on either Windows 7 or XP.
getOSTimeZoneName returned 'Mitteleuropäische Zeit'
instead of 'Europe/Berlin‘.
Created a fix and tested it on Windows 7 German and
Windows XP Spanish
Copyright © 2013 Instantiations, Inc.
If I had it to do over again I would
•
•
•
Get a pre-release out to select non-English customers
Investigate platform differences sooner
Leave more time for things to go wrong - Doh!
Copyright © 2013 Instantiations, Inc.
Demo!
•
•
•
(DateAndTime now) transformToTimeZoneNamed:
'America/St_Johns‘
(DateAndTime now) transformToTimeZoneNamed:
'Asia/Kathmandu'
(DateAndTime now) transformToTimeZoneNamed:
'Pacific/Chatham'
Copyright © 2013 Instantiations, Inc.
Log4s Has Been Open Sourced
•
•
Instantiations has open sourced its log4s logging
framework.
http://ss3.gemstone.com/ss/Log4s.html
Copyright © 2013 Instantiations, Inc.
References
•
•
•
•
•
Chronos - http://chronos-st.org/
Olson time zone http://en.wikipedia.org/wiki/IANA_time_zone_database
David T. Lewis - http://wiki.squeak.org/squeak/1076
Time Zones at IANA - http://www.iana.org/time-zones
VA Smalltalk documentation http://www.instantiations.com/docs/852/wwhelp/wwhimpl
/js/html/wwhelp.htm#href=sg/timeZones.531.1.html
Copyright © 2013 Instantiations, Inc.