Converting Microsoft ActiveSync TIME_ZONE_INFORMATION structure to named timezones

We had to deal with some perils when synchronizing recurring events between tine20 and mobile devices via Microsoft Active Sync protocol because of the proprietary MS TIME_ZONE_INFORMATION structure which we had to convert to a named timezone like “Europe/Berlin”.

I spent some time researching how to “convert” this TIME_ZONE_INFORMATION structure to a timezone name and the other way round in PHP but I could not find a reusable solution for this problem.

So I created the class ActiveSync_TimezoneConverter to guess timezones matching to the given daylight saving time (DST) transitions and to the given difference to the universal coordinated time (UTC) and vice versa:

First I studied the specifications from Microsoft:

Microsoft TIME_ZONE_INFORMATION Structure:
http://msdn.microsoft.com/en-us/library/ms725481(VS.85).aspx

ActiveSync Exchange Format:
http://msdn.microsoft.com/en-us/library/dd299455.aspx

Then I looked at sample data sent by mobile phones (Timezone Europe/Berlin):

xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==

this string can be unpacked to a hash like this:

array(
‘bias’ => -60,
’standardName’ => ”,
’standardYear’ => 0,
’standardMonth’ => 10,
’standardDayOfWeek’ => 0,
’standardDay’ => 5,
’standardHour’ => 3,
’standardMinute’ => 0,
’standardSecond’ => 0,
’standardMilliseconds’ => 0,
’standardBias’ => 0,
‘daylightName’ => ”,
‘daylightYear’ => 0,
‘daylightMonth’ => 3,
‘daylightDayOfWeek’ => 0,
‘daylightDay’ => 5,
‘daylightHour’ => 2,
‘daylightMinute’ => 0,
‘daylightSecond’ => 0,
‘daylightMilliseconds’ => 0,
‘daylightBias’ => -60
)

Unfortunately, the standardName and daylightName fields are optional and were never present in my generated sample data. I suppose that they might under some circumstances contain the timezone name we are looking for.

If a timezone has no DST change then the daylight and standard fields all equal 0. Then you only have to compare the UTC offset. That is easy.

However, if there is a DST change then the daylight and standard fields define the precise moment when this change happens.
The daylightYear and standardYear fields tell the year in which the specified DST transition takes place. If daylightYear and standardYear equal 0 then the DST transition always follows the same rule, as the MSDN description of the TIME_ZONE_INFORMATION Structure states. Strangely, these fields always equal 0 in my sample data even for timezones that do have variable DST transition rules.

Also the naming of the TIME_ZONE_INFORMATION Structure fields is a little bit confusing, especially the standardDay and daylightDay fields which indicate the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the month if that day of the week does not occur 5 times).

After all I came up with the ActiveSync_TimezoneConverter class with the following public methods:

  • getListOfTimezones($_offsets, $_expextedTimezone = null) – returns all matching timezones
  • getTimezone($_offsets, $_expectedTimezone = null) – returns only the group name of the matching timzones
  • encodeTimezone($_timezone, $_startDate = null) – returns the packed string generated for the given timezone

$_offsets can be either a packed string or a hash using the field names from the example above
$_expectedTimezone is optional and if present it will ensure that the correct timzone is returned when there are multiple matches.

Tags: , ,

Leave a Reply