1/*
2********************************************************************************
3*   Copyright (C) 2009-2011, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5********************************************************************************
6*
7* File WINTZIMPL.CPP
8*
9********************************************************************************
10*/
11
12#include "unicode/utypes.h"
13
14#if U_PLATFORM_HAS_WIN32_API
15
16#include "wintzimpl.h"
17
18#include "unicode/unistr.h"
19#include "unicode/timezone.h"
20#include "unicode/basictz.h"
21#include "putilimp.h"
22#include "uassert.h"
23#include "cmemory.h"
24
25#   define WIN32_LEAN_AND_MEAN
26#   define VC_EXTRALEAN
27#   define NOUSER
28#   define NOSERVICE
29#   define NOIME
30#   define NOMCX
31
32#include <windows.h>
33
34U_NAMESPACE_USE
35
36static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SYSTEMTIME &standardDate, int32_t &bias, int32_t &daylightBias, int32_t &standardBias) {
37    UErrorCode status = U_ZERO_ERROR;
38    UBool result = TRUE;
39    BasicTimeZone *btz = (BasicTimeZone*)tz; // we should check type
40    InitialTimeZoneRule *initial = NULL;
41    AnnualTimeZoneRule *std = NULL, *dst = NULL;
42
43    btz->getSimpleRulesNear(uprv_getUTCtime(), initial, std, dst, status);
44    if (U_SUCCESS(status)) {
45        if (std == NULL || dst == NULL) {
46            bias = -1 * (initial->getRawOffset()/60000);
47            standardBias = 0;
48            daylightBias = 0;
49            // Do not use DST.  Set 0 to all stadardDate/daylightDate fields
50            standardDate.wYear = standardDate.wMonth  = standardDate.wDayOfWeek = standardDate.wDay =
51            standardDate.wHour = standardDate.wMinute = standardDate.wSecond    = standardDate.wMilliseconds = 0;
52            daylightDate.wYear = daylightDate.wMonth  = daylightDate.wDayOfWeek = daylightDate.wDay =
53            daylightDate.wHour = daylightDate.wMinute = daylightDate.wSecond    = daylightDate.wMilliseconds = 0;
54        } else {
55            U_ASSERT(std->getRule()->getDateRuleType() == DateTimeRule::DOW);
56            U_ASSERT(dst->getRule()->getDateRuleType() == DateTimeRule::DOW);
57
58            bias = -1 * (std->getRawOffset()/60000);
59            standardBias = 0;
60            daylightBias = -1 * (dst->getDSTSavings()/60000);
61            // Always use DOW type rule
62            int32_t hour, min, sec, mil;
63            standardDate.wYear = 0;
64            standardDate.wMonth = std->getRule()->getRuleMonth() + 1;
65            standardDate.wDay = std->getRule()->getRuleWeekInMonth();
66            if (standardDate.wDay < 0) {
67                standardDate.wDay = 5;
68            }
69            standardDate.wDayOfWeek = std->getRule()->getRuleDayOfWeek() - 1;
70
71            mil = std->getRule()->getRuleMillisInDay();
72            hour = mil/3600000;
73            mil %= 3600000;
74            min = mil/60000;
75            mil %= 60000;
76            sec = mil/1000;
77            mil %= 1000;
78
79            standardDate.wHour = hour;
80            standardDate.wMinute = min;
81            standardDate.wSecond = sec;
82            standardDate.wMilliseconds = mil;
83
84            daylightDate.wYear = 0;
85            daylightDate.wMonth = dst->getRule()->getRuleMonth() + 1;
86            daylightDate.wDay = dst->getRule()->getRuleWeekInMonth();
87            if (daylightDate.wDay < 0) {
88                daylightDate.wDay = 5;
89            }
90            daylightDate.wDayOfWeek = dst->getRule()->getRuleDayOfWeek() - 1;
91
92            mil = dst->getRule()->getRuleMillisInDay();
93            hour = mil/3600000;
94            mil %= 3600000;
95            min = mil/60000;
96            mil %= 60000;
97            sec = mil/1000;
98            mil %= 1000;
99
100            daylightDate.wHour = hour;
101            daylightDate.wMinute = min;
102            daylightDate.wSecond = sec;
103            daylightDate.wMilliseconds = mil;
104        }
105    } else {
106        result = FALSE;
107    }
108
109    delete initial;
110    delete std;
111    delete dst;
112
113    return result;
114}
115
116static UBool getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length) {
117    UBool result = FALSE;
118    UnicodeString id = UnicodeString(icuid, length);
119    TimeZone *tz = TimeZone::createTimeZone(id);
120
121    if (tz != NULL) {
122        int32_t bias;
123        int32_t daylightBias;
124        int32_t standardBias;
125        SYSTEMTIME daylightDate;
126        SYSTEMTIME standardDate;
127
128        if (getSystemTimeInformation(tz, daylightDate, standardDate, bias, daylightBias, standardBias)) {
129            uprv_memset(zoneInfo, 0, sizeof(TIME_ZONE_INFORMATION)); // We do not set standard/daylight names, so nullify first.
130            zoneInfo->Bias          = bias;
131            zoneInfo->DaylightBias  = daylightBias;
132            zoneInfo->StandardBias  = standardBias;
133            zoneInfo->DaylightDate  = daylightDate;
134            zoneInfo->StandardDate  = standardDate;
135
136            result = TRUE;
137        }
138    }
139
140    return result;
141}
142
143/*
144 * Given the timezone icuid, fill in zoneInfo by calling auxillary functions that creates a timezone and extract the
145 * information to put into zoneInfo. This includes bias and standard time date and daylight saving date.
146 */
147U_CAPI UBool U_EXPORT2
148uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length)
149{
150    if (getWindowsTimeZoneInfo(zoneInfo, icuid, length)) {
151        return TRUE;
152    } else {
153        return FALSE;
154    }
155}
156
157#endif
158