ntdll: Detect current time zone settings. Take 2

Dmitry Timoshkov dmitry at codeweavers.com
Tue Aug 7 06:01:16 CDT 2007


Hello,

this version of the patch doesn't assume that year starts with tm_isdst == 0.

Alexandre suggested that instead of forcing a user to specify time zone
information in winecfg time zone settings should be detected in run-time.

Changelog:
    ntdll: Detect current time zone settings.

---
 dlls/kernel32/tests/time.c |    5 +
 dlls/ntdll/time.c          |  795 ++++++++++++++++++--------------------------
 include/winternl.h         |    1 +
 3 files changed, 334 insertions(+), 467 deletions(-)

diff --git a/dlls/kernel32/tests/time.c b/dlls/kernel32/tests/time.c
index 6bf79ed..83581c1 100644
--- a/dlls/kernel32/tests/time.c
+++ b/dlls/kernel32/tests/time.c
@@ -246,6 +246,11 @@ static void test_GetTimeZoneInformation(void)
     tz_id = GetTimeZoneInformation(&tzinfo);
     ok(tz_id != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n");
 
+    trace("tz_id %u (%s)\n", tz_id,
+          tz_id == TIME_ZONE_ID_DAYLIGHT ? "TIME_ZONE_ID_DAYLIGHT" :
+          (tz_id == TIME_ZONE_ID_STANDARD ? "TIME_ZONE_ID_STANDARD" :
+          "TIME_ZONE_ID_INVALID"));
+
     trace("bias %d\n", tzinfo.Bias);
     trace("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
         tzinfo.StandardDate.wDay, tzinfo.StandardDate.wMonth,
diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c
index 9f1cef2..f100968 100644
--- a/dlls/ntdll/time.c
+++ b/dlls/ntdll/time.c
@@ -6,6 +6,7 @@
  * Copyright 2002 Rex Jolliff (rex at lvcablemodem.com)
  *
  * Copyright 1999 Juergen Schmied
+ * Copyright 2007 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -50,379 +51,17 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
 
-static RTL_CRITICAL_SECTION TIME_GetBias_section;
+static RTL_CRITICAL_SECTION TIME_tz_section;
 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
 {
-    0, 0, &TIME_GetBias_section,
+    0, 0, &TIME_tz_section,
     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": TIME_GetBias_section") }
+      0, 0, { (DWORD_PTR)(__FILE__ ": TIME_tz_section") }
 };
-static RTL_CRITICAL_SECTION TIME_GetBias_section = { &critsect_debug, -1, 0, 0, 0, 0 };
-
-/* TimeZone registry key values */
-static const WCHAR TZInformationKeyW[] = { 'M','a','c','h','i','n','e','\\',
- 'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r',
- 'o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','T','i','m','e','z',
- 'o','n','e','I','n','f','o','r','m','a','t','i','o','n', 0};
-static const WCHAR TZStandardStartW[] = {
-  'S','t','a','n','d','a','r','d','s','t','a','r','t', 0};
-static const WCHAR TZDaylightStartW[] = {
-  'D','a','y','l','i','g','h','t','s','t','a','r','t', 0};
-static const WCHAR TZDaylightBiasW[] = {
-    'D','a','y','l','i','g','h','t','B','i','a','s', 0};
-static const WCHAR TZStandardBiasW[] = {
-    'S','t','a','n','d','a','r','d','B','i','a','s', 0};
-static const WCHAR TZBiasW[] = {'B','i','a','s', 0};
-static const WCHAR TZDaylightNameW[] = {
-    'D','a','y','l','i','g','h','t','N','a','m','e', 0};
-static const WCHAR TZStandardNameW[] = {
-    'S','t','a','n','d','a','r','d','N','a','m','e', 0};
-
+static RTL_CRITICAL_SECTION TIME_tz_section = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 #define SETTIME_MAX_ADJUST 120
 
