Mac OS X and WA Daylight Saving Time

Overview

The (re-)introduction of daylight saving in Western Australia is causing noticeable grief for IT staff across the state, due to the very short lead time provided by our ever-so-wise political leadership. Given the timeframe we are presented with, it is unlikely that we will see full and complete timezone patches from vendors Apple. This applies to both operating systems, server products and end-user applications.

This document is intended to highlight and address some of these issues in FAHSS - much of our infrastructure is Mac OS X-based, and we do not expect to see a patch released by Apple before December 3. It is not intended to be a "how-to" document detailing what needs to be done to fix an OS X machine to respect WA DST. Apple sources have informed us that the fix will not be released until the 10.4.9 patch; given that 10.4.9 is not yet even released to ADC Select or Premier members, I'd put money on it not arriving until 2007. We also have been advised that there will not be any updates for 10.3. At all.

On Mac OS X, there are numerous main methods for obtaining timezone information. The first two are both generated from the standard POSIX time zone file:

The compiled POSIX data files are relatively simple to generate; however, the ICU files are "less trivial". Java timezones I've not explored - only mentioned due to reference in the Wikipedia article; will be examining in more detail later.

POSIX Timezones

Updated timezone file, based on the same source zonefiles as used in 10.4.x (compiled zoneinfo files located in /usr/share/zoneinfo):

	ftp://elsie.nci.nih.gov/pub/tzdata2006o.tar.gz		raw text timezone information files

ftp://elsie.nci.nih.gov/pub/tzcode2006o.tar.gz tzcode utility source

Don't ask why the US National Cancer Institute is the authoritative source of international timezone information - I don't have an answer to that.

Update: Filed the POSIX timezone file with NCI on 27 November 2006, 13:41 WAST.

Update: There's an updated timezone file available from NCI (version 2006p) that has updated DST info for WA. I'm gratified that my submitted information looks almost identical to the new data in the australasia file (the current data is from an independent source) - at least I know I wasn't completely off track :-)

