Convert DateTime between different TimeZone  
Author Message
TravelMan





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

Hey,

We need find a way to convert DateTime between two different TimeZone regard what TimeZone you chosed in your local machine. We found all TimeZone information are stored under HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones. We want make sure this registry key are same in vary windows os, such as 9x, 2000, NT, XP, 2003 server and Vistra.

If you have can help us verify this, that will be great.

Thanks,


.NET Development24  
 
 
DMan1





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

Dim MyTimeZone As System.TimeZone = System.TimeZone.CurrentTimeZone



 
 
Sarah Parra - MSFT





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

Moved to the .NET Base Class Library forum.

Thanks,
Sarah



 
 
TravelMan





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

Thanks for your reply. We would like get all Timezone information stored in client machine. So we can convert datetime from client's local timezone to EST time or GMT. In some case, we need consider day saving time. That's why we need get all timezone information.

System.TimeZone.CurrentTimeZone only get local timezone information and we can't get EST, GMT or others timezone information.

 
 
Duncan Woods





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

Here is some C++\CLI that you could build and call from .net:

#include "StdAfx.h"
#include "TimeZoneInformation.h"

/// Disable STL warnings
#pragma warning(disable: 4786) // Disable truncated name warnings
#include <map>
#include <string>
typedef std::basic_string<TCHAR> tstring;

///
/// Store of loaded timezones
///
#define TZREG _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones")
#define TZREG2 _T("SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation")
#define MAX_SIZE 512
#undef GENERATE_TZ_LIST


namespace Common
{
namespace Util
{
/// Static members
static const __int64 WIN32_FILETIME_EPOCH_BIAS = 116444736000000000;

/// Structure to read from the registry
struct REG_TZI
{
long Bias;
long StandardBias;
long DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
};


struct LS_TZREG
{
TCHAR tcName[MAX_SIZE];
TCHAR tcDisp[MAX_SIZE];
TCHAR tcDLT[MAX_SIZE];
TCHAR tcSTD[MAX_SIZE];
TCHAR MapID[MAX_SIZE];
DWORD Index;
DWORD ActiveTimeBias;
REG_TZI TZI;
};


typedef std::map<tstring, LS_TZREG> TimezoneMap;
static TimezoneMap sc_TimeZoneMap;
static bool s_bTimezonesLoaded = false;

DateTime TimeZoneInformation::FromSystemTime(SYSTEMTIME & A_St)
{
return DateTime(
(int) A_St.wYear,
(int) A_St.wMonth,
(int) A_St.wDay,
(int) A_St.wHour,
(int) A_St.wMinute,
(int) A_St.wSecond);
}


void TimeZoneInformation::LoadTimeZoneInfo()
{
if (s_bTimezonesLoaded)
{
return;
}

HKEY HKlmtz;
HKEY KKtz;
DWORD dwIndex = 0;
TCHAR tcName[MAX_SIZE];
DWORD dwcbName = MAX_SIZE;
DWORD dwcbValue;
DWORD dwcbSTD;
DWORD dwcbDLT;
LS_TZREG Temp;
FILETIME ftLastWrite;

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TZREG, 0, KEY_ALL_ACCESS, &HKlmtz) != ERROR_SUCCESS)
{
ATLTRACE("Could not open registry to query timezone info");
return;
}

while (RegEnumKeyEx(HKlmtz, dwIndex++, tcName, &dwcbName, NULL, NULL, NULL, &ftLastWrite) != ERROR_NO_MORE_ITEMS)
{
dwcbName = MAX_SIZE;

if (RegOpenKeyEx(HKlmtz, tcName, 0, KEY_ALL_ACCESS, &KKtz) != ERROR_SUCCESS)
{
ATLTRACE("Could not open registry to query specific timezone info");
RegCloseKey(HKlmtz);
}
else
{
dwcbValue = MAX_SIZE;
RegQueryValueEx(KKtz, _T("Display"), NULL, NULL, (BYTE*) Temp.tcDisp, &dwcbValue);
dwcbDLT = MAX_SIZE;
RegQueryValueEx(KKtz, _T("Dlt"), NULL, NULL, (BYTE*)Temp.tcDLT, &dwcbDLT);
dwcbSTD = MAX_SIZE;
RegQueryValueEx(KKtz, _T("Std"), NULL,NULL,(BYTE*)Temp.tcSTD,&dwcbSTD);
dwcbValue = MAX_SIZE;
RegQueryValueEx(KKtz, _T("MapID"), NULL,NULL,(BYTE*)Temp.MapID,&dwcbValue);
dwcbValue = sizeof(DWORD);
RegQueryValueEx(KKtz, _T("Index"), NULL,NULL, (BYTE*)&Temp.Index,&dwcbValue);
dwcbValue = sizeof(TIME_ZONE_INFORMATION);
RegQueryValueEx(KKtz, _T("TZI"), NULL,NULL,(BYTE*)&Temp.TZI, &dwcbValue);
}

tstring sName = tcName;
RegCloseKey(KKtz);
sc_TimeZoneMap[sName] = Temp;

#ifdef GENERATE_TZ_LIST
CString sATLTRACE;
sATLTRACE.Format("\"%s\"\n", sName.c_str());
ATLTRACE(sATLTRACE);
#endif
}
RegCloseKey(HKlmtz);
s_bTimezonesLoaded = true;
}

