🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #1796

Re: TDateTime & GMT

#1796
From: Dennis Jones
Date: Wed, 20 Jun 2007 00:10
174 lines
6362 bytes
"Robert G. Hoover" <not.a.real.address@anywhere.sorry> wrote in message 
news:46781ca0@newsgroups.borland.com...
> Hi All,
>
> Is there an easy way to convert the current time to a different
> timezone? Something like this...?
>
> AnsiString TimeString = Now().FormatString(GMT);

Unfortunately, no.


> Or do I have to use a TIME_ZONE_INFORMATION object or something?

Yeah, or something.  I was looking at this a couple of years ago, and I 
thought if you just knew the offset, you could get whatever you wanted.  But 
it turns out that each time zone has its own way of handling 
standard/daylight time, so just knowing the timezone's offset isn't enough 
to get an accurate conversion -- you also have to know its rules for 
handling standard/daylight time.

So, what you have to do is:

1) Get the timezone information from the registry for both the source and 
target timezones.

    Note: The timezone information is in: HKLM\Software\Microsoft\Windows 
NT\Time Zones\CurrentVersion.  For an explanation of the format of the time 
zone information in the registry, see: 
http://support.microsoft.com/kb/115231

2) Convert the time from the source time zone to UTC (see: 
TzSpecificLocalTimeToSystemTime).
3) Convert from UTC to the time in the target timezone (see: 
SystemTimeToTzSpecificLocalTime).

If you can guarantee that your code will run on XP or higher, you can use 
TzSpecificLocalTimeToSystemTime.  If not, you'll have to roll your own or 
get one from somewhere else.  A good place to find source code for this kind 
of thing is the Wine project. You will find an implementation for 
TzSpecificLocalTimeToSystemTime in wine\dlls\kernel32\time.c.

Here's a quick and dirty implementation of GetTimeZoneInfoFromRegistry:

struct TZI
{
  int Bias;
  int StandardBias;
  int DaylightBias;
  SYSTEMTIME StandardDate;
  SYSTEMTIME DaylightDate;
};

bool GetTimeZoneInfoFromRegistry(TIME_ZONE_INFORMATION &tzinfo, const 
AnsiString &TZName)
{
  static TIME_ZONE_INFORMATION _tzinfo;
  tzinfo = _tzinfo;
  bool bResult = false;

  boost::scoped_ptr<TRegistry> pRegistry( new TRegistry );
  pRegistry->RootKey = HKEY_LOCAL_MACHINE;
  AnsiString TimeZonesKey = "Software\\Microsoft\\Windows 
NT\\CurrentVersion\\Time Zones";
  if ( pRegistry->OpenKey( TimeZonesKey, false ) )
  {
    boost::scoped_ptr<TStringList> pZones( new TStringList );
    pRegistry->GetKeyNames( pZones.get() );
    pRegistry->CloseKey();

    int Index = pZones->IndexOf( TZName );
    if ( Index != -1 )
    {
      AnsiString KeyToOpen = TimeZonesKey + "\\" + pZones->Strings[Index];
      if ( pRegistry->OpenKey( KeyToOpen, false ) )
      {
        if ( pRegistry->ValueExists( "TZI" ) )
        {
          TZI tzi = { 0 };
          if ( pRegistry->ReadBinaryData( "TZI", &tzi, sizeof(tzi) ) )
          {
            if ( pRegistry->ValueExists( "Std" ) )
            {
              AnsiString StandardName = pRegistry->ReadString( "Std" );
              StandardName.WideChar( tzinfo.StandardName, 
sizeof(tzinfo.StandardName) );
              if ( pRegistry->ValueExists( "Dlt" ) )
              {
                AnsiString DaylightName = pRegistry->ReadString( "Dlt" );
                DaylightName.WideChar( tzinfo.DaylightName, 
sizeof(tzinfo.DaylightName) );

                tzinfo.Bias = tzi.Bias;
                tzinfo.StandardBias = tzi.StandardBias;
                tzinfo.DaylightBias = tzi.DaylightBias;
                tzinfo.StandardDate = tzi.StandardDate;
                tzinfo.DaylightDate = tzi.DaylightDate;

                bResult = true;
              }
            }
          }
        }
        pRegistry->CloseKey();
      }
    }
  }
  return bResult;
}


Then, with some helper functions, conversion from one timezone to another is 
fairly straightforward:

static void DateTimeToFileTime( const TDateTime &dt, FILETIME *ft )
{
  SYSTEMTIME st;
  DateTimeToSystemTime( dt, st );
  SystemTimeToFileTime( &st, ft );
}

static void FileTimeToDateTime( const FILETIME *ft, TDateTime &dt )
{
  SYSTEMTIME st;
  FileTimeToSystemTime( ft, &st );
  dt = SystemTimeToDateTime( st );
}

bool ConvertTimeZone( TDateTime &DateTime, const AnsiString &source_tz, 
const AnsiString &target_tz )
{
   TIME_ZONE_INFORMATION source_tzinfo;
   if ( !GetTimeZoneInfoFromRegistry( source_tzinfo, source_tz ) ) return 
false;

   TIME_ZONE_INFORMATION target_tzinfo;
   if ( !GetTimeZoneInfoFromRegistry( target_tzinfo, target_tz ) ) return 
false;

   FILETIME FileTime;
   DateTimeToFileTime( DateTime, &FileTime );

   SYSTEMTIME SystemTime;
   FileTimeToSystemTime( &FileTime, &SystemTime );

   SYSTEMTIME UniversalTime;
   if ( !TzSpecificLocalTimeToSystemTime( &source_tzinfo, &SystemTime, 
&UniversalTime ) ) return false;

   if ( !SystemTimeToTzSpecificLocalTime( &target_tzinfo, &UniversalTime, 
&SystemTime ) ) return false;

   DateTime = SystemTimeToDateTime( SystemTime );

   return true;
}

#pragma argsused
int main(int argc, char* argv[])
{
   TDateTime now = Now();
   printf( "The current time in Portland, Oregon is: %s\n", 
now.FormatString( "hh:nn:ss" ).c_str() );
   // get the current time in Bangalore, India
   ConvertTimeZone( now, "Pacific Standard Time", "India Standard Time" );
   printf( "The current time in Bangalore, India is: %s\n", 
now.FormatString( "hh:nn:ss" ).c_str() );
   return 0;
}

HTH,

- Dennis 
Technical Details
Message-ID: <46787087$1@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!news.glorb.com!newsfeeds.ihug.co.nz!ihug.co.nz!newsgroups.borland.com!not-for-mail
References: <46781ca0@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,92eb08d929c9d2d7
X-Google-Attributes: gid10cc67,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
From: "Dennis Jones" <nospam@nospam.com>
Newsgroups: borland.public.cppbuilder.nativeapi
References: <46781ca0@newsgroups.borland.com>
Subject: Re: TDateTime & GMT
Date: Tue, 19 Jun 2007 17:10:48 -0700
Lines: 176
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2900.3138
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3138
X-RFC2646: Format=Flowed; Original
NNTP-Posting-Host: 71.245.109.58
Message-ID: <46787087$1@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1182298247 71.245.109.58 (19 Jun 2007 17:10:47 -0700)
Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!news.glorb.com!newsfeeds.ihug.co.nz!ihug.co.nz!newsgroups.borland.com!not-for-mail