Chronos is one of the many Smalltalk-related blogs syndicated on Planet Smalltalk
χρόνος

Discussion of the Essence# programming language, and related issues and technologies.

Blog Timezone: America/Los_Angeles [Winter: -0800 hhmm | Summer: -0700 hhmm] 
Your local time:  
Showing posts with label Chronos. Show all posts
Showing posts with label Chronos. Show all posts

2009-03-12

2009 US Holidays

Most of the listed "holidays" will actually be business days, although some will not. The US Federal Holidays (on which most US Government offices will close, along with all Federally-chartered banks) are highlighted in bold. Generally, each business decides on its own which of these days (if any) will be non-business days (and for which employees):


Thu, 01 Jan 2009: NewYearsDay
Thu, 08 Jan 2009: JacksonDay
Mon, 19 Jan 2009: MartinLutherKingDay
Tue, 20 Jan 2009: InaugurationDay
Mon, 02 Feb 2009: GroundhogDay
Thu, 12 Feb 2009: LincolnsBirthday
Sat, 14 Feb 2009: ValentinesDay
Mon, 16 Feb 2009: WashingtonsBirthday
Tue, 17 Mar 2009: StPatricksDay
Wed, 01 Apr 2009: AprilFoolsDay
Fri, 10 Apr 2009: GoodFriday
Sun, 12 Apr 2009: Easter
Wed, 22 Apr 2009: EarthDay
Wed, 22 Apr 2009: AdministrativeAssistantsDay
Fri, 24 Apr 2009: ArborDay
Sun, 10 May 2009: MothersDay
Mon, 25 May 2009: MemorialDay
Sun, 14 Jun 2009: FlagDay
Sun, 21 Jun 2009: FathersDay
Sat, 04 Jul 2009: IndependenceDay
Sun, 26 Jul 2009: ParentsDay
Mon, 07 Sep 2009: LaborDay
Sun, 13 Sep 2009: GrandParentsDay
Mon, 12 Oct 2009: ColumbusDay
Sat, 24 Oct 2009: UnitedNationsDay
Sat, 31 Oct 2009: Halloween
Wed, 11 Nov 2009: VeteransDay
Thu, 26 Nov 2009: Thanksgiving
Fri, 27 Nov 2009: DayAfterThanksgiving
Thu, 24 Dec 2009: ChristmasEve
Fri, 25 Dec 2009: Christmas
Thu, 31 Dec 2009: NewYearsEve

The above list was generated by the Chronos Date/Time Library, using the following "do it":

