summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n/wintzimpl.cpp
blob: c55ed95fa8aea20b80ae628dfc1d0cd0d32cab00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
*   Copyright (C) 2009-2013, International Business Machines
*   Corporation and others.  All Rights Reserved.
********************************************************************************
*
* File WINTZIMPL.CPP
*
********************************************************************************
*/

#include "unicode/utypes.h"

#if U_PLATFORM_USES_ONLY_WIN32_API && !UCONFIG_NO_FORMATTING

#include "wintzimpl.h"

#include "unicode/unistr.h"
#include "unicode/timezone.h"
#include "unicode/basictz.h"
#include "putilimp.h"
#include "uassert.h"
#include "cmemory.h"

#ifndef WIN32_LEAN_AND_MEAN
#   define WIN32_LEAN_AND_MEAN
#endif
#   define VC_EXTRALEAN
#   define NOUSER
#   define NOSERVICE
#   define NOIME
#   define NOMCX

#include <windows.h>

U_NAMESPACE_USE

static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SYSTEMTIME &standardDate, int32_t &bias, int32_t &daylightBias, int32_t &standardBias) {
    UErrorCode status = U_ZERO_ERROR;
    UBool result = TRUE;
    BasicTimeZone *btz = (BasicTimeZone*)tz; // we should check type
    InitialTimeZoneRule *initial = NULL;
    AnnualTimeZoneRule *std = NULL, *dst = NULL;

    btz->getSimpleRulesNear(uprv_getUTCtime(), initial, std, dst, status);
    if (U_SUCCESS(status)) {
        if (std == NULL || dst == NULL) {
            bias = -1 * (initial->getRawOffset()/60000);
            standardBias = 0;
            daylightBias = 0;
            // Do not use DST.  Set 0 to all stadardDate/daylightDate fields
            standardDate.wYear = standardDate.wMonth  = standardDate.wDayOfWeek = standardDate.wDay =
            standardDate.wHour = standardDate.wMinute = standardDate.wSecond    = standardDate.wMilliseconds = 0;
            daylightDate.wYear = daylightDate.wMonth  = daylightDate.wDayOfWeek = daylightDate.wDay =
            daylightDate.wHour = daylightDate.wMinute = daylightDate.wSecond    = daylightDate.wMilliseconds = 0;
        } else {
            U_ASSERT(std->getRule()->getDateRuleType() == DateTimeRule::DOW);
            U_ASSERT(dst->getRule()->getDateRuleType() == DateTimeRule::DOW);

            bias = -1 * (std->getRawOffset()/60000);
            standardBias = 0;
            daylightBias = -1 * (dst->getDSTSavings()/60000);
            // Always use DOW type rule
            int32_t hour, min, sec, mil;
            standardDate.wYear = 0;
            standardDate.wMonth = static_cast<WORD>(std->getRule()->getRuleMonth()) + 1;
            standardDate.wDay = static_cast<WORD>(std->getRule()->getRuleWeekInMonth());
            if (standardDate.wDay < 0) {
                standardDate.wDay = 5;
            }
            standardDate.wDayOfWeek = static_cast<WORD>(std->getRule()->getRuleDayOfWeek()) - 1;

            mil = std->getRule()->getRuleMillisInDay();
            hour = mil/3600000;
            mil %= 3600000;
            min = mil/60000;
            mil %= 60000;
            sec = mil/1000;
            mil %= 1000;

            standardDate.wHour = static_cast<WORD>(hour);
            standardDate.wMinute = static_cast<WORD>(min);
            standardDate.wSecond = static_cast<WORD>(sec);
            standardDate.wMilliseconds = static_cast<WORD>(mil);

            daylightDate.wYear = 0;
            daylightDate.wMonth = static_cast<WORD>(dst->getRule()->getRuleMonth()) + 1;
            daylightDate.wDay = static_cast<WORD>(dst->getRule()->getRuleWeekInMonth());
            if (daylightDate.wDay < 0) {
                daylightDate.wDay = 5;
            }
            daylightDate.wDayOfWeek = static_cast<WORD>(dst->getRule()->getRuleDayOfWeek()) - 1;

            mil = dst->getRule()->getRuleMillisInDay();
            hour = mil/3600000;
            mil %= 3600000;
            min = mil/60000;
            mil %= 60000;
            sec = mil/1000;
            mil %= 1000;

            daylightDate.wHour = static_cast<WORD>(hour);
            daylightDate.wMinute = static_cast<WORD>(min);
            daylightDate.wSecond = static_cast<WORD>(sec);
            daylightDate.wMilliseconds = static_cast<WORD>(mil);
        }
    } else {
        result = FALSE;
    }

    delete initial;
    delete std;
    delete dst;

    return result;
}

static UBool getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length) {
    UBool result = FALSE;
    UnicodeString id = UnicodeString(icuid, length);
    TimeZone *tz = TimeZone::createTimeZone(id);

    if (tz != NULL) {
        int32_t bias;
        int32_t daylightBias;
        int32_t standardBias;
        SYSTEMTIME daylightDate;
        SYSTEMTIME standardDate;

        if (getSystemTimeInformation(tz, daylightDate, standardDate, bias, daylightBias, standardBias)) {
            uprv_memset(zoneInfo, 0, sizeof(TIME_ZONE_INFORMATION)); // We do not set standard/daylight names, so nullify first.
            zoneInfo->Bias          = bias;
            zoneInfo->DaylightBias  = daylightBias;
            zoneInfo->StandardBias  = standardBias;
            zoneInfo->DaylightDate  = daylightDate;
            zoneInfo->StandardDate  = standardDate;

            result = TRUE;
        }
    }

    return result;
}

/*
 * Given the timezone icuid, fill in zoneInfo by calling auxillary functions that creates a timezone and extract the
 * information to put into zoneInfo. This includes bias and standard time date and daylight saving date.
 */
U_CAPI UBool U_EXPORT2
uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length)
{
    if (getWindowsTimeZoneInfo(zoneInfo, icuid, length)) {
        return TRUE;
    } else {
        return FALSE;
    }
}

#endif