-/* This structure is used to store strings that represent all of the time zones
- * in the world. (This is used to help GetTimeZoneInformation)
- */
-struct tagTZ_INFO
-{
-    const char *psTZFromUnix;
-    WCHAR psTZWindows[32];
-    int bias;
-    int dst;
-};
-
-static const struct tagTZ_INFO TZ_INFO[] =
-{
-   {"MHT",
-    {'D','a','t','e','l','i','n','e',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e','\0'}, -720, 0},
-   {"SST",
-    {'S','a','m','o','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, 660, 0},
-   {"HST",
-    {'H','a','w','a','i','i','a','n',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e','\0'}, 600, 0},
-   {"AKST",
-    {'A','l','a','s','k','a','n',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e',0}, 540, 0 },
-   {"AKDT",
-    {'A','l','a','s','k','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, 480, 1},
-   {"PST",
-    {'P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, 480, 0},
-   {"PDT",
-    {'P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, 420, 1},
-   {"MST",
-    {'U','S',' ','M','o','u','n','t','a','i','n',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e','\0'}, 420, 0},
-   {"MDT",
-    {'M','o','u','n','t','a','i','n',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e','\0'}, 360, 1},
-   {"CST",
-    {'C','e','n','t','r','a','l',' ','A','m','e','r','i','c','a',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e','\0'}, 360, 0},
-   {"CDT",
-    {'C','e','n','t','r','a','l',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, 300, 1},
-   {"COT",
-    {'S','A',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 300, 0},
-   {"PET",
-    {'S','A',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e',0}, 300, 0 },
-   {"EDT",
-    {'E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, 240, 1},
-   {"EST",
-    {'U','S',' ','E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 300, 0},
-   {"ECT",
-    {'E','a','s','t','e','r','n',' ','C','e','n','t','r','a','l',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 300, 0},
-   {"ADT",
-    {'A','t','l','a','n','t','i','c',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e','\0'}, 180, 1},
-   {"VET",
-    {'S','A',' ','W','e','s','t','e','r','n',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 240, 0},
-   {"CLT",
-    {'P','a','c','i','f','i','c',' ','S','A',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 240, 0},
-   {"CLST",
-    {'P','a','c','i','f','i','c',' ','S','A',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e',0}, 180, 1},
-   {"AST",
-    {'A','t','l','a','n','t','i','c',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e',0}, 240, 0 },
-   {"NDT",
-    {'N','e','w','f','o','u','n','d','l','a','n','d',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, 150, 1},
-   {"NST",
-    {'N','e','w','f','o','u','n','d','l','a','n','d',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e',0}, 210, 0 },
-   {"BRT",
-    {'B','r','a','z','i','l','i','a','n',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, 180, 0},
-   {"BRST",
-    {'B','r','a','z','i','l','i','a','n',' ','S','u','m','m','e','r',
-     ' ','T','i','m','e','\0'}, 120, 1},
-   {"PYT",
-    {'P','a','r','a','g','u','a','y','a','n',' ',
-     'S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'}, 240, 0},
-   {"PYST",
-    {'P','a','r','a','g','u','a','y','a','n',' ','S','u','m','m','e','r',
-     ' ','T','i','m','e','\0'}, 180, 1},
-   {"ART",
-    {'S','A',' ','E','a','s','t','e','r','n',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 180, 0},
-   {"WGST",
-    {'G','r','e','e','n','l','a','n','d',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, 120, 1},
-   {"GST",
-    {'M','i','d','-','A','t','l','a','n','t','i','c',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, 120, 0},
-   {"AZOT",
-    {'A','z','o','r','e','s',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e',0}, 60, 0},
-   {"AZOST",
-    {'A','z','o','r','e','s',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','\0'}, 0, 1},
-   {"CVT",
-    {'C','a','p','e',' ','V','e','r','d','e',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, 60, 0},
-   {"WEST",
-    {'W','e','s','t','e','r','n',' ','E','u','r','o','p','e','a','n',' ','S','u','m','m','e','r',' ','T','i','m','e','\0'}, -60, 1},
-   {"WET",
-    {'G','r','e','e','n','w','i','c','h',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, 0, 0},
-   {"BST",
-    {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
-    -60, 1},
-   {"IST",
-    {'I','r','i','s','h',' ','S','u','m','m','e','r',' ','T','i','m','e','\0'},
-    -60, 1},
-   {"GMT",
-    {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
-    0, 0},
-   {"UTC",
-    {'G','M','T',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'},
-    0, 0},
-   {"CET",
-    {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e','a','n',' ',
-     'T','i','m','e','\0'}, -60, 0},
-   {"CEST",
-    {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','S','t','a',
-     'n','d','a','r','d',' ','T','i','m','e','\0'}, -120, 1},
-   {"MET",
-    {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','S','t','a',
-     'n','d','a','r','d',' ','T','i','m','e','\0'}, -60, 0},
-   {"MEST",
-    {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e',' ','D','a','y',
-     'l','i','g','h','t',' ','T','i','m','e','\0'}, -120, 1},
-   {"WAT",
-    {'W','.',' ','C','e','n','t','r','a','l',' ','A','f','r','i','c','a',' ',
-     'S','t','a','n','d','a','r','d',' ','T','i','m','e','\0'}, -60, 0},
-   {"EEST",
-    {'E','.',' ','E','u','r','o','p','e',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, -180, 1},
-   {"EET",
-    {'E','g','y','p','t',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -120, 0},
-   {"CAT",
-    {'C','e','n','t','r','a','l',' ','A','f','r','i','c','a','n',' '
-    ,'T','i','m','e','\0'}, -120, 0},
-   {"SAST",
-    {'S','o','u','t','h',' ','A','f','r','i','c','a',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -120, 0},
-   {"IST",
-    {'I','s','r','a','e','l',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','\0'}, -120, 0},
-   {"IDT",
-    {'I','s','r','a','e','l',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','\0'}, -180, 1},
-   {"MSK",
-    {'R','u','s','s','i','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -180, 0},
-   {"ADT",
-    {'A','r','a','b','i','c',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','\0'}, -240, 1},
-   {"AST",
-    {'A','r','a','b',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
-     '\0'}, -180, 0},
-   {"MSD",
-    {'R','u','s','s','i','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -240, 1},
-   {"EAT",
-    {'E','.',' ','A','f','r','i','c','a',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, -180, 0},
-   {"IRST",
-    {'I','r','a','n',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
-     0},-210, 0 },
-   {"IRST",
-    {'I','r','a','n',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
-     '\0'}, -270, 1},
-   {"GST",
-    {'A','r','a','b','i','a','n',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -240, 0},
-   {"AZT",
-    {'C','a','u','c','a','s','u','s',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e',0}, -240, 0 },
-   {"AZST",
-    {'C','a','u','c','a','s','u','s',' ','S','t','a','n','d','a','r','d',' ',
-     'T','i','m','e','\0'}, -300, 1},
-   {"AFT",
-    {'A','f','g','h','a','n','i','s','t','a','n',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e','\0'}, -270, 0},
-   {"SAMT",
-    {'S','a','m','a','r','a',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','(','W','i','n','t','e','r',')','\0'}, -240, 0},
-   {"SAMST",
-    {'S','a','m','a','r','a',' ','D','a','y','l','i','g','h','t',' ','T','i',
-     'm','e','(','S','u','m','m','e','r',')','\0'}, -300, 1},
-   {"YEKT",
-    {'U','r','a','l','s',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e',' ','(','W','i','n','t','e','r',')','\0'}, -300, 0},
-   {"YEKST",
-    {'U','r','a','l','s',' ','D','a','y','l','i','g','h','t',
-     ' ','T','i','m','e',' ','(','S','u','m','m','e','r',')','\0'}, -360, 1},
-   {"OMST",
-    {'O','m','s','k',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e',' ','(','W','i','n','t','e','r',')','\0'}, -360, 0},
-   {"OMSST",
-    {'O','m','s','k',' ','D','a','y','l','i','g','h','t',
-     ' ','T','i','m','e',' ','(','S','u','m','m','e','r',')','\0'}, -420, 1},
-   {"PKT",
-    {'W','e','s','t',' ','A','s','i','a',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, -300, 0},
-   {"IST",
-    {'I','n','d','i','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -330, 0},
-   {"NPT",
-    {'N','e','p','a','l',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -345, 0},
-   {"ALMST",
-    {'N','.',' ','C','e','n','t','r','a','l',' ','A','s','i','a',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -420, 1},
-   {"BDT",
-    {'C','e','n','t','r','a','l',' ','A','s','i','a',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -360, 0},
-   {"LKT",
-    {'S','r','i',' ','L','a','n','k','a',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, -360, 0},
-   {"MMT",
-    {'M','y','a','n','m','a','r',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -390, 0},
-   {"ICT",
-    {'S','E',' ','A','s','i','a',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -420, 0},
-   {"KRAT",
-    {'N','o','r','t','h',' ','A','s','i','a',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e',0}, -420, 0},
-   {"KRAST",
-    {'N','o','r','t','h',' ','A','s','i','a',' ','S','t','a','n','d','a','r',
-     'd',' ','T','i','m','e','\0'}, -480, 1},
-   {"IRKT",
-    {'N','o','r','t','h',' ','A','s','i','a',' ','E','a','s','t',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e',0}, -480, 0},
-   {"CST",
-    {'C','h','i','n','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -480, 0},
-   {"IRKST",
-    {'N','o','r','t','h',' ','A','s','i','a',' ','E','a','s','t',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -540, 1},
-   {"SGT",
-    {'M','a','l','a','y',' ','P','e','n','i','n','s','u','l','a',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -480, 0},
-   {"WST",
-    {'W','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -480, 0},
-   {"WST",
-    {'W','.',' ','A','u','s','t','r','a','l','i','a',' ','S','u','m','m','e',
-     'r',' ','T','i','m','e','\0'}, -540, 1},
-   {"JST",
-    {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -540, 0},
-   {"KST",
-    {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -540, 0},
-   {"YAKST",
-    {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T',
-     'i','m','e','\0'}, -600, 1},
-   {"CST",
-    {'C','e','n','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a',
-     'n','d','a','r','d',' ','T','i','m','e','\0'}, -570, 0},
-   {"CST",
-    {'C','e','n','.',' ','A','u','s','t','r','a','l','i','a',' ','D','a','y',
-     'l','i','g','h','t',' ','T','i','m','e','\0'}, -630, 1},
-   {"EST",
-    {'E','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -600, 0},
-   {"EST",
-    {'E','.',' ','A','u','s','t','r','a','l','i','a',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -660, 1},
-   {"GST",
-    {'W','e','s','t',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e','\0'}, -600, 0},
-   {"VLAT",
-    {'V','l','a','d','i','v','o','s','t','o','k',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e',0}, -600, 0 },
-   {"ChST",
-    {'W','e','s','t',' ','P','a','c','i','f','i','c',' ','S','t','a','n','d',
-     'a','r','d',' ','T','i','m','e',0}, -600, 0},
-   {"VLAST",
-    {'V','l','a','d','i','v','o','s','t','o','k',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e','\0'}, -660, 1},
-   {"MAGT",
-    {'C','e','n','t','r','a','l',' ','P','a','c','i','f','i','c',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e',0}, -660, 0},
-   {"MAGST",
-    {'C','e','n','t','r','a','l',' ','P','a','c','i','f','i','c',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e','\0'}, -720, 1},
-   {"NZST",
-    {'N','e','w',' ','Z','e','a','l','a','n','d',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e','\0'}, -720, 0},
-   {"NZDT",
-    {'N','e','w',' ','Z','e','a','l','a','n','d',' ','D','a','y','l','i','g',
-     'h','t',' ','T','i','m','e','\0'}, -780, 1},
-   {"FJT",
-    {'F','i','j','i',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',
-     '\0'}, -720, 0},
-   {"TOT",
-    {'T','o','n','g','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m',
-     'e','\0'}, -780, 0},
-   {"NOVT",
-    {'N','.',' ','C','e','n','t','r','a','l',' ','A','s','i','a',' ','S','t',
-     'a','n','d','a','r','d',' ','T','i','m','e',0 }, -360, 0},
-   {"NOVT",
-    {'N','o','v','o','s','i','b','i','r','s','k',' ','S','t','a','n','d','a',
-     'r','d',' ','T','i','m','e','\0'}, -360, 1},
-   {"ANAT",
-    {'A','n','a','d','y','r',' ','S','t','a','n','d','a','r','d',' ','T','i',
-     'm','e','\0'}, -720, 1},
-   {"HKT",
-    {'H','o','n','g',' ','K','o','n','g',' ','S','t','a','n','d','a','r','d',
-     ' ','T','i','m','e','\0'}, -480, 0},
-   {"UYT",
-    {'U','r','u','g','u','a','y','a','n',' ','T','i','m','e','\0'}, 180, 0},
-   {"UYST",
-    {'U','r','u','g','u','a','y','a','n',' ','S','u','m','m','e','r',' ','T',
-    'i','m','e','\0'}, 120, 1},
-   {"MYT",
-    {'M','a','l','a','y','s','i','a','n',' ','T','i','m','e','\0'}, -480, 0},
-   {"PHT",
-    {'P','h','i','l','i','p','p','i','n','e',' ','T','i','m','e','\0'}, -480, 0},
-   {"NOVST",
-    {'N','o','v','o','s','i','b','i','r','s','k',' ','S','u','m','m','e','r',
-     ' ','T','i','m','e','\0'}, -420, 1},
-   {"BOT",
-    {'B','o','l','i','v','i','a','n',' ','T','i','m','e','\0'}, 240, 0},
-   {"UZT",
-    {'U','z','b','e','k','i','s','t','h','a','n',' ','T','i','m','e','\0'}, -300, 0}
-};
-
 #define TICKSPERSEC        10000000
 #define TICKSPERMSEC       10000
 #define SECSPERDAY         86400
@@ -608,7 +247,7 @@ static int TIME_GetBias(time_t utc, int *pdaylight)
     static int last_daylight;
     int ret;
 
-    RtlEnterCriticalSection( &TIME_GetBias_section );
+    RtlEnterCriticalSection( &TIME_tz_section );
     if (utc != last_utc)
     {
         ptm = localtime(&utc);
@@ -622,7 +261,7 @@ static int TIME_GetBias(time_t utc, int *pdaylight)
     *pdaylight = last_daylight;
     ret = last_bias;
 
-    RtlLeaveCriticalSection( &TIME_GetBias_section );
+    RtlLeaveCriticalSection( &TIME_tz_section );
     return ret;
 }
 
@@ -857,63 +496,114 @@ ULONG WINAPI NtGetTickCount(void)
     return (now.QuadPart - server_start_time) / 10000;
 }
 
-
-/***********************************************************************
- *        TIME_GetTZAsStr [internal]
- *
- * Helper function that returns the given timezone as a string.
+/* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
+ * (last Sunday in October of 2007) becomes Sun Oct 28 2007 
  *
- * PARAMS
- *   utc [I] The current utc time.
- *   bias [I] The bias of the current timezone.
- *   dst [I] ??
- *
- * RETURNS
- *   Timezone name.
- *
- * NOTES:
- *   This could be done with a hash table instead of merely iterating through a
- *   table, however with the small amount of entries (60 or so) I didn't think
- *   it was worth it.
+ * Note: year, day and month must be in unix format.
  */
-static const WCHAR* TIME_GetTZAsStr (time_t utc, int bias, int dst)
+static int weekday_to_mday(int year, int day, int mon, int day_of_week)
 {
-   char psTZName[7];
-   struct tm *ptm = localtime(&utc);
-   unsigned int i;
-
-   if (!strftime (psTZName, 7, "%Z", ptm))
-   {
-      WARN("strftime error %d\n", errno);
-      return NULL;
-   }
-
-   for (i=0; i<(sizeof(TZ_INFO) / sizeof(struct tagTZ_INFO)); i++)
-   {
-      if ( strcmp(TZ_INFO[i].psTZFromUnix, psTZName) == 0 &&
-           TZ_INFO[i].bias == bias &&
-           TZ_INFO[i].dst == dst
-         )
-            return TZ_INFO[i].psTZWindows;
-   }
-   FIXME("Can't match system time zone name \"%s\", bias=%d and dst=%d "
-         "to an entry in TZ_INFO. Please add appropriate entry to "
-         "TZ_INFO and submit as patch to wine-patches\n",psTZName,bias,dst);
-   return NULL;
+    struct tm date;
+    time_t tmp;
+    int wday, mday;
+
+    /* find first day in the month matching week day of the date */
+    memset(&date, 0, sizeof(date));
+    date.tm_year = year;
+    date.tm_mon = mon;
+    date.tm_mday = -1;
+    date.tm_wday = -1;
+    do
+    {
+        date.tm_mday++;
+        tmp = mktime(&date);
+    } while (date.tm_wday != day_of_week || date.tm_mon != mon);
+
+    mday = date.tm_mday;
+
+    /* find number of week days in the month matching week day of the date */
+    wday = 1; /* 1 - 1st, ...., 5 - last */
+    while (wday < day)
+    {
+        struct tm *tm;
+
+        date.tm_mday += 7;
+        tmp = mktime(&date);
+        tm = localtime(&tmp);
+        if (tm->tm_mon != mon)
+            break;
+        mday = tm->tm_mday;
+        wday++;
+    }
+
+    return mday;
 }
 
-/***  TIME_GetTimeZoneInfoFromReg: helper for GetTimeZoneInformation ***/
+static BOOL match_tz_date(const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st)
+{
+    WORD wDay;
 
+    if (st->wMonth != reg_st->wMonth) return FALSE;
 
-static int TIME_GetTimeZoneInfoFromReg(RTL_TIME_ZONE_INFORMATION *tzinfo)
+    if (!st->wMonth) return TRUE; /* no transition dates */
+
+    wDay = reg_st->wDay;
+    if (!reg_st->wYear) /* date in a day-of-week format */
+        wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
+
+    if (st->wDay != wDay ||
+        st->wHour != reg_st->wHour ||
+        st->wMinute != reg_st->wMinute ||
+        st->wSecond != reg_st->wSecond ||
+        st->wMilliseconds != reg_st->wMilliseconds) return FALSE;
+
+    return TRUE;
+}
+
+static BOOL match_tz_info(const RTL_TIME_ZONE_INFORMATION *tzi, const RTL_TIME_ZONE_INFORMATION *reg_tzi)
+{
+    if (tzi->Bias == reg_tzi->Bias &&
+        match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
+        match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate))
+        return TRUE;
+
+    return FALSE;
+}
+
+static BOOL reg_query_value(HKEY hkey, LPCWSTR name, DWORD type, void *data, DWORD count)
 {
-    BYTE buf[90];
-    KEY_VALUE_PARTIAL_INFORMATION * KpInfo =
-        (KEY_VALUE_PARTIAL_INFORMATION *) buf;
+    UNICODE_STRING nameW;
+    char buf[256];
+    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
+
+    if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION))
+        return FALSE;
+
+    RtlInitUnicodeString(&nameW, name);
+
+    if (NtQueryValueKey(hkey, &nameW, KeyValuePartialInformation,
+                        buf, sizeof(buf), &count))
+        return FALSE;
+
+    if (info->Type != type) return FALSE;
+
+    memcpy(data, info->Data, info->DataLength);
+    return TRUE;
+}
+
+static void find_reg_tz_info(RTL_TIME_ZONE_INFORMATION *tzi)
+{
+    static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
+        'S','o','f','t','w','a','r','e','\\',
+        'M','i','c','r','o','s','o','f','t','\\',
+        'W','i','n','d','o','w','s',' ','N','T','\\',
+        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+        'T','i','m','e',' ','Z','o','n','e','s',0 };
     HANDLE hkey;
-    DWORD size;
+    ULONG idx;
     OBJECT_ATTRIBUTES attr;
     UNICODE_STRING nameW;
+    WCHAR buf[128];
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = 0;
@@ -921,43 +611,223 @@ static int TIME_GetTimeZoneInfoFromReg(RTL_TIME_ZONE_INFORMATION *tzinfo)
     attr.Attributes = 0;
     attr.SecurityDescriptor = NULL;
     attr.SecurityQualityOfService = NULL;
-    RtlInitUnicodeString( &nameW, TZInformationKeyW);
-    if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) {
-
-#define GTZIFR_N( valkey, tofield) \
-        RtlInitUnicodeString( &nameW, valkey );\
-        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, KpInfo,\
-                    sizeof(buf), &size )) { \
-            if( size >= (sizeof((tofield)) + \
-                    offsetof(KEY_VALUE_PARTIAL_INFORMATION,Data))) { \
-                memcpy(&(tofield), \
-                        KpInfo->Data, sizeof(tofield)); \
-            } \
+    RtlInitUnicodeString(&nameW, Time_ZonesW);
+    if (NtOpenKey(&hkey, KEY_READ, &attr))
+    {
+        WARN("Unable to open the time zones key\n");
+        return;
+    }
+
+    idx = 0;
+    nameW.Buffer = buf;
+    nameW.Length = sizeof(buf);
+    nameW.MaximumLength = sizeof(buf);
+
+    while (!RtlpNtEnumerateSubKey(hkey, &nameW, idx++))
+    {
+        static const WCHAR stdW[] = { 'S','t','d',0 };
+        static const WCHAR dltW[] = { 'D','l','t',0 };
+        static const WCHAR tziW[] = { 'T','Z','I',0 };
+        RTL_TIME_ZONE_INFORMATION reg_tzi;
+        HANDLE hSubkey;
+        struct tz_reg_data
+        {
+            LONG bias;
+            LONG std_bias;
+            LONG dlt_bias;
+            RTL_SYSTEM_TIME std_date;
+            RTL_SYSTEM_TIME dlt_date;
+        } tz_data;
+
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = hkey;
+        attr.ObjectName = &nameW;
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        if (NtOpenKey(&hSubkey, KEY_READ, &attr))
+        {
+            WARN("Unable to open subkey %s\n", debugstr_wn(nameW.Buffer, nameW.Length/sizeof(WCHAR)));
+            continue;
         }
-#define GTZIFR_S( valkey, tofield) \
-        RtlInitUnicodeString( &nameW, valkey );\
-        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, KpInfo,\
-                    sizeof(buf), &size )) { \
-            size_t len = (strlenW( (WCHAR*)KpInfo->Data ) + 1) * sizeof(WCHAR); \
-            if (len > sizeof(tofield)) len = sizeof(tofield); \
-            memcpy( tofield, KpInfo->Data, len ); \
-            tofield[(len/sizeof(WCHAR))-1] = 0; \
+
+#define get_value(hkey, name, type, data, len) \
+    if (!reg_query_value(hkey, name, type, data, len)) \
+    { \
+        WARN("can't read data from %s\n", debugstr_w(name)); \
+        NtClose(hkey); \
+        continue; \
+    }
+
+        get_value(hSubkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName));
+        get_value(hSubkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName));
+        get_value(hSubkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data));
+
+#undef get_value
+
+        reg_tzi.Bias = tz_data.bias;
+        reg_tzi.StandardBias = tz_data.std_bias;
+        reg_tzi.DaylightBias = tz_data.dlt_bias;
+        reg_tzi.StandardDate = tz_data.std_date;
+        reg_tzi.DaylightDate = tz_data.dlt_date;
+
+        TRACE("%s: bias %d\n", debugstr_wn(nameW.Buffer, nameW.Length/sizeof(WCHAR)), reg_tzi.Bias);
+        TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
+            reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
+            reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
+            reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
+            reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
+            reg_tzi.StandardBias);
+        TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
+            reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
+            reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
+            reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
+            reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
+            reg_tzi.DaylightBias);
+
+        NtClose(hSubkey);
+
+        if (match_tz_info(tzi, &reg_tzi))
+        {
+            memcpy(tzi, &reg_tzi, sizeof(*tzi));
+            NtClose(hkey);
+            return;
         }
 
-        GTZIFR_N( TZStandardStartW,  tzinfo->StandardDate)
-        GTZIFR_N( TZDaylightStartW,  tzinfo->DaylightDate)
-        GTZIFR_N( TZBiasW,          tzinfo->Bias)
-        GTZIFR_N( TZStandardBiasW,  tzinfo->StandardBias)
-        GTZIFR_N( TZDaylightBiasW,  tzinfo->DaylightBias)
-        GTZIFR_S( TZStandardNameW, tzinfo->StandardName)
-        GTZIFR_S( TZDaylightNameW, tzinfo->DaylightName)
-
-#undef GTZIFR_N
-#undef GTZIFR_S
-        NtClose( hkey );
-        return 1;
+        /* reset len */
+        nameW.Length = sizeof(buf);
+        nameW.MaximumLength = sizeof(buf);
     }
-    return 0;
+
+    NtClose(hkey);
+
+    FIXME("Can't find matching timezone information in the registry for "
+          "bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
+          tzi->Bias,
+          tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
+          tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
+}
+
+static time_t find_dst_change(unsigned long min, unsigned long max, int *is_dst)
+{
+    time_t start;
+    struct tm *tm;
+
+    start = min;
+    tm = localtime(&start);
+    *is_dst = !tm->tm_isdst;
+    TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
+
+    while (min <= max)
+    {
+        time_t pos = (min + max) / 2;
+        tm = localtime(&pos);
+
+        if (tm->tm_isdst != *is_dst)
+            min = pos + 1;
+        else
+            max = pos - 1;
+    }
+    return min;
+}
+
+static void init_tz_info(RTL_TIME_ZONE_INFORMATION *tzi, int *valid_year)
+{
+    struct tm *tm;
+    time_t year_start, year_end, tmp, dlt = 0, std = 0;
+    int is_dst;
+
+    year_start = time(NULL);
+    tm = localtime(&year_start);
+
+    if (*valid_year == tm->tm_year) return;
+
+    memset(tzi, 0, sizeof(*tzi));
+
+    TRACE("tz data will be valid through year %d\n", tm->tm_year + 1900);
+    *valid_year = tm->tm_year;
+
+    tm->tm_isdst = 0;
+    tm->tm_mday = 1;
+    tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
+    year_start = mktime(tm);
+    TRACE("year_start: %s", ctime(&year_start));
+
+    tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
+    tm->tm_mon = 12;
+    tm->tm_hour = 23;
+    tm->tm_min = tm->tm_sec = 59;
+    year_end = mktime(tm);
+    TRACE("year_end: %s", ctime(&year_end));
+
+    tm = gmtime(&year_start);
+    tzi->Bias = (LONG)(mktime(tm) - year_start) / 60;
+    TRACE("bias: %d\n", tzi->Bias);
+
+    tmp = find_dst_change(year_start, year_end, &is_dst);
+    if (is_dst)
+        dlt = tmp;
+    else
+        std = tmp;
+
+    tmp = find_dst_change(tmp, year_end, &is_dst);
+    if (is_dst)
+        dlt = tmp;
+    else
+        std = tmp;
+
+    TRACE("std: %s", ctime(&std));
+    TRACE("dlt: %s", ctime(&dlt));
+
+    if (dlt == std || !dlt || !std)
+    {
+        TRACE("there is no daylight saving rules in this time zone\n");
+        return;
+    }
+
+    tmp = dlt - tzi->Bias * 60;
+    tm = gmtime(&tmp);
+    TRACE("dlt gmtime: %s", asctime(tm));
+
+    tzi->DaylightBias = -60;
+    tzi->DaylightDate.wYear = tm->tm_year + 1900;
+    tzi->DaylightDate.wMonth = tm->tm_mon + 1;
+    tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
+    tzi->DaylightDate.wDay = tm->tm_mday;
+    tzi->DaylightDate.wHour = tm->tm_hour;
+    tzi->DaylightDate.wMinute = tm->tm_min;
+    tzi->DaylightDate.wSecond = tm->tm_sec;
+    tzi->DaylightDate.wMilliseconds = 0;
+
+    TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
+        tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
+        tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
+        tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
+        tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
+        tzi->DaylightBias);
+
+    tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
+    tm = gmtime(&tmp);
+    TRACE("std gmtime: %s", asctime(tm));
+
+    tzi->StandardBias = 0;
+    tzi->StandardDate.wYear = tm->tm_year + 1900;
+    tzi->StandardDate.wMonth = tm->tm_mon + 1;
+    tzi->StandardDate.wDayOfWeek = tm->tm_wday;
+    tzi->StandardDate.wDay = tm->tm_mday;
+    tzi->StandardDate.wHour = tm->tm_hour;
+    tzi->StandardDate.wMinute = tm->tm_min;
+    tzi->StandardDate.wSecond = tm->tm_sec;
+    tzi->StandardDate.wMilliseconds = 0;
+
+    TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
+        tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
+        tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
+        tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
+        tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
+        tzi->StandardBias);
+
+    find_reg_tz_info(tzi);
 }
 
 /***********************************************************************
@@ -974,28 +844,19 @@ static int TIME_GetTimeZoneInfoFromReg(RTL_TIME_ZONE_INFORMATION *tzinfo)
  */
 NTSTATUS WINAPI RtlQueryTimeZoneInformation(RTL_TIME_ZONE_INFORMATION *tzinfo)
 {
-    time_t gmt;
-    int bias, daylight;
-    const WCHAR *psTZ;
+    static RTL_TIME_ZONE_INFORMATION *cached_tzi;
+    static int current_year = -1;
 
-    memset(tzinfo, 0, sizeof(RTL_TIME_ZONE_INFORMATION));
+    RtlEnterCriticalSection(&TIME_tz_section);
+
+    if (!cached_tzi)
+        cached_tzi = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*cached_tzi));
+
+    init_tz_info(cached_tzi, &current_year);
+    *tzinfo = *cached_tzi;
+
+    RtlLeaveCriticalSection(&TIME_tz_section);
 
-    if( !TIME_GetTimeZoneInfoFromReg(tzinfo))
-    {
-        WARN("TIME_GetTimeZoneInfoFromReg failed\n");
-
-        gmt = time(NULL);
-        bias = TIME_GetBias(gmt, &daylight);
-        TRACE("bias %d, daylight %d\n", -bias/60, daylight);
-
-        tzinfo->Bias = -bias / 60;
-        tzinfo->StandardBias = 0;
-        tzinfo->DaylightBias = -60;
-        tzinfo->StandardName[0]='\0';
-        tzinfo->DaylightName[0]='\0';
-        psTZ = TIME_GetTZAsStr (gmt, (-bias/60), daylight);
-        if (psTZ) strcpyW( tzinfo->StandardName, psTZ );
-        }
     return STATUS_SUCCESS;
 }
 
diff --git a/include/winternl.h b/include/winternl.h
index d1764cd..541eb58 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -2278,6 +2278,7 @@ NTSTATUS  WINAPI RtlWalkHeap(HANDLE,PVOID);
 NTSTATUS  WINAPI RtlWriteRegistryValue(ULONG,PCWSTR,PCWSTR,ULONG,PVOID,ULONG);
 
 NTSTATUS  WINAPI RtlpNtCreateKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
+NTSTATUS  WINAPI RtlpNtEnumerateSubKey(HANDLE,UNICODE_STRING *, ULONG);
 NTSTATUS  WINAPI RtlpWaitForCriticalSection(RTL_CRITICAL_SECTION *);
 NTSTATUS  WINAPI RtlpUnWaitCriticalSection(RTL_CRITICAL_SECTION *);
 
-- 
1.5.2.3






More information about the wine-patches mailing list