| list |
list := SortedCollection sortBlock: [:a :b | a value < b value].
SemanticDatePolicy unitedStates
nominalAnnualEventOccurenceDatesInYear: 2009 do:
[:semanticKey :date | list add: semanticKey->date].
Transcript cr.
list do:
[:assoc |
Transcript
cr; show: (assoc value printStringUsing: #rfc2822);
show: ':'; tab; show: assoc key]


2008-03-25

Version 2008b of the Chronos Time Zone Repository has been published

Version 2008b of the Chronos Time Zone Repository has been published. It is based on version 2008b of the Olson Time Zone Database.

Downloads:




2008-03-23

Easter Dates From 2000 to 2020

Since it's Easter today (according to the rule for computing Easter established by Pope Gregory in the late sixteenth century,) I thought I would post the occurrence dates for Easter from 2000 to 2020 AD (Gregorian):

2000-04-23
2001-04-15
2002-03-31
2003-04-20
2004-04-11
2005-03-27
2006-04-16
2007-04-08
2008-03-23
2009-04-12
2010-04-04
2011-04-24
2012-04-08
2013-03-31
2014-04-20
2015-04-05
2016-03-27
2017-04-16
2018-04-01
2019-04-21
2020-04-12

And here's the Chronos code that computes the list above:

2000 to: 2020 
do: [:year |
Transcript
cr;
show: (GregorianEaster canonical inYear: year) printString]

Note, however, that not all Christians use the Gregorian calendar, or don't use Pope Gregory's rule for determining the date on which Easter occurs. Some still use the first "universal" Roman Catholic rule (which was established in 325 AD.) Before that, Easter was celebrated at various dates in different locales and cultures. Originally, it coincided with the day just before Passover (which is 14 Nisan in the Hebrew calendar, since Passover starts on 15 Nisan; also note that Hebrew calendar days start at sundown.)

2008-03-23 AD @ 12:55:09 pm -0700 [Gregorian]
0165-01-03 BE @ 12:55:09 pm -0700 [Bahai]
1724-07-14 AM @ 12:55:09 pm -0700 [Coptic]
2000-07-14 ZH @ 12:55:09 pm -0700 [Ethiopic]
5768-13-16 AM @ 12:55:09 pm -0700 [Hebrew]
1930-01-03 AS @ 12:55:09 pm -0700 [Indian Civil]
1429-03-15 AH @ 12:55:09 pm -0700 [Islamic (Fatimid)]
2008-03-10 AD @ 12:55:09 pm -0700 [Julian]
2761-03-10 AUC @ 12:55:09 pm -0700 [Julian (Imperial)]
1387-01-04 AP @ 12:55:09 pm -0700 [Persian]
6244-04-04 SY @ 12:55:09 pm -0700 [Solarian]
2008-083 @ 12:55:09 pm -0700 [Gregorian-ordinal date]
2008-W12-7 @ 12:55:09 pm -0700 [ISO]
J.D. 2454549 @ 12:55:09 pm -0700 [Julian Day]
39163:19:55:09.771325 days:hh:mm:ss.s.. since 1901-01-01T00:00:00Z (ST80 epoch)
1206302109 seconds since 1970-01-01T00:00:00Z (Unix epoch)
128507757097713250 100-nanosecond ticks since 1601-01-01T00:00:00Z (MS WIndows epoch)
Easter
weekend (Sunday)


2008-01-01

2007-12-31

2008 US Holidays

Most of the listed "holidays" will actually be business days, although some will not. The US Federal Holidays (on which most US Government offices will close, along with all Federally-chartered banks) are highlighted in bold. Generally, each business decides on its own which of these days (if any) will be non-business days (and for which employees):


Tue, 01 Jan 2008: NewYearsDay
Tue, 08 Jan 2008: JacksonDay
Mon, 21 Jan 2008: MartinLutherKingDay
Sat, 02 Feb 2008: GroundhogDay
Tue, 12 Feb 2008: LincolnsBirthday
Thu, 14 Feb 2008: ValentinesDay
Mon, 18 Feb 2008: WashingtonsBirthday
Mon, 17 Mar 2008: StPatricksDay
Fri, 21 Mar 2008: GoodFriday
Sun, 23 Mar 2008: Easter
Tue, 01 Apr 2008: AprilFoolsDay
Tue, 22 Apr 2008: EarthDay
Wed, 23 Apr 2008: AdministrativeAssistantsDay
Fri, 25 Apr 2008: ArborDay
Sun, 11 May 2008: MothersDay
Mon, 26 May 2008: MemorialDay
Sat, 14 Jun 2008: FlagDay
Sun, 15 Jun 2008: FathersDay
Fri, 04 Jul 2008: IndependenceDay
Sun, 27 Jul 2008: ParentsDay
Mon, 01 Sep 2008: LaborDay
Sun, 07 Sep 2008: GrandParentsDay
Mon, 13 Oct 2008: ColumbusDay
Fri, 24 Oct 2008: UnitedNationsDay
Fri, 31 Oct 2008: Halloween
Tue, 04 Nov 2008: ElectionDay
Tue, 11 Nov 2008: VeteransDay
Thu, 27 Nov 2008: Thanksgiving
Fri, 28 Nov 2008: DayAfterThanksgiving
Wed, 24 Dec 2008: ChristmasEve
Thu, 25 Dec 2008: Christmas
Wed, 31 Dec 2008: NewYearsEve

The above list was generated by the Chronos Date/Time Library, using the following "do it":

| list |
list := SortedCollection sortBlock: [:a :b | a value < b value].
SemanticDatePolicy unitedStates
nominalAnnualEventOccurenceDatesInYear: 2008 do:
[:semanticKey :date | list add: semanticKey->date].
Transcript cr.
list do:
[:assoc |
Transcript
cr; show: (assoc value printStringUsing: #rfc2822);
show: ':'; tab; show: assoc key]


Happy (Gregorian) New Year! (2008)

Timepoint now showInCommonWorldTimezones


Tue, 01 Jan 2008 13:55:54 +1300 (NZDT: Pacific/Auckland | New Zealand Time)
Tue, 01 Jan 2008 11:55:54 +1100 (EST: Australia/Sydney | AUS Eastern Time)
Tue, 01 Jan 2008 09:55:54 +0900 (JST: Asia/Tokyo | Tokyo Time)
Tue, 01 Jan 2008 09:55:54 +0900 (WST: Australia/Perth | W. Australia Time)
Tue, 01 Jan 2008 08:55:54 +0800 (HKT: Asia/Hong_Kong)
Tue, 01 Jan 2008 06:25:54 +0530 (IST: Asia/Calcutta | India Time)
Tue, 01 Jan 2008 03:55:54 +0300 (MSK: Europe/Moscow | Russian Time)
Tue, 01 Jan 2008 02:55:54 +0200 (IST: Asia/Jerusalem | Israel Time)
Tue, 01 Jan 2008 01:55:54 +0100 (CET: Europe/Amsterdam)
Tue, 01 Jan 2008 00:55:54 +0000 (GMT: Europe/London | London Time)
Tue, 01 Jan 2008 00:55:54 +0000 (UT: Universal Time)
Mon, 31 Dec 2007 22:55:54 -0200 (BRST: America/Sao_Paulo | E. South America Time)
Mon, 31 Dec 2007 21:55:54 -0300 (ART: America/Argentina/Buenos_Aires)
Mon, 31 Dec 2007 19:55:54 -0500 (EST: America/New_York | Eastern Time)
Mon, 31 Dec 2007 18:55:54 -0600 (CST: America/Chicago | Central Time)
Mon, 31 Dec 2007 17:55:54 -0700 (MST: America/Denver | Mountain Time)
Mon, 31 Dec 2007 16:55:54 -0800 (PST: America/Los_Angeles | Pacific Time)
Mon, 31 Dec 2007 14:55:54 -1000 (HST: Pacific/Honolulu | Hawaiian Time)


2007-12-25

Merry Christmas! (in Various Calendars)

Timepoint now showInAllCalendars
Local time is America/Los_Angeles ("Pacific Standard Time")—8 hours west of Universal Time


2007-12-25 AD @ 9:00:15 am -0800 [Gregorian]
0164-15-14 BE @ 9:00:15 am -0800 [Bahai]
1724-04-15 AM @ 9:00:15 am -0800 [Coptic]
2000-04-15 ZH @ 9:00:15 am -0800 [Ethiopic]
5768-10-16 AM @ 9:00:15 am -0800 [Hebrew]
1929-10-04 AS @ 9:00:15 am -0800 [Indian Civil]
1428-12-15 AH @ 9:00:15 am -0800 [Islamic (Fatimid)]
2007-12-12 AD @ 9:00:15 am -0800 [Julian]
2760-12-12 AUC @ 9:00:15 am -0800 [Julian (Imperial)]
1386-10-04 AP @ 9:00:15 am -0800 [Persian]
6244-01-04 SY @ 9:00:15 am -0800 [Solarian]
2007-359 @ 9:00:15 am -0800 [Gregorian-ordinal date]
2007-W52-2 @ 9:00:15 am -0800 [ISO]
J.D. 2454459 @ 9:00:15 am -0800 [Julian Day]
39074:17:00:15.077734 days:hh:mm:ss.s.. since 1901-01-01T00:00:00Z (ST80 epoch)
1198602015 seconds since 1970-01-01T00:00:00Z (Unix epoch)
128430756150777340 100-nanosecond ticks since 1601-01-01T00:00:00Z (MS WIndows epoch)
Christmas


2007-06-05

Time Zone Boundary Divides University Campus

SOUTHERN Cross University (New South Wales, Australia) has a rather unique problem: They're establishing a new campus at the Gold Coast Airport Development Park, which will straddle the Queensland-NSW border on Crown land abutting the southern side of the Gold Coast Airport. New South Wales observes DST. Queensland does not.

Civil time will shift back and forth by an hour in NSW, but not in Queensland. So how will classes be scheduled? What about work schedules? Vice Chancellor Paul Clark said "We will probably be the guinea pigs in many ways because there's nowhere else in Australia with feet in two different states."

Now consider this question: How well would your software handle a case like this? Would your date/time library even be up to the task?


2007-04-29

About the version of Chronos distributed with VW 7.5...

VisualWorks 7.5 was released (finally!) a few days ago. For the first time, the Chronos Date/Time Library is included as a contributed component.

However, I would like to make everyone aware of the following points:


  • The version of Chronos that is on the CD (or that is available from the download page) is an ancient version from early January 2006 (more than a year ago.)

  • No Chronos parcels are included. Only the "Chronos.st" and "Chronos-Utilities.st" files are present (because back in January 2006, I wasn't distributing parcel files for Chronos.) I've been including parcels in the VisualWorks version of the Chronos download archive since March 2006.

I really recommend that, instead of using the version of Chronos that comes with VW 7.5, you either download the latest version of Chronos (Chronos Version B1.196), or else get the latest released version from the Cincom Public Store.


2007-03-26

Chronos Time Zone Repository Version 2007d Published

Version 2007d of the Chronos Time Zone Repository has been published. It is based on version 2007d of the Olson Time Zone Database.

Downloads:




2007-03-12

2007 North American DST Changes: Resources & References (2)

Due to the changes at Planet Smalltalk, which have invalidated all URLs to old articles, and due to the fact that Google searches are still preferentially returning results to now-invalid URLs at Planet Smalltalk, I am republishing the following information:


The Chronos Date/Time Library has had the correct DST rules for North America since 2005-08-22 (a year and a half ago.)


2007-02-13

Chronos Time Zone Repository Version 2007b Published

Version 2007b of the Chronos Time Zone Repository has been published. It is based on version 2007b of the Olson Time Zone Database.

Downloads:




Chronos Roadmap

Current Task: Implement iCal Recurrence Rules

Planned Tasks/Enhancements/Features:


  • Implement full support for "Business Day Conventions," including addition/subtraction of business days (supplementing the already-supported "business days between dates" functionality.) Business date conventions specify the business rule for adjusting dates so that they don't fall on holidays, such as "next business day," "preceding business day," "nearest business day, "next business day in same month--adjusting to previous business day if necessary," "previous business day in same month--adjusting to next business day if necessary"

  • Implement multiple timescales (e.g., UT0, UT1, UTC, TAI, apparent
    solar...) Will at least implement UT1 and UTC--but the architecture will be extensible.

  • Complete all documentation.

  • Implement the Chinese Calendar.

  • Implement the Astronomical Hijri (Islamic) Calendar.

  • Implement conformance to the IANA Time Zone Registry Specification




2007-02-08

The times they are a-changing...

The last time the rules for entering and leaving Daylight Saving Time changed in North America was 1987. That was a very different world than we have today. It was significantly less automated, significantly less computerized and significantly less dependent on computers and software for accomplishing mission critical tasks.

So, on an upcoming fateful day in March 2007, when legal, civil time in North America's "Eastern Time Zone" jumps in an instant from 2007-03-11T01:59:59.99999999...-05:00 to 2007-03-11T03:00:00-04:00, what will happen? How many computer systems, and devices using embedded computer systems, will fail to recognize that civil time is suddenly an hour later than it had been? And what consequences are likely to ensue?

I strongly suspect (to put it mildly) that the number of systems that won't have the correct civil time will be decidedly non-trivial. But the likely consequences of that timekeeping failure are much harder to guess. One likely result will be users complaining about 1-hour time-of-day discrepancies. The most likely cause of serious malfunctions will be situations where two or more computer systems colloborate together in such a way that clock synchronization matters, with some (but not all) of them still using the old time zone rules for North America.

The best way to handle the problems that might arise due to your computers using the wrong time zone rules is to make sure all your computers know the new rules. If you do nothing, it's highly likely that your computers won't know anything about it (and that's true from Mainframes to PDAs, especially including computers that use Unix or Windows.)

Here are some resources with helpful information about updating the time zone rules for computers of various types:


But updating the operating system may not be sufficient. For reasons I won't go into here, there are many applications that don't rely on the OS to tell them what the time zone rules happen to be. One prominent example is Java. Another that may be of some interest to my intended audience on this blog (the community of Smalltalk programmers,) would be one of the most widely used Smalltalk variants: VisualWorks.

For information about updating Java applications with the new time zone rules, refer to the following:
Smalltalkers who use the Chronos Date/Time Library in their Smalltalk applications, and who obtained any version of the Chronos Time Zone Repository after late-August 2005 (a year and half ago!) already have the new time zone rules for North America. This is because the new rules were known as soon as Congress passed the Energy Policy Act of 2005 (in the Summer of 2005,) and also because the Chronos time zone rule sets are able to represent not only the rules for the current year, but also rules for other either past or future years that differ from those currently in effect.

As for those Smalltalkers who don't use Chronos in their applications, the situation is as follows:

VisualWorks: The time zone rules must be updated. My earlier blog post, VW: 2007 TimeZone settings for North America, explains how to do so.

Squeak: Those using the "out-of-the-box" Chronology classes don't need to do anything. But that's not because the Chronology classes know all about time zones, but rather because they don't. For many situations, there is no need for the Chronology classes to know anything about time zones. Squeak relies on the operating system to tell it what the local time currently is. That's a very simple approach...which stops working as soon as you need to do any of the following things:
  • Convert a date/time from some other time zone into your local time (because you don't know what your offset from Universal Time happens to be, and may also not know the offset of the other time zone.)
  • Convert a local date/time to some other time zone (for the same reasons as above.)
  • Correctly compute the amount of physical, elapsed time between two points in time (because you won't know whether the time zone offsets of the two points in time were the same, since there may have been one or more intervening DST transitions; or worse, the two points in time may not even have been intended to represent time in the same time zone.)
  • Correctly compute the point in time that results when adding a duration to a point in time (again, because you won't know whether the offset will be the same, since the offset may be different even a fraction of a second earlier or later.)

But those using Squeak have two other options. One is Chronos, which has already been discussed. The other is the David T. Lewis' TimeZoneDatabase (which functions in a way very similar to Chronos, at least as far as time zones are concerned.) Just like Chronos, the TimeZoneDatabase relies on an external repository of time zone rules--and both use the Olson Time Zone Database as the source of those rules. On Unix-based hosts, the TimeZoneDatabase can be configured to use the same binary "tzfiles" as Unix itself uses, at the same disk location--which means that updating the operating system's time zone rules also updates the TimeZoneDatabase. But on non-Unix based systems, the "tzfiles" must be updated separately.

Dolphin Smalltalk: Dolphin uses Windows system calls to get the current local time. Although Dolphin very helpfully provides the ability to get time zone information from the Windows Registry, its native TimeStamp class doesn't use that capability to provide time-zone-aware date/time behavior. Chronos is also available for Dolphin.

Most other Smalltalk systems are essentially similar to either Squeak or Dolphin, as far as time zone functionality is concerned.

But all this raises a very good question: Why are time zones such a hard problem?


2007-02-07

When's the next (or previous) DST offset transition?

How can you tell programmatically when the next (or previous) DST (daylight saving time) offset transition will occur (has occurred)--other than by using a brute-force approach where one checks the offset of successive points in time, each one second later than the previous one? Few date/time libraries provide any support for such functionality (and many don't even provide support for real-world time zones where offsets change during the year according to a set of rules.)

Although it's possible to use Chronos to discover all the moments when a time zone's offset, name or abbreviation changes (and not just by the brute-force method mentioned above,) the bad news is that for a developer who casually uses Chronos to figure out how to code that functionality would probably require not only a bit of research, but also the writing of some non-trivial amount of new code.

So, the next release of Chronos (which is not yet available) will provide a simple, easy-to-use API for enumerating through all the moments when a time zone's offset changes, so that developers who use Chronos won't have to do as much research, and won't have to write anywhere near as much new new code, in order to find the next (or previous) offset transition for a time zone. Using this new API, the following list of every offset transition in the America/Los_Angeles time zone, from the very first one in 1883 until the arbitrarily chosen end-year of 2050, can easily be generated:

1883-11-18T12:00:00-08:00  [1883-11-18T20:00:00Z] -07:52:58 -> -08:00  {-2717640000}
1918-03-31T03:00:00-07:00 [1918-03-31T10:00:00Z] -08:00 -> -07:00 {-1633269600}
1918-10-27T01:00:00-08:00 [1918-10-27T09:00:00Z] -07:00 -> -08:00 {-1615129200}
1919-03-30T03:00:00-07:00 [1919-03-30T10:00:00Z] -08:00 -> -07:00 {-1601820000}
1919-10-26T01:00:00-08:00 [1919-10-26T09:00:00Z] -07:00 -> -08:00 {-1583679600}
1942-02-09T03:00:00-07:00 [1942-02-09T10:00:00Z] -08:00 -> -07:00 {-880207200}
1945-08-14T16:00:00-07:00 [1945-08-14T23:00:00Z] -07:00 -> -07:00 {-769395600}
1945-09-30T01:00:00-08:00 [1945-09-30T09:00:00Z] -07:00 -> -08:00 {-765385200}
1948-03-14T03:00:00-07:00 [1948-03-14T10:00:00Z] -08:00 -> -07:00 {-687967200}
1949-01-01T01:00:00-08:00 [1949-01-01T09:00:00Z] -07:00 -> -08:00 {-662655600}
1950-04-30T03:00:00-07:00 [1950-04-30T10:00:00Z] -08:00 -> -07:00 {-620834400}
1950-09-24T01:00:00-08:00 [1950-09-24T09:00:00Z] -07:00 -> -08:00 {-608137200}
1951-04-29T03:00:00-07:00 [1951-04-29T10:00:00Z] -08:00 -> -07:00 {-589384800}
1951-09-30T01:00:00-08:00 [1951-09-30T09:00:00Z] -07:00 -> -08:00 {-576082800}
1952-04-27T03:00:00-07:00 [1952-04-27T10:00:00Z] -08:00 -> -07:00 {-557935200}
1952-09-28T01:00:00-08:00 [1952-09-28T09:00:00Z] -07:00 -> -08:00 {-544633200}
1953-04-26T03:00:00-07:00 [1953-04-26T10:00:00Z] -08:00 -> -07:00 {-526485600}
1953-09-27T01:00:00-08:00 [1953-09-27T09:00:00Z] -07:00 -> -08:00 {-513183600}
1954-04-25T03:00:00-07:00 [1954-04-25T10:00:00Z] -08:00 -> -07:00 {-495036000}
1954-09-26T01:00:00-08:00 [1954-09-26T09:00:00Z] -07:00 -> -08:00 {-481734000}
1955-04-24T03:00:00-07:00 [1955-04-24T10:00:00Z] -08:00 -> -07:00 {-463586400}
1955-09-25T01:00:00-08:00 [1955-09-25T09:00:00Z] -07:00 -> -08:00 {-450284400}
1956-04-29T03:00:00-07:00 [1956-04-29T10:00:00Z] -08:00 -> -07:00 {-431532000}
1956-09-30T01:00:00-08:00 [1956-09-30T09:00:00Z] -07:00 -> -08:00 {-418230000}
1957-04-28T03:00:00-07:00 [1957-04-28T10:00:00Z] -08:00 -> -07:00 {-400082400}
1957-09-29T01:00:00-08:00 [1957-09-29T09:00:00Z] -07:00 -> -08:00 {-386780400}
1958-04-27T03:00:00-07:00 [1958-04-27T10:00:00Z] -08:00 -> -07:00 {-368632800}
1958-09-28T01:00:00-08:00 [1958-09-28T09:00:00Z] -07:00 -> -08:00 {-355330800}
1959-04-26T03:00:00-07:00 [1959-04-26T10:00:00Z] -08:00 -> -07:00 {-337183200}
1959-09-27T01:00:00-08:00 [1959-09-27T09:00:00Z] -07:00 -> -08:00 {-323881200}
1960-04-24T03:00:00-07:00 [1960-04-24T10:00:00Z] -08:00 -> -07:00 {-305733600}
1960-09-25T01:00:00-08:00 [1960-09-25T09:00:00Z] -07:00 -> -08:00 {-292431600}
1961-04-30T03:00:00-07:00 [1961-04-30T10:00:00Z] -08:00 -> -07:00 {-273679200}
1961-09-24T01:00:00-08:00 [1961-09-24T09:00:00Z] -07:00 -> -08:00 {-260982000}
1962-04-29T03:00:00-07:00 [1962-04-29T10:00:00Z] -08:00 -> -07:00 {-242229600}
1962-10-28T01:00:00-08:00 [1962-10-28T09:00:00Z] -07:00 -> -08:00 {-226508400}
1963-04-28T03:00:00-07:00 [1963-04-28T10:00:00Z] -08:00 -> -07:00 {-210780000}
1963-10-27T01:00:00-08:00 [1963-10-27T09:00:00Z] -07:00 -> -08:00 {-195058800}
1964-04-26T03:00:00-07:00 [1964-04-26T10:00:00Z] -08:00 -> -07:00 {-179330400}
1964-10-25T01:00:00-08:00 [1964-10-25T09:00:00Z] -07:00 -> -08:00 {-163609200}
1965-04-25T03:00:00-07:00 [1965-04-25T10:00:00Z] -08:00 -> -07:00 {-147880800}
1965-10-31T01:00:00-08:00 [1965-10-31T09:00:00Z] -07:00 -> -08:00 {-131554800}
1966-04-24T03:00:00-07:00 [1966-04-24T10:00:00Z] -08:00 -> -07:00 {-116431200}
1966-10-30T01:00:00-08:00 [1966-10-30T09:00:00Z] -07:00 -> -08:00 {-100105200}
1967-04-30T03:00:00-07:00 [1967-04-30T10:00:00Z] -08:00 -> -07:00 {-84376800}
1967-10-29T01:00:00-08:00 [1967-10-29T09:00:00Z] -07:00 -> -08:00 {-68655600}
1968-04-28T03:00:00-07:00 [1968-04-28T10:00:00Z] -08:00 -> -07:00 {-52927200}
1968-10-27T01:00:00-08:00 [1968-10-27T09:00:00Z] -07:00 -> -08:00 {-37206000}
1969-04-27T03:00:00-07:00 [1969-04-27T10:00:00Z] -08:00 -> -07:00 {-21477600}
1969-10-26T01:00:00-08:00 [1969-10-26T09:00:00Z] -07:00 -> -08:00 {-5756400}
1970-04-26T03:00:00-07:00 [1970-04-26T10:00:00Z] -08:00 -> -07:00 {9972000}
1970-10-25T01:00:00-08:00 [1970-10-25T09:00:00Z] -07:00 -> -08:00 {25693200}
1971-04-25T03:00:00-07:00 [1971-04-25T10:00:00Z] -08:00 -> -07:00 {41421600}
1971-10-31T01:00:00-08:00 [1971-10-31T09:00:00Z] -07:00 -> -08:00 {57747600}
1972-04-30T03:00:00-07:00 [1972-04-30T10:00:00Z] -08:00 -> -07:00 {73476000}
1972-10-29T01:00:00-08:00 [1972-10-29T09:00:00Z] -07:00 -> -08:00 {89197200}
1973-04-29T03:00:00-07:00 [1973-04-29T10:00:00Z] -08:00 -> -07:00 {104925600}
1973-10-28T01:00:00-08:00 [1973-10-28T09:00:00Z] -07:00 -> -08:00 {120646800}
1974-01-06T03:00:00-07:00 [1974-01-06T10:00:00Z] -08:00 -> -07:00 {126698400}
1974-10-27T01:00:00-08:00 [1974-10-27T09:00:00Z] -07:00 -> -08:00 {152096400}
1975-02-23T03:00:00-07:00 [1975-02-23T10:00:00Z] -08:00 -> -07:00 {162381600}
1975-10-26T01:00:00-08:00 [1975-10-26T09:00:00Z] -07:00 -> -08:00 {183546000}
1976-04-25T03:00:00-07:00 [1976-04-25T10:00:00Z] -08:00 -> -07:00 {199274400}
1976-10-31T01:00:00-08:00 [1976-10-31T09:00:00Z] -07:00 -> -08:00 {215600400}
1977-04-24T03:00:00-07:00 [1977-04-24T10:00:00Z] -08:00 -> -07:00 {230724000}
1977-10-30T01:00:00-08:00 [1977-10-30T09:00:00Z] -07:00 -> -08:00 {247050000}
1978-04-30T03:00:00-07:00 [1978-04-30T10:00:00Z] -08:00 -> -07:00 {262778400}
1978-10-29T01:00:00-08:00 [1978-10-29T09:00:00Z] -07:00 -> -08:00 {278499600}
1979-04-29T03:00:00-07:00 [1979-04-29T10:00:00Z] -08:00 -> -07:00 {294228000}
1979-10-28T01:00:00-08:00 [1979-10-28T09:00:00Z] -07:00 -> -08:00 {309949200}
1980-04-27T03:00:00-07:00 [1980-04-27T10:00:00Z] -08:00 -> -07:00 {325677600}
1980-10-26T01:00:00-08:00 [1980-10-26T09:00:00Z] -07:00 -> -08:00 {341398800}
1981-04-26T03:00:00-07:00 [1981-04-26T10:00:00Z] -08:00 -> -07:00 {357127200}
1981-10-25T01:00:00-08:00 [1981-10-25T09:00:00Z] -07:00 -> -08:00 {372848400}
1982-04-25T03:00:00-07:00 [1982-04-25T10:00:00Z] -08:00 -> -07:00 {388576800}
1982-10-31T01:00:00-08:00 [1982-10-31T09:00:00Z] -07:00 -> -08:00 {404902800}
1983-04-24T03:00:00-07:00 [1983-04-24T10:00:00Z] -08:00 -> -07:00 {420026400}
1983-10-30T01:00:00-08:00 [1983-10-30T09:00:00Z] -07:00 -> -08:00 {436352400}
1984-04-29T03:00:00-07:00 [1984-04-29T10:00:00Z] -08:00 -> -07:00 {452080800}
1984-10-28T01:00:00-08:00 [1984-10-28T09:00:00Z] -07:00 -> -08:00 {467802000}
1985-04-28T03:00:00-07:00 [1985-04-28T10:00:00Z] -08:00 -> -07:00 {483530400}
1985-10-27T01:00:00-08:00 [1985-10-27T09:00:00Z] -07:00 -> -08:00 {499251600}
1986-04-27T03:00:00-07:00 [1986-04-27T10:00:00Z] -08:00 -> -07:00 {514980000}
1986-10-26T01:00:00-08:00 [1986-10-26T09:00:00Z] -07:00 -> -08:00 {530701200}
1987-04-05T03:00:00-07:00 [1987-04-05T10:00:00Z] -08:00 -> -07:00 {544615200}
1987-10-25T01:00:00-08:00 [1987-10-25T09:00:00Z] -07:00 -> -08:00 {562150800}
1988-04-03T03:00:00-07:00 [1988-04-03T10:00:00Z] -08:00 -> -07:00 {576064800}
1988-10-30T01:00:00-08:00 [1988-10-30T09:00:00Z] -07:00 -> -08:00 {594205200}
1989-04-02T03:00:00-07:00 [1989-04-02T10:00:00Z] -08:00 -> -07:00 {607514400}
1989-10-29T01:00:00-08:00 [1989-10-29T09:00:00Z] -07:00 -> -08:00 {625654800}
1990-04-01T03:00:00-07:00 [1990-04-01T10:00:00Z] -08:00 -> -07:00 {638964000}
1990-10-28T01:00:00-08:00 [1990-10-28T09:00:00Z] -07:00 -> -08:00 {657104400}
1991-04-07T03:00:00-07:00 [1991-04-07T10:00:00Z] -08:00 -> -07:00 {671018400}
1991-10-27T01:00:00-08:00 [1991-10-27T09:00:00Z] -07:00 -> -08:00 {688554000}
1992-04-05T03:00:00-07:00 [1992-04-05T10:00:00Z] -08:00 -> -07:00 {702468000}
1992-10-25T01:00:00-08:00 [1992-10-25T09:00:00Z] -07:00 -> -08:00 {720003600}
1993-04-04T03:00:00-07:00 [1993-04-04T10:00:00Z] -08:00 -> -07:00 {733917600}
1993-10-31T01:00:00-08:00 [1993-10-31T09:00:00Z] -07:00 -> -08:00 {752058000}
1994-04-03T03:00:00-07:00 [1994-04-03T10:00:00Z] -08:00 -> -07:00 {765367200}
1994-10-30T01:00:00-08:00 [1994-10-30T09:00:00Z] -07:00 -> -08:00 {783507600}
1995-04-02T03:00:00-07:00 [1995-04-02T10:00:00Z] -08:00 -> -07:00 {796816800}
1995-10-29T01:00:00-08:00 [1995-10-29T09:00:00Z] -07:00 -> -08:00 {814957200}
1996-04-07T03:00:00-07:00 [1996-04-07T10:00:00Z] -08:00 -> -07:00 {828871200}
1996-10-27T01:00:00-08:00 [1996-10-27T09:00:00Z] -07:00 -> -08:00 {846406800}
1997-04-06T03:00:00-07:00 [1997-04-06T10:00:00Z] -08:00 -> -07:00 {860320800}
1997-10-26T01:00:00-08:00 [1997-10-26T09:00:00Z] -07:00 -> -08:00 {877856400}
1998-04-05T03:00:00-07:00 [1998-04-05T10:00:00Z] -08:00 -> -07:00 {891770400}
1998-10-25T01:00:00-08:00 [1998-10-25T09:00:00Z] -07:00 -> -08:00 {909306000}
1999-04-04T03:00:00-07:00 [1999-04-04T10:00:00Z] -08:00 -> -07:00 {923220000}
1999-10-31T01:00:00-08:00 [1999-10-31T09:00:00Z] -07:00 -> -08:00 {941360400}
2000-04-02T03:00:00-07:00 [2000-04-02T10:00:00Z] -08:00 -> -07:00 {954669600}
2000-10-29T01:00:00-08:00 [2000-10-29T09:00:00Z] -07:00 -> -08:00 {972810000}
2001-04-01T03:00:00-07:00 [2001-04-01T10:00:00Z] -08:00 -> -07:00 {986119200}
2001-10-28T01:00:00-08:00 [2001-10-28T09:00:00Z] -07:00 -> -08:00 {1004259600}
2002-04-07T03:00:00-07:00 [2002-04-07T10:00:00Z] -08:00 -> -07:00 {1018173600}
2002-10-27T01:00:00-08:00 [2002-10-27T09:00:00Z] -07:00 -> -08:00 {1035709200}
2003-04-06T03:00:00-07:00 [2003-04-06T10:00:00Z] -08:00 -> -07:00 {1049623200}
2003-10-26T01:00:00-08:00 [2003-10-26T09:00:00Z] -07:00 -> -08:00 {1067158800}
2004-04-04T03:00:00-07:00 [2004-04-04T10:00:00Z] -08:00 -> -07:00 {1081072800}
2004-10-31T01:00:00-08:00 [2004-10-31T09:00:00Z] -07:00 -> -08:00 {1099213200}
2005-04-03T03:00:00-07:00 [2005-04-03T10:00:00Z] -08:00 -> -07:00 {1112522400}
2005-10-30T01:00:00-08:00 [2005-10-30T09:00:00Z] -07:00 -> -08:00 {1130662800}
2006-04-02T03:00:00-07:00 [2006-04-02T10:00:00Z] -08:00 -> -07:00 {1143972000}
2006-10-29T01:00:00-08:00 [2006-10-29T09:00:00Z] -07:00 -> -08:00 {1162112400}
2007-03-11T03:00:00-07:00 [2007-03-11T10:00:00Z] -08:00 -> -07:00 {1173607200}
2007-11-04T01:00:00-08:00 [2007-11-04T09:00:00Z] -07:00 -> -08:00 {1194166800}
2008-03-09T03:00:00-07:00 [2008-03-09T10:00:00Z] -08:00 -> -07:00 {1205056800}
2008-11-02T01:00:00-08:00 [2008-11-02T09:00:00Z] -07:00 -> -08:00 {1225616400}
2009-03-08T03:00:00-07:00 [2009-03-08T10:00:00Z] -08:00 -> -07:00 {1236506400}
2009-11-01T01:00:00-08:00 [2009-11-01T09:00:00Z] -07:00 -> -08:00 {1257066000}
2010-03-14T03:00:00-07:00 [2010-03-14T10:00:00Z] -08:00 -> -07:00 {1268560800}
2010-11-07T01:00:00-08:00 [2010-11-07T09:00:00Z] -07:00 -> -08:00 {1289120400}
2011-03-13T03:00:00-07:00 [2011-03-13T10:00:00Z] -08:00 -> -07:00 {1300010400}
2011-11-06T01:00:00-08:00 [2011-11-06T09:00:00Z] -07:00 -> -08:00 {1320570000}
2012-03-11T03:00:00-07:00 [2012-03-11T10:00:00Z] -08:00 -> -07:00 {1331460000}
2012-11-04T01:00:00-08:00 [2012-11-04T09:00:00Z] -07:00 -> -08:00 {1352019600}
2013-03-10T03:00:00-07:00 [2013-03-10T10:00:00Z] -08:00 -> -07:00 {1362909600}
2013-11-03T01:00:00-08:00 [2013-11-03T09:00:00Z] -07:00 -> -08:00 {1383469200}
2014-03-09T03:00:00-07:00 [2014-03-09T10:00:00Z] -08:00 -> -07:00 {1394359200}
2014-11-02T01:00:00-08:00 [2014-11-02T09:00:00Z] -07:00 -> -08:00 {1414918800}
2015-03-08T03:00:00-07:00 [2015-03-08T10:00:00Z] -08:00 -> -07:00 {1425808800}
2015-11-01T01:00:00-08:00 [2015-11-01T09:00:00Z] -07:00 -> -08:00 {1446368400}
2016-03-13T03:00:00-07:00 [2016-03-13T10:00:00Z] -08:00 -> -07:00 {1457863200}
2016-11-06T01:00:00-08:00 [2016-11-06T09:00:00Z] -07:00 -> -08:00 {1478422800}
2017-03-12T03:00:00-07:00 [2017-03-12T10:00:00Z] -08:00 -> -07:00 {1489312800}
2017-11-05T01:00:00-08:00 [2017-11-05T09:00:00Z] -07:00 -> -08:00 {1509872400}
2018-03-11T03:00:00-07:00 [2018-03-11T10:00:00Z] -08:00 -> -07:00 {1520762400}
2018-11-04T01:00:00-08:00 [2018-11-04T09:00:00Z] -07:00 -> -08:00 {1541322000}
2019-03-10T03:00:00-07:00 [2019-03-10T10:00:00Z] -08:00 -> -07:00 {1552212000}
2019-11-03T01:00:00-08:00 [2019-11-03T09:00:00Z] -07:00 -> -08:00 {1572771600}
2020-03-08T03:00:00-07:00 [2020-03-08T10:00:00Z] -08:00 -> -07:00 {1583661600}
2020-11-01T01:00:00-08:00 [2020-11-01T09:00:00Z] -07:00 -> -08:00 {1604221200}
2021-03-14T03:00:00-07:00 [2021-03-14T10:00:00Z] -08:00 -> -07:00 {1615716000}
2021-11-07T01:00:00-08:00 [2021-11-07T09:00:00Z] -07:00 -> -08:00 {1636275600}
2022-03-13T03:00:00-07:00 [2022-03-13T10:00:00Z] -08:00 -> -07:00 {1647165600}
2022-11-06T01:00:00-08:00 [2022-11-06T09:00:00Z] -07:00 -> -08:00 {1667725200}
2023-03-12T03:00:00-07:00 [2023-03-12T10:00:00Z] -08:00 -> -07:00 {1678615200}
2023-11-05T01:00:00-08:00 [2023-11-05T09:00:00Z] -07:00 -> -08:00 {1699174800}
2024-03-10T03:00:00-07:00 [2024-03-10T10:00:00Z] -08:00 -> -07:00 {1710064800}
2024-11-03T01:00:00-08:00 [2024-11-03T09:00:00Z] -07:00 -> -08:00 {1730624400}
2025-03-09T03:00:00-07:00 [2025-03-09T10:00:00Z] -08:00 -> -07:00 {1741514400}
2025-11-02T01:00:00-08:00 [2025-11-02T09:00:00Z] -07:00 -> -08:00 {1762074000}
2026-03-08T03:00:00-07:00 [2026-03-08T10:00:00Z] -08:00 -> -07:00 {1772964000}
2026-11-01T01:00:00-08:00 [2026-11-01T09:00:00Z] -07:00 -> -08:00 {1793523600}
2027-03-14T03:00:00-07:00 [2027-03-14T10:00:00Z] -08:00 -> -07:00 {1805018400}
2027-11-07T01:00:00-08:00 [2027-11-07T09:00:00Z] -07:00 -> -08:00 {1825578000}
2028-03-12T03:00:00-07:00 [2028-03-12T10:00:00Z] -08:00 -> -07:00 {1836468000}
2028-11-05T01:00:00-08:00 [2028-11-05T09:00:00Z] -07:00 -> -08:00 {1857027600}
2029-03-11T03:00:00-07:00 [2029-03-11T10:00:00Z] -08:00 -> -07:00 {1867917600}
2029-11-04T01:00:00-08:00 [2029-11-04T09:00:00Z] -07:00 -> -08:00 {1888477200}
2030-03-10T03:00:00-07:00 [2030-03-10T10:00:00Z] -08:00 -> -07:00 {1899367200}
2030-11-03T01:00:00-08:00 [2030-11-03T09:00:00Z] -07:00 -> -08:00 {1919926800}
2031-03-09T03:00:00-07:00 [2031-03-09T10:00:00Z] -08:00 -> -07:00 {1930816800}
2031-11-02T01:00:00-08:00 [2031-11-02T09:00:00Z] -07:00 -> -08:00 {1951376400}
2032-03-14T03:00:00-07:00 [2032-03-14T10:00:00Z] -08:00 -> -07:00 {1962871200}
2032-11-07T01:00:00-08:00 [2032-11-07T09:00:00Z] -07:00 -> -08:00 {1983430800}
2033-03-13T03:00:00-07:00 [2033-03-13T10:00:00Z] -08:00 -> -07:00 {1994320800}
2033-11-06T01:00:00-08:00 [2033-11-06T09:00:00Z] -07:00 -> -08:00 {2014880400}
2034-03-12T03:00:00-07:00 [2034-03-12T10:00:00Z] -08:00 -> -07:00 {2025770400}
2034-11-05T01:00:00-08:00 [2034-11-05T09:00:00Z] -07:00 -> -08:00 {2046330000}
2035-03-11T03:00:00-07:00 [2035-03-11T10:00:00Z] -08:00 -> -07:00 {2057220000}
2035-11-04T01:00:00-08:00 [2035-11-04T09:00:00Z] -07:00 -> -08:00 {2077779600}
2036-03-09T03:00:00-07:00 [2036-03-09T10:00:00Z] -08:00 -> -07:00 {2088669600}
2036-11-02T01:00:00-08:00 [2036-11-02T09:00:00Z] -07:00 -> -08:00 {2109229200}
2037-03-08T03:00:00-07:00 [2037-03-08T10:00:00Z] -08:00 -> -07:00 {2120119200}
2037-11-01T01:00:00-08:00 [2037-11-01T09:00:00Z] -07:00 -> -08:00 {2140678800}
2038-03-14T03:00:00-07:00 [2038-03-14T10:00:00Z] -08:00 -> -07:00 {2152173600}
2038-11-07T01:00:00-08:00 [2038-11-07T09:00:00Z] -07:00 -> -08:00 {2172733200}
2039-03-13T03:00:00-07:00 [2039-03-13T10:00:00Z] -08:00 -> -07:00 {2183623200}
2039-11-06T01:00:00-08:00 [2039-11-06T09:00:00Z] -07:00 -> -08:00 {2204182800}
2040-03-11T03:00:00-07:00 [2040-03-11T10:00:00Z] -08:00 -> -07:00 {2215072800}
2040-11-04T01:00:00-08:00 [2040-11-04T09:00:00Z] -07:00 -> -08:00 {2235632400}
2041-03-10T03:00:00-07:00 [2041-03-10T10:00:00Z] -08:00 -> -07:00 {2246522400}
2041-11-03T01:00:00-08:00 [2041-11-03T09:00:00Z] -07:00 -> -08:00 {2267082000}
2042-03-09T03:00:00-07:00 [2042-03-09T10:00:00Z] -08:00 -> -07:00 {2277972000}
2042-11-02T01:00:00-08:00 [2042-11-02T09:00:00Z] -07:00 -> -08:00 {2298531600}
2043-03-08T03:00:00-07:00 [2043-03-08T10:00:00Z] -08:00 -> -07:00 {2309421600}
2043-11-01T01:00:00-08:00 [2043-11-01T09:00:00Z] -07:00 -> -08:00 {2329981200}
2044-03-13T03:00:00-07:00 [2044-03-13T10:00:00Z] -08:00 -> -07:00 {2341476000}
2044-11-06T01:00:00-08:00 [2044-11-06T09:00:00Z] -07:00 -> -08:00 {2362035600}
2045-03-12T03:00:00-07:00 [2045-03-12T10:00:00Z] -08:00 -> -07:00 {2372925600}
2045-11-05T01:00:00-08:00 [2045-11-05T09:00:00Z] -07:00 -> -08:00 {2393485200}
2046-03-11T03:00:00-07:00 [2046-03-11T10:00:00Z] -08:00 -> -07:00 {2404375200}
2046-11-04T01:00:00-08:00 [2046-11-04T09:00:00Z] -07:00 -> -08:00 {2424934800}
2047-03-10T03:00:00-07:00 [2047-03-10T10:00:00Z] -08:00 -> -07:00 {2435824800}
2047-11-03T01:00:00-08:00 [2047-11-03T09:00:00Z] -07:00 -> -08:00 {2456384400}
2048-03-08T03:00:00-07:00 [2048-03-08T10:00:00Z] -08:00 -> -07:00 {2467274400}
2048-11-01T01:00:00-08:00 [2048-11-01T09:00:00Z] -07:00 -> -08:00 {2487834000}
2049-03-14T03:00:00-07:00 [2049-03-14T10:00:00Z] -08:00 -> -07:00 {2499328800}
2049-11-07T01:00:00-08:00 [2049-11-07T09:00:00Z] -07:00 -> -08:00 {2519888400}
2050-03-13T03:00:00-07:00 [2050-03-13T10:00:00Z] -08:00 -> -07:00 {2530778400}
2050-11-06T01:00:00-08:00 [2050-11-06T09:00:00Z] -07:00 -> -08:00 {2551338000}

Here's the Chronos code that generates the list of offset transitions:
  | transition prevOffset printPolicy |
printPolicy := ChronosPrintPolicy iso8601.
transition := Timepoint year: 1881 day: 1 timeZone: #'America/Los_Angeles'.
[prevOffset := transition offset.
transition := transition nextOffsetTransitionDateAndTimeIfNone: [].
transition == nil or: [transition year > 2050]]
whileFalse:
[Transcript
cr; show: transition printString;
tab; show: ' ['; show: transition asUT % printPolicy; show: ']';
tab; show: prevOffset timeZoneOffsetPrintString;
show: ' -> '; show: transition offset timeZoneOffsetPrintString;
tab; show: ' {';
show: (transition secondsSince: ChronosSystemClock unixEpoch) printString;
show: '}'].



2007-02-02

Why don’t calendars do Time Zones?

Jim Phelps asks (2006-01-18) "Why don’t calendars do Time Zones?"

He laments "My laptop and my palm both understand Time Zones. I understand Time Zones. Why don’t my calendar applications (Oracle’s Calendar and the Palm Calendar in the handheld) understand Time Zones?"

Jim has the following "simple" requests:


  1. When I create an appointment I should be able to mark the Time Zone for the appointment.

  2. I should also be able to make appointments that are Time Zone neutral - not tied to a Time Zone.

  3. My clients (Palm and Desktop and Web) should all understand Time Zones and should be able to shift the alarms to compensate for my changes in Time Zone.

Here's how Jim would use such functionality, were it only available:

  • If I get an invite to join a conference call at 11AM EST, I could just enter that time without adjusting for my local time zone. Same with UTC time.

  • If I changed time zones (say fly from Madison to San Francisco), my alarms would change to be appropriate. As it is now, if I fly to California, I need to keep track of the fact that the 10AM meeting is really a[t] 10AM Central time so I need to set an alarm 2 hours earlier. But I can’t do a global change because some things might be dinners in California so they need to stay on Pacific time.

Of course, Jim's not the only one whose Use Cases aren't well satisfied by most current applications and/or date time libraries. For example, a few years ago, some date/time Use Cases were posted on Zope.org, because Zope's date/time functionality was seen as unsatisfactory. And on BoingBoing, there was the rant "Extended iCal rant from a timezone warrior," whose basic complaint resembles Jim's. There was also recently a discussion on Bugzilla where some of the same issues and concerns were raised.

Here are the key requirements that can be abstracted from the aforementioned discussions/rants:
  • It must be possible to associate each point-in-time value with a time zone that may or may not be the same as the time zone associated with other point-in-time values.
  • It must be possible to specify a point-in-time without reference or association to any particular time zone. (Examples: The point-in-time that specifies the first moment of 2008 (for any and all time zones,) the annual date on which a person's birthday is celebrated, the list of non-business days of the US Federal government, the date on which a person must have been born in order to legally purchase alcohol today.)
  • Point-in-time values must either know, or be able to derive, both their local time and their Universal Time.
  • It must be possible to convert point-in-time values from one time zone to another.
  • The same point-in-time value must be able to act as though it is associated with ("local to") a different time zone in different contexts (e.g., the possibly-different local time zone of different users at the same time, and also the local time zone of the same user at different times, even when the user's local time zone changes as he travels from one location to another.)
  • Point-in-time values should provide both sufficient sub-second resolution and sufficient range (from earliest to latest representable value.)
  • Point-in-time values should provide appropriate granularities--timestamps should span a reasonably small sub-second duration, but dates should span a calendar day (and not be sub-second-resolution timestamps that happen to specify the first moment of the day.)
  • Point-in-time values must be immutable so that changes to their value don't invalidate the logic that uses them (e.g., they must be useable as dictionary keys.)
  • Adding any combination of some number of days, months and years to a point-in-time value should result in a new point-in-time value that number of days/months/years distant--but having the same civil time of day, regardless of any DST transitions that may have occurred.
  • It must be possible specify partial/recurring dates and times (e.g., "every/any day at 5pm," "the last Sunday of October every/any year.")


I was especially interested in what one of the Zope developers had to say in response to the Zope Use Cases posted by the general public (spelling and punctuation as in the original):

"I find all of that very allarming.

Do people want the datetime object solve all this use cases out of the box? I hope that they are only samples of applications and that people agree that they will have to do a little work by theimself.

It is already difficult to find a straightforward interface for basic operations, if we wait to have an universal datetime type, we will never have it before Python 48.12b1 release.

So please, go for a minimal API, and let people play with the type and discover the better way to do elaborated stuff.

By the way from the tz database README file at: http://www.twinsun.com/tz/tz-link.htm you can't guess a time zone from a time-zone offset and a daylight saving flag.

So I think that a full and cross-platform timezone support is just a wonderful dream. But if you can prove me that I'm false, with an actual implementation ..."


I'm quite sure that many programmers would have a similar reaction: They'd be highly alarmed. Well, tough. People don't care how you solve their problems, they just want them solved. A solution that doesn't work right can be worse (or no better than) not having any solution at all.

We've had "a minimal API" for date/time computations available in just about every programming language and operating system for decades now--but the requests, complaints and rants shown above are from recent times, not from decades past. It's almost universally true that programming languages, operating systems and applications either don't handle dates/times at all, or don't do so correctly and consistently, and don't satisfy most of the requirements discussed above.

"Do the simplest thing that could possibly work" is not a license to provide incomplete and/or incorrect functionality. Real use cases that are commonly encountered are not being satisfied. The first step to a cure is to admit there's a problem.

Dates and times are not simple. Not at all. They're a relatively hard problem. The truth is, dates and times are too hard for most programmers to handle correctly on their own--which is precisely why they don't do it, and instead attempt to justify their failure by misapplying design principles. And that's why the "provide the simple stuff, and let the application coders solve the hard problems" approach won't work. It doesn't work in other domains, either--not in the past, not now, and probably not ever.

The "let them do it themselves" approach is about as wise as letting each application programmer code his own number classes, his own collection classes, his own filesystem, his own garbage collection engine, his own virtual memory subsystem, his own graphics library and GUI framework, his own web/application server--and in his spare time, develop his own programming language and compiler. If you really feel that a date/time library that actually gets the job done would be just too complex, then to be consistent, you would have to raise the same objection to all the other tools that programmers don't do themselves anymore (because the problems are hard, and most programmers will take unwise shortcuts, or make serious errors, if they have to do it themselves.)

As time has gone by, we've gone from machine language, to assembly language, to procedural languages, to functional languages, to object-oriented languages. We've gone from no operating system, to reusable, statically-linked code libraries, to dynamically-linked code libraries, to run time systems, to basic operating systems, to operating systems with virtual memory, to operating systems with GUIs. We've gone from punched cards to Microsoft Word, and from the abacus to Microsoft Excel.

Does anyone see a pattern here? Yes, you have to walk before you can run. But we've been crawling around trying to avoid actually dealing with dates and times in all their glory for far too long now. It's time to advance to the next level. So, to the programmers of the world, I say: Admit it. Admit that you're not satisfying the real date/time use cases.

As for an actual implementation of a date/time library that satisfies the requirements we've been discussing, it happens that there is at least one: The Chronos Date/Time Library. Of course, it's a date/time library, not a calendaring/scheduling application, so it would be more accurate to say it makes it much easier to write applications with just about all of the requested features. Yes, applications do need to take some responsibility for their own particular use cases.

What are the features of Chronos that satisfy (or greatly help to satisfy) the requirements discussed above? They are as follows:

  1. Chronos uses the Olson Time Zone Database, so it knows about all the world's time zones--including historical information. For example, Chronos knows, and is able to correctly handle, all the following facts:
    • Most (but not all!) locations in North America have been switching from standard time to daylight saving time on the first Sunday of April each year, from 1987 through 2006--but starting in 2007, most North American locations will switch from standard time to daylight saving time on the second Sunday of March.
    • All the countries in the European Union modernly transition to and from daylight saving time at the same moment in Universal Time--unlike the case in North America, where all zones with the same offset transition to/from daylight saving time at the same local time, but at a different moment in Universal Time.
    • All of India uses the same time zone offset, does not observe daylight saving time, and uses an offset of 5.5 hours east of Universal Time.
    • In Australia, South America, New Zealand and Africa, daylight saving time, if it is observed at all, is observed during the Southern Hemisphere's summer (for example, from September to April.)
    • During World War II, several countries were on "daylight saving time" all year round for several years in a row (in the US, this was called "War Time," and was abbreviated as "EWT," "CWT," "MWT" and "PWT.")
    • For the years 1921 and 1922 only, Moscow started the year with an offset of 3 hours, transitioned to an offset of 4 hours on 1920-02-24T23:00 and 1921-02-24T23:00, transitioned to an offset of 5 hours on the 79th day of the year (different dates and day-of-the-week each year,) transitioned back to an offset of 4 hours on the 244th day of the year, and then transitioned back to an offset of 3 hours on the 274th day of the year (so there were 4 offset transitions and 3 different offsets each year.)

  2. In addition to the predefined time zones that come from the information provided by the Olson Time Zone Database, Chronos permits you to define your own time zones--which can be as simple as "-5 hours asTimezone" or as complex as any of the cases described in the preceding bullet item. Or you can easily construct a Chronos time zone from either a POSIX time zone rule literal or from the information in the Windows registry--and it will behave identically to its UNIX or Windows counterpart.

  3. The Chronos Time Zone Repository (which is generated from the Olson Time Zone Database) is deployed separately and independently from the Chronos codebase. Either can be changed without any need to redeploy the other--and even already-running applications can see and use a newly-deployed version of the time zone repository. And both Chronos and the Chronos Time Zone Repository are available for Windows, Mac, Unix and Linux--so your applications will not only run unchanged in all those environments, but will exhibit identical date/time behavior.

  4. Chronos point-in-time values can be associated with ("bound to" in Chronos terminology) a particular time zone. Or, they can be bound to a proxy time zone that dynamically refers to a different time zone at different times or in different contexts (so that the associated point-in-time's local time changes dynamically whenever the proxy time zone is changed to have a different time zone as its referent.) Or, Chronos point-in-time values can be bound to a special time zone that Chronos refers to as "nominal time." Nominal time represents the concept of "any time zone," or "local time in some unspecified context, or in any and all contexts simultaneously."

  5. Chronos point-in-time values that are bound to a specific time zone or to a proxy time zone (and so aren't bound to nominal time) are said to be invariant to Universal Time. Chronos point-in-time values that are bound to nominal time are said to be invariant to nominal time. Point-in-time values that are invariant to Universal Time keep the moment in time that they represent in Unversal Time as their semantic invariant. Point-in-time values that are invariant to nominal time keep the moment in time that they represent in nominal time (their "local time") as their semantic invariant. In other words, two points-in-time that are invariant to Universal Time are equal when they represent the same moment in Universal Time, regardless of the moment they nominally specify in their local time zone (the one to which they are bound.) But a point-in-time that is invariant to nominal time is equal to any other point-in-time that specifies the same nominal (local) time. So the following expressions both evaluate to true:
    • (Timepoint 
      year: 2007 month: 2 day: 3
      hour: 10 minute: 0 second: 0
      timeZone: -8 hours)
      = (Timepoint
      year: 2007 month: 2 day: 3
      hour: 13 minute: 0 second: 0
      timeZone: -5 hours)
      "10 am in California is the same moment
      in Universal Time as is 1pm in New York"
    • (Timepoint 
      year: 2007 month: 2 day: 3
      hour: 13 minute: 0 second: 0
      timeZone: Timezone nominal)
      = (Timepoint
      year: 2007 month: 2 day: 3
      hour: 13 minute: 0 second: 0
      timeZone: -5 hours)
      "1 pm nominal time is 1pm local time,
      regardless of time zone"

  6. Chronos point-in-time values that are invariant to Universal-Time internally store their value in Universal Time, but report their year, month, day, hour, minute and second according to the equivalent local time in the time zone with which they are associated. Also, the local time values for their year, month and day-of-month are cached (lazily computed when needed--it's an expensive computation.)

  7. Chronos point-in-time values can easily (and efficiently) be converted from any time zone to any other:
    (Timepoint 
    year: 2007 month: 2 day: 3
    hour: 13 minute: 0 second: 0
    timeZone: 'Pacific/Honolulu') >> #'Asia/Katmandu'
    results in 2007-02-04T04:45:00+05:45 (and yes, Asia/Katmandu actually does have an offset of 5 hours 45 minutes.)

  8. Chronos point-in-time values have no limits (other than available memory on your computer) with respect to the range of representable dates--a feature that derives mostly from the fact that Chronos is implemened in Smalltalk--although, even if the implementation language had limited the design to using nothing but 32-bit signed integers, the way Chronos internally represents point-in-time values would still have supported a range of +/- 6 million years for timestamps (and +/- 2 billion years for dates.) Chronos also provides a special value that represents the infinite past, and another that represents the infinite future.

  9. Chronos point-in-time values are actually time intervals, as explained in the Chronos blog entry Chronos 101: "Points" in Time. Chronos points-in-time that are meant to represent dates have a temporal extent (and hence resolution) of one calendar day. Chronos points-in-time that are meant to be used as timestamps have a temporal extent (and hence resolution) of one nanosecond. In addition to these two common cases (one optimized for dates, the other for timestamps,) Chronos provides general Timeperiod values, which can start at any point in time, and can have any temporal extent/duration.

  10. Chronos point-in-time, durational and time interval values are all immutable.

  11. Chronos handles date/time arithmetic correctly, satisfying both civil and scientific/technical use cases. Adding a day results in the same civil time of day on the next calendar day.

  12. Chronos provides a variety of classes for representing partial/recurring dates--including the time-of-day without any associated date, and the month/day without any specified year. You can even construct a value that specifies "the first Tuesday of November, every fourth year modulo 4."

And there's yet more. If you're interested, you can peruse the Chronos web site, browse the Chronos blog, or read the "Chronos 101" tutorials, of which the following have been published so far:

So, to answer Jim's original question, calendar applications don't understand time zones because most people, including software developers, programming language library creators and programming language designers don't understand time zones. Or in some cases, they understand them well enough, but decide (for whatever reason) that full and correct time zone behavior is more work than they want to take on. Fortunately, that unwillingness to tackle the date/time domain comprehensively is not universal.


2007-01-31

Filenames and Inter-Smalltalk Portability

Troy Brumley, in his blog post File access demo from VW to Squeak (2006-06-03), picks up on some example VisualWorks code posted by James Robertson a day earlier (Simple File I/O Demo, 2006-06-02.) Troy's examples show how to code the same thing in Squeak.

But there is another option: Use the Passport inter-Smalltalk portability library that was implemented in order to make it possible to host The Chronos Date/Time Library on VisualWorks, Squeak and Dolphin. Using Passport, the code will work unchanged in VisualWorks, Squeak and Dolphin.

Here's the Passport version (with Jim's original variable names unchanged, even though they aren't the best names for use with Passport):

"write a simple file"
file := 'myTestFile.txt' asResourcePath.
stream := file writeStream.
stream nextPutAll: 'Line 1'.
stream nextPut: Character cr.
stream nextPutAll: 'Line 2'.
stream nextPut: Character cr.
stream nextPutAll: 'Line 3'.
stream nextPut: Character cr.
stream close.

"read the entire file"
file := 'myTestFile.txt' asResourcePath.
contents := file value.
^contents.

"read line by line"
file := 'myTestFile.txt' asResourcePath.
stream := file readStream.
lines := OrderedCollection new.
[stream atEnd]
whileFalse: [| line |
line := UtilityFunction nextLineFrom: stream.
lines add: line].
stream close.
^lines.

"finding the file"
directory := '.' asResourcePath.
files := OrderedCollection new.
directory contentsDo: [:resourcePath | ('myTest*' match: resourcePath suffixString) ifTrue: [files add: resourcePath]].
^files.

(To see Jim's original VW code, follow this link: Simple File I/O Demo (VW code))

Passport not only makes it possible to write the same file name logic portably among different Smalltalk versions, it also makes it possible to use the same code regardless of whether the host operating system is Unix, MacOS X or Windows. But to do that, there are some constraints:

Firstly, either you can't use absolute pathnames, or else the absolute path must be constructed at run time by appending a well-known path suffix onto a path prefix that is supplied as a parameter at run time (and which will necessarily differ from one host OS to another, and often also even between different computers, even when they all use the same OS.)

Secondly, the relative path suffix must be constructed using a Pathname, as in the following example:
| resourcePath stream |
resourcePath := (Pathname fromString: 'test/folder1') asResourcePath.
resourcePath makeDirectory.
resourcePath := resourcePath, 'junk.txt'.
"The ResoucePath is now [./test/folder1/junk.txt]"
stream := resourcePath newWriteStream.
stream nextPutAll: 'This is a test.'.
stream close.


Typically, one would construct a ResourcePath using a path prefix obtained from your application's configuration parameters, using a well-known (or deterministically computable) path suffix. For example, the Chronos Date/Time Library might construct the path to a Chronos time zone ruleset file as follows:

(ResourcePath
namespace:
(EnvironmentFacade current
valueOfEnvironmentVariableAt: 'CHRONOS_PATH')
pathname:
(Pathname
fromString: 'time-zones/rulesets/Pacific/Honolulu'))
appendingExtension: 'tzn'

On the Windows machine I use for Chronos development, doing a "print it" on the above example would have the following result: H:\Dev\Smalltalk\Chronos\Chronos Versions\VisualWorks\Chronos\time-zones\rulesets\Pacific\Honolulu.tzn.

The Squeak version of Passport is available as two of the files in the version of Chronos.zip distributed for Squeak (namely, "Passport-Kernel.st" and "Passport-Squeak.st.") It's also available from SqueakSource (in the Chronos project.)

The VisualWorks version can be obtained from the Cincom Public StORE. It can also be filed out or parcelled out after installing the VisualWorks version of Chronos (it's in the packages Passport-Kernel and Passport-Kernel-VW.)

The Dolphin version of Passport is available on request (requests (at) chronos-st (dot) org).


2007-01-24

Chronos B1.196 Published on SqueakSource (Monticello Package)

Chronos B1.196 is now available on SqueakSource.

For more information on Chronos B1.196, see the Chronos B1.196 publication announcement.

Chronos on SqueakSource is packaged as 6 separate Monticello packages, which physically are contained in six different *.mcz files. Unfortunately, the package version must be encoded in the filename, so the filename changes with each new version. The 6 packages, and the filenames of their current versions as of this writing (2007-01-24T04:05Z,) are listed below:









Package NameMonticello Filename
PassportPreamblePassportPreamble-B1.5.mcz
PassportPassport-B1.6.mcz
ChronosPreambleChronosPreamble-B1.2.mcz
ChronosChronos-B1.196.mcz
ChronosPostscriptChronosPostscript-B1.4.mcz
ChronosSqueakPost36OnlyChronosSqueakPost36Only-B1.3.mcz


The detailed installation instructions are presented below. They can also be found on the SqueakSource "Wiki" page for the Chronos project. They ought to reside on the main page of the Chronos project on SqueakSource, but since I'm not the administrator, I can't put them there.

Detailed Installation Instructions


First, download the Chronos Time Zone Repository, and install it according to the Chronos installation instructions (which have not yet been updated with any SqueakSource-specific infomration.)

The following packages must be installed in the specified order (and any packages not mentioned should be ignored):

1. Install the package PassportPreamble (The filename will be of the form "PassportPreamble-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

2. Install the package Passport (The filename will be of the form "Passport-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

NOTE: The first two packages comprise the "Passport" inter-smalltalk portability library that is used by Chronos (and was in fact developed for use by Chronos.) Passport might prove useful for other applications and/or class libraries that need to operate on more than one Smalltalk platform.

3. Install the package ChronosPreamble (The filename will be of the form "ChronosPreamble-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

4. Install the package Chronos (The filename will be of the form "Chronos-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

5. Install the package ChronosPostscript (The filename will be of the form "ChronosPostscript-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

6. IF AND ONLY IF you are installing Chronos in a Squeak image whose version > 3.6, then install the package ChronosSqueakPost36Only (The filename will be of the form "ChronosSqueakPost36Only-SV.B.mcz", where "S" is one of "A" (alpha), "B" (Beta) or "R" (Release,) "V" is the major version (release) number, and "B" is the build number.)

Usually, the package version with the highest version (release) and build number should be chosen (so choose "Chronos-B1.190" over "Chronos-B1.188".)
__________________________________________________
WARNING: The initial version, dated 2006-02-19 and labelled "Chronos.B1.15-avi*", is only partially functional, and worse, will break your image if you're using any version of Squeak later than 3.6!