Matt@ucc was on the right track with his fix that was posted to tech-contacts, but (arguably) the best way to fix this part of the problem is to adapt the existing raw australasia timezone file in the tzdata2006o folder  - change the "Western Australia" section (it's very close to the top of the file) as follows (download):

	# Western Australia
	# Rule	NAME	FROM	TO	TYPE	IN	ON		AT		SAVE	LETTER/S
		Rule	AW	1974	only	-	Oct	lastSun	2:00s		1:00	D
		Rule	AW	1975	only	-	Mar	Sun>=1	2:00s		0	W
		Rule	AW	1983	only	-	Oct	lastSun	2:00s		1:00	D
		Rule	AW	1984	only	-	Mar	Sun>=1	2:00s		0	W
		Rule	AW	1991	only	-	Nov	17 	2:00s		1:00	-
		Rule	AW	1992	only	-	Mar	Sun>=1	2:00s		0	-
		Rule	AW	2006	only	-	Dec	Sun>=1	2:00s		1:00	-
		Rule	AW	2007	2008	-	Oct	lastSun	2:00s		1:00	-
		Rule	AW	2007	2009	-	Mar	lastSun	2:00s		0	-
		
	# Zone	NAME			GMTOFF	RULES		FORMAT	[UNTIL]
	Zone Australia/Perth		7:43:24	-		LMT		1895 Dec
					8:00	Aus		WST		1974 Oct
					8:00	AW		WST

Now update the existing zonefile based on the updated australasia raw file and make sure the local time is set as expected:

	$ sudo -s
	# tar -cf australasia-backup.tar /usr/share/zoneinfo/Australia
	# zdump -v australasia
	/etc/localtime  australasia Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 20:45:52 1901 UTC isdst=0
	/etc/localtime  australasia Sat Dec 14 20:45:52 1901 UTC = Sat Dec 14 20:45:52 1901 UTC isdst=0
	/etc/localtime  australasia Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 03:14:07 2038 UTC isdst=0
	/etc/localtime  australasia Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 03:14:07 2038 UTC isdst=0
	# sudo zic -l Australia/Perth australasia

Once the timezone information has been updated, run zdump to verify that the system knows about both the forward and reverse transitions (line breaks added to show the clock transitions):

	$ zdump -v /etc/localtime | egrep 200[6789]
	/etc/localtime  Sat Dec  2 17:59:59 2006 UTC = Sun Dec  3 01:59:59 2006 WST isdst=0
	/etc/localtime  Sat Dec  2 18:00:00 2006 UTC = Sun Dec  3 03:00:00 2006 WST isdst=1
/etc/localtime  Sat Mar 24 17:59:59 2007 UTC = Sun Mar 25 02:59:59 2007 WST isdst=1 /etc/localtime  Sat Mar 24 18:00:00 2007 UTC = Sun Mar 25 02:00:00 2007 WST isdst=0
/etc/localtime  Sat Oct 27 17:59:59 2007 UTC = Sun Oct 28 01:59:59 2007 WST isdst=0 /etc/localtime  Sat Oct 27 18:00:00 2007 UTC = Sun Oct 28 03:00:00 2007 WST isdst=1
/etc/localtime  Sat Mar 29 17:59:59 2008 UTC = Sun Mar 30 02:59:59 2008 WST isdst=1 /etc/localtime  Sat Mar 29 18:00:00 2008 UTC = Sun Mar 30 02:00:00 2008 WST isdst=0
/etc/localtime  Sat Oct 25 17:59:59 2008 UTC = Sun Oct 26 01:59:59 2008 WST isdst=0 /etc/localtime  Sat Oct 25 18:00:00 2008 UTC = Sun Oct 26 03:00:00 2008 WST isdst=1
/etc/localtime  Sat Mar 28 17:59:59 2009 UTC = Sun Mar 29 02:59:59 2009 WST isdst=1 /etc/localtime  Sat Mar 28 18:00:00 2009 UTC = Sun Mar 29 02:00:00 2009 WST isdst=0

You should now be able to use System Preferences to set the time manually to 1:58am, 3 Dec 2006 and watch the analog clock tick over from 2:00am to 3:00am (in fact, it usually takes place 5-10 seconds before one would expect; not sure if this is a bug or a "conservative implementation". 

Note that the "tzdata..." file is the essentially the same data file used in 10.4. If you're sceptical, grab the australasia file, run "zic -d dir tzdata2006o/australasia" and compare the md5 checksums between the compiled output in ./dir and the versions in /usr/share/zoneinfo. To be precise, 10.4.8 is using version 2006a (see /usr/share/zoneinfo/+version), but the checksum match is also evidence of  no changes to Australian timezone information between versions 2006a and 2006o.

Finally, it should be noted that the linked Australasia zone file should be also able to be used on other UNIX-based systems (some adaptation may be required depending on the OS.)

ICU Timezones

For the higher level APIs [1], ICU is used to provide internationalised timezone support. If the ICU data files aren't also fixed, then the behaviour of your OS is defined to be undefined :-) AFAICT, this is the primary cause of the problem with iCal's "off-by-one" (hour) error and the menubar clock not showing the correct time.[2]

From the original 10.4 release notes (CoreFoundation release notes)

CFCalendar (Section added since WWDC)

CFCalendar is a new API for Mac OS X 10.4, contained in CFCalendar.h. CFCalendar allows you to ask for numeric properties of a calendar, convert between CFAbsoluteTimes and decomposed unit representations, and perform some types of calendrical arithmetic. Like CFLocale, CFDateFormatter, and CFNumberFormatter, the CFCalendar API is based on the open-source ICU (International Components for Unicode) library, and its behavior follows the behavior of the ICU library (currently in version 3.2 on Mac OS X 10.4). CFCalendar is toll-free bridged with the NSCalendar API in Cocoa's Foundation framework.

Calendars are created using the calendar identifiers in CFLocale.h, and only those identifiers are supported. You cannot define your own calendars with CFCalendar. The "current calendar" returned by CFCalendarCopyCurrent() is the user's preferred calendar configured with the user's locale and the default time zone. The default locale for a CFCalendar is the System Locale (CFLocaleGetSystem()).

Note: in ICU 3.2 the Chinese calendar is currently unimplemented, so it is also unimplemented in the CFCalendar, and related, APIs. (Results are undefined.)

You can change some properties of a CFCalendarRef (locale, time zone, first day of the week, and the minimum number of days for a week to be the first week of the year). However, these are just a convenience for setting parameters to the calendrical calculations, and do not change the CFCalendarRef, say, for purposes of equality testing.

[snip]

iCal (amongst other Cocoa applications) relies on Foundation=>CoreFoundation=>ICU for timezone support - not an internal timezone database - and it definitely needs working timezone support, so if the ICU information if b0rked, then iCal will be too (although contrary to some reports, fixing the POSIX information "properly" doesn't cause iCal to crash - events do show up out by an hour however.) As I can gather, ICU is necessary for international calendar support, since not everyone in the world uses the Gregorian calendar. [There's nothing wrong with POSIX per se, unless you want to support users with bi-di text, different calendars and multibyte non-Roman charsets. Then POSIX and C style strings - not so much fun :-)]

Instructions:

Download tarball appropriate for your platform (see notes [3][4]) - tarballs of ICU for Mac OS X available at OpenDarwin site.

Intel source code

PowerPC source code

	$ tar -zxvf ICU-6.2.*gz
	$ cd ICU*/icuSources
	$ ./runConfigureICU MacOSX
	$ make
	$ sudo make install

That does actually install stuff; however, it doesn't all work. For example, the tzcode tool in icuSources/tools/tzcode isn't actually built as part of the install. Apparently one needs to download the additional POSIX timezone code from the NCI FTP server (the tzcode2006<version>.tar.gz file.) Unfortunately, following the instructions in the readme file is essentially counterproductive: there's a lot of different makefile targets once you have all the files as requested, but they all depend upon localtime.c - which won't build. Additionally, there's a required patch for zic.c:

3. Apply the ICU patch to zic.c:

$ patch < patch-icu-tzcode

If patch complains at this point, there is a mismatch that must be manually addressed.  See the CVS log of `patch-icu-tzcode' for version details.

The "fix for the patch" is apparently buried somewhere in the CVS logs for the ICU project. Given that there are 20,000+ commits on the project (http://source.icu-project.org/vc/icu/trunk/source/tools/tzcode/), that's when I decided a bug report was likely to be more friendly to my sanity :-)

Update 1: Well, I'm back trying to beat ICU into submission, with a little more success today...turns out we can't expect a fix from Apple for any of our 10.3 machines, so that leaves fixing the problem squarely in my court. More info when I have anything definite.

Update 2: managed to recreate the /usr/lib/libicucore.A.dylib library from scratch - I don't think I need a new version, but it's helping my understanding a bit more. md5 hashes of the original library and my version don't match, but the hash of /usr/bin/strings for each version does match. That's good enough in my book; I'll put the mismatch down to minor compile-time differences.

Update 3: I've got a "pulled-apart" version of /usr/lib/icu/icudt32l.dat after (re-)beating ICU according to the updated note [4] below. The critical file that needs to be updated in this tree is zoneinfo.res. After going through http://icu.sourceforge.net/userguide/icudata.html (again!), it states:

Time zone data icu/source/data/misc/zoneinfo.txt : ftp://elsie.nci.nih.gov/pub/ tzdata<year> zoneinfo.res (generated by genrb and source/tools/tzcode/tz.pl)

Interpretation: ICU's zoneinfo.res file is a binary file. This binary file is generated by the genrb and tz.pl tools; the latter is (ostensibly) part of tzcode. The tools expect the data in a certain format - current source file for these tools is generated from the Olson timezone 2006o version, and is available at http://dev.icu-project.org/cgi-bin/viewcvs.cgi/icu/source/data/misc/zoneinfo.txt?view=co. The tool to generate this ICU custom format file is tz2icu. tz2icu is part of the usual ICU distribution - but, wait for it - it's built as part of ICU's modded tzcode. I think. Going back for another stab at tzcode...hopefully fresh eyes will make a difference to last time...

Update 4: Could be my problems are a result of this (http://gcc.gnu.org/ml/gcc-patches/2005-06/msg01876.html) gcc regression on 64-bit machines (which of course I'm using ATM.) Using "gcc -c -m32" doesn't complain on the source code in that posting, but "gcc -c -m64" does. I'm using gcc 4.0.1 (Apple, build 5367) from 2.4.1 dev tools.

Update 5: Worked around gcc with appropriate use of casts. Eventually patched the source by hand (since no-one seems to be updating the patch file in ICU for tzcode to match up with the changes in the original version of tzcode.) Found that manual patches of C++ code and makefiles aren't much fun. Spent most of Monday 27 Nov doing extensive rejigging of code to find out where stuff broke.

Update 6: Finally admit defeat and move to Plan B. Going with Japan time until official fix released. If anyone cares about where I got up to, let me know (email address below.)

Notes:

[1] CoreFoundation at least, and therefore AppKit also.

[2] See the MacEnterprise Archives for someone who had more than a week to solve this problem. AFAICT, there's not yet a solution to the ICU timezone support issue - at least for end-users to fix themselves.

[3] ICU .dat files are not completely cross-platform, due to endianness - however Apple supplies files for both PPC and Intel on x86 (presumably the PPC version is provided for Rosetta support, as the PPC is all alone on a PPC machine.) For instance, on a 10.4.8 Mac Pro, using ICU 3.2, we see in /usr/share/icu:

icudt32l.dat = little endian (Intel)

icudt32b.dat = big endian (PPC)

[4] Source download of ICU 3.2 from ICU site builds and installs with only one (unimportant) test error, but "decmn" fails inexplicably when converting data files; attempted fix but then thought I should see if it was in the Darwin repository. Unfortunately, the Apple "sanctioned" version also fails identically. If you look in the ICU.plist file that comes with the Apple version, you'll see the URL to the original source download location: same as what I already used earlier. Turns out there's some really bad code smells from the "decmn" tool - it doesn't create subdirectories when the source data indicates it should, and then barfs. If you wait for it to complain, create the directories manually and re-run until it quits moaning, you'll be right.]

Java Timezones

Anyone thought about JVM timezones? This is something that is likely to concern everyone on campus regardless of desktop or server platform - yet I haven't seen anything about J2SE or J2EE timezone support and the implications thereof.

Wikipedia entry on Java timezone support

[Test code forthcoming...]

Application-based Timezones

As ideal as it would be for applications to leverage the underlying OS timezone support, this is obviously not the case for a number of applications, particularly those that handle "events" in any capacity - either calendaring programs or MTAs with calendar functionality. The primary suspects for issues with daylight time are:

Microsoft Exchange

Microsoft Outlook [Express - please tell me no-one's using that on campus!]

Microsoft Entourage

Mozilla Sunbird (does anyone seriously use it?)

PeopleCube MeetingMaker

...Others?


Contributions, feedback and especially corrections welcome...

Posted by Mark Glossop, Faculty of Arts, Humanities and Social Sciences
mark DOT glossop AT uwa DOT edu DOT au