///
/// Converts the time assumed as GMT to the provided timezone
///
DateTime TimeZoneInformation::ToTimeZone(DateTime dateTime, String ^ A_pTz, bool A_bDST)
{
DateTime ret = ConvertTimeZone(dateTime, CString(A_pTz), A_bDST, true);
return ret;
}

///
/// Converts the time assumed from the provided timezone to GMT
///
DateTime TimeZoneInformation::FromTimeZone(DateTime dateTime, String ^ A_pTz, bool A_bDST)
{
DateTime ret = ConvertTimeZone(dateTime, CString(A_pTz), A_bDST, false);
return ret;
}

///
/// Returns true if the given time is in summer time
///
bool TimeZoneInformation::IsDST(DateTime dateTime, String ^ A_pTz)
{
return (FromTimeZone(dateTime, A_pTz, false) != FromTimeZone(dateTime, A_pTz, true));
}

///
/// Converts the time assumed as GMT to the provided timezone
///
DateTime TimeZoneInformation::ConvertTimeZone(
DateTime dateTime,
CString & A_sTz,
bool A_bDST,
bool A_bConvertTo)
{
// Get the timezone to convert to
tstring sTimezone = A_sTz;

// Load the timezones if necessary
if (!s_bTimezonesLoaded)
{
LoadTimeZoneInfo();
}

TimezoneMap::iterator iter = sc_TimeZoneMap.find(sTimezone);
if (iter == sc_TimeZoneMap.end())
{
CString sATLTRACE;
sATLTRACE.Format(_T("Failed to find timezone definition for %s"), sTimezone.c_str());
ATLTRACE(sATLTRACE);
throw gcnew System::Exception(gcnew String(sATLTRACE));
}

LS_TZREG oTime = (*iter).second;
TIME_ZONE_INFORMATION tz;
tz.Bias = oTime.TZI.Bias;
tz.StandardBias = oTime.TZI.StandardBias;
tz.DaylightBias = oTime.TZI.DaylightBias;
tz.StandardDate = oTime.TZI.StandardDate;
tz.DaylightDate = oTime.TZI.DaylightDate;

if (!A_bDST)
{
tz.DaylightBias = 0;
tz.DaylightDate.wMonth = 0;
}

// Set the time components
SYSTEMTIME tIn, tOut;
tIn.wYear = (WORD) dateTime.Year;
tIn.wMonth = (WORD) dateTime.Month;
tIn.wDayOfWeek = (WORD) -1;
tIn.wDay = (WORD) dateTime.Day;
tIn.wHour = (WORD) dateTime.Hour;
tIn.wMinute = (WORD) dateTime.Minute;
tIn.wSecond = (WORD) dateTime.Second;
tIn.wMilliseconds = (WORD) 0;

// Convert
if (A_bConvertTo)
{
if (!SystemTimeToTzSpecificLocalTime(&tz, &tIn, &tOut))
{
ATLTRACE("Failed to convert to timezone");
}
}
else
{
if (!TzSpecificLocalTimeToSystemTime(&tz, &tIn, &tOut))
{
ATLTRACE("Failed to convert from timezone");
}
}

// Extract to the return value
return FromSystemTime(tOut);
}


int TimeZoneInformation::DayLightCompareDate(
const LPSYSTEMTIME date, /* [in] The date to compare. */
const LPSYSTEMTIME compareDate) /* [in] The daylight saving begin or end date */
{
int limit_day;

if (compareDate->wYear != 0)
{
if (date->wMonth < compareDate->wMonth)
return -1; /* We are in a year before the date limit. */

if (date->wMonth > compareDate->wMonth)
return 1; /* We are in a year after the date limit. */
}

if (date->wMonth < compareDate->wMonth)
return -1; /* We are in a month before the date limit. */

if (date->wMonth > compareDate->wMonth)
return 1; /* We are in a month after the date limit. */

if (compareDate->wDayOfWeek <= 6)
{
SYSTEMTIME tmp;
FILETIME tmp_ft;

/* compareDate->wDay is interpreted as number of the week in the month. */
/* 5 means: the last week in the month */
int weekofmonth = compareDate->wDay;

/* calculate day of week for the first day in the month */
memcpy(&tmp, date, sizeof(SYSTEMTIME));
tmp.wDay = 1;
tmp.wDayOfWeek = -1;

if (weekofmonth == 5)
{
/* Go to the beginning of the next month. */
if (++tmp.wMonth > 12)
{
tmp.wMonth = 1;
++tmp.wYear;
}
}

if (!SystemTimeToFileTime(&tmp, &tmp_ft))
return -2;

if (weekofmonth == 5)
{
LONGLONG t, one_day;

t = tmp_ft.dwHighDateTime;
t <<= 32;
t += (UINT)tmp_ft.dwLowDateTime;

/* subtract one day */
one_day = 24*60*60;
one_day *= 10000000;
t -= one_day;

tmp_ft.dwLowDateTime = (UINT)t;
tmp_ft.dwHighDateTime = (UINT)(t >> 32);
}

if (!FileTimeToSystemTime(&tmp_ft, &tmp))
return -2;

if (weekofmonth == 5)
{
/* calculate the last matching day of the week in this month */
int dif = tmp.wDayOfWeek - compareDate->wDayOfWeek;
if (dif < 0)
dif += 7;

limit_day = tmp.wDay - dif;
}
else
{
/* calculate the matching day of the week in the given week */
int dif = compareDate->wDayOfWeek - tmp.wDayOfWeek;
if (dif < 0)
dif += 7;

limit_day = tmp.wDay + 7*(weekofmonth-1) + dif;
}
}
else
{
limit_day = compareDate->wDay;
}

if (date->wDay < limit_day)
return -1;

if (date->wDay > limit_day)
return 1;

return 0; /* date is equal to the date limit. */
}



BOOL TimeZoneInformation::GetTimezoneBias(
const LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The time zone data. */
LPSYSTEMTIME lpSystemTime, /* [in] The system time. */
LONG* pBias) /* [out] The calulated bias in minutes */
{
int ret;
BOOL beforeStandardDate, afterDaylightDate;
BOOL daylightsaving = FALSE;
LONG bias = lpTimeZoneInformation->Bias;

if (lpTimeZoneInformation->DaylightDate.wMonth != 0)
{
if (lpTimeZoneInformation->StandardDate.wMonth == 0 ||
lpTimeZoneInformation->StandardDate.wDay<1 ||
lpTimeZoneInformation->StandardDate.wDay>5 ||
lpTimeZoneInformation->DaylightDate.wDay<1 ||
lpTimeZoneInformation->DaylightDate.wDay>5)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}

/* check for daylight saving */
ret = DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->StandardDate);
if (ret == -2)
return FALSE;

beforeStandardDate = ret < 0;

ret = DayLightCompareDate(lpSystemTime, &lpTimeZoneInformation->DaylightDate);
if (ret == -2)
return FALSE;

afterDaylightDate = ret >= 0;

if (beforeStandardDate && afterDaylightDate)
daylightsaving = TRUE;
}

if (daylightsaving)
bias += lpTimeZoneInformation->DaylightBias;
else if (lpTimeZoneInformation->StandardDate.wMonth != 0)
bias += lpTimeZoneInformation->StandardBias;

*pBias = bias;

return TRUE;
}

BOOL TimeZoneInformation::TzSpecificLocalTimeToSystemTime(
LPTIME_ZONE_INFORMATION lpTimeZoneInformation, /* [in] The desired time zone. */
LPSYSTEMTIME lpLocalTime, /* [in] The local time. */
LPSYSTEMTIME lpUniversalTime) /* [out] The calculated utc time. */
{
FILETIME ft;
LONG lBias;
LONGLONG t, bias;
TIME_ZONE_INFORMATION tzinfo;

if (lpTimeZoneInformation != NULL)
{
memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
}
else
{
if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
return FALSE;
}

if (!SystemTimeToFileTime(lpLocalTime, &ft))
return FALSE;

t = ft.dwHighDateTime;
t <<= 32;
t += (UINT)ft.dwLowDateTime;

if (!GetTimezoneBias(&tzinfo, lpLocalTime, &lBias))
return FALSE;

bias = (LONGLONG)lBias * 600000000; /* 60 seconds per minute, 100000 [100-nanoseconds-ticks] per second */
t += bias;

ft.dwLowDateTime = (UINT)t;
ft.dwHighDateTime = (UINT)(t >> 32);

return FileTimeToSystemTime(&ft, lpUniversalTime);
}
}
}



 
 
TravelMan





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones will be good for all Windows OS

If there have any version OS it doesn't support, please let me know.

Thanks,

 
 
Duncan Woods





PostPosted: .NET Base Class Library, Convert DateTime between different TimeZone Top

I can confirm 2000, XP and 2003 server. I would expect NT also but doubtful about 9x.