4

My subject is probably terribly worded, but here's what I have.

I have a web service that reports timestamps in its local time and the timestamps reflect daylight time if the server is in an affected area. The web service also has a second call to retrieve the server time in UTC so a server in Pacific Daylight Time (PDT) reports its UTC offset as -08:00 even though it's effectively -07:00 because of PDT.

Here is the result of my call to return the server's timezone info.

Pacific Standard Time;-480;(UTC-08:00) Pacific Time (US & Canada);Pacific Standard Time;Pacific Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];

So, if a timestamp returned from the web service is 3/12/2013 12:00am and the UTC offset is -08:00 and I live in a daylight time exempt area of Arizona where my UTC offset is -07:00 how can I convert from the returned timestamp to my local time?

The killer here is the web service using local time in timestamps. If they would just stick to a universal format my life would be easy. My current thinking is if I can get the server's information in a TTimeZone or equivalent structure then I can use the TTimeZone.IsDaylightTime(Timestamp) function to know if I need to subtract an hour from the timestamp before then using the -08:00 server offset and -07:00 local offset to get my correct local time.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Michael S.
  • 1,771
  • 15
  • 20

1 Answers1

7

You can use delphi-tzdb. Pseudo-code:

uses
  ..., TZDB;

procedure Main;
var
  ServerTZID: string;
  TZ: TTimeZone;
  Stamp1, Stamp2: TDateTime;
begin
  // 1. retrieve server timezone info
  ServerTZID := ... // MyServer.GetTimezoneInfo; e.g. 'Pacific Standard Time';
  // look up the retrieved timezone
  TZ := TBundledTimeZone.GetTimeZone(ServerTZID); // nil if not found
  // 2. retrieve server timestamp
  Stamp1 := ... // MyServer.RetrieveTimestamp;
  // 3. convert to UTC and back to local timezone
  Stamp2 := TZ.Local.ToLocalTime(TZ.ToUniversalTime(Stamp1));

  Writeln(Format('%s %s -> %s %s', [FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Stamp1),
    TZ.DisplayName, FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Stamp2),
    TZ.Local.DisplayName]));
end;
Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • The time zone ids the OP showed that are coming back from the sever are Microsoft Windows time zones - not IANA/Olson TZDB time zones. Does delphi-tzdb do CLDR mapping? If not he will need a library that does. I do not know of one for Delphi off hand. The CLDR mapping data is the second table [on this page](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html) – Matt Johnson-Pint Mar 13 '13 at 03:22
  • @MattJohnson It does do some mapping, using some predefined timezone [aliases](https://code.google.com/p/delphi-tzdb/source/browse/trunk/src/TZDBPK/TZDB.inc#7989) which (at first glance) look like Windows timezones. – Ondrej Kelle Mar 13 '13 at 07:31
  • Ok, it looks like they are indeed mapped from the CLDR. See [this source](https://code.google.com/p/delphi-tzdb/source/browse/trunk/src/TZUpdate/TZSchema.pas#613). So your answer is correct. This looks like a pretty good library. – Matt Johnson-Pint Mar 13 '13 at 13:12
  • Thanks, TOndrej. I'll give this a shot today. – Michael S. Mar 13 '13 at 13:57
  • @TOndrej, you're the man. It works like a charm. I wish I had posted this question first thing yesterday morning instead of wasting a couple of hours looking into the issue. Thanks! – Michael S. Mar 13 '13 at 21:04