]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | ******************************************************************************* | |
3 | * Copyright (C) 2007-2011, International Business Machines Corporation and * | |
4 | * others. All Rights Reserved. * | |
5 | ******************************************************************************* | |
6 | */ | |
7 | #include "unicode/utypes.h" | |
8 | ||
9 | #if !UCONFIG_NO_FORMATTING | |
10 | ||
11 | #include "tzoffloc.h" | |
12 | ||
13 | #include "unicode/ucal.h" | |
14 | #include "unicode/timezone.h" | |
15 | #include "unicode/calendar.h" | |
16 | #include "unicode/dtrule.h" | |
17 | #include "unicode/tzrule.h" | |
18 | #include "unicode/rbtz.h" | |
19 | #include "unicode/simpletz.h" | |
20 | #include "unicode/tzrule.h" | |
21 | #include "unicode/smpdtfmt.h" | |
22 | #include "unicode/gregocal.h" | |
23 | ||
24 | void | |
25 | TimeZoneOffsetLocalTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) | |
26 | { | |
27 | if (exec) { | |
28 | logln("TestSuite TimeZoneOffsetLocalTest"); | |
29 | } | |
30 | switch (index) { | |
31 | TESTCASE(0, TestGetOffsetAroundTransition); | |
32 | default: name = ""; break; | |
33 | } | |
34 | } | |
35 | ||
36 | /* | |
37 | * Testing getOffset APIs around rule transition by local standard/wall time. | |
38 | */ | |
39 | void | |
40 | TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() { | |
41 | const int32_t NUM_DATES = 10; | |
42 | const int32_t NUM_TIMEZONES = 3; | |
43 | ||
44 | const int32_t HOUR = 60*60*1000; | |
45 | const int32_t MINUTE = 60*1000; | |
46 | ||
47 | const int32_t DATES[NUM_DATES][6] = { | |
48 | {2006, UCAL_APRIL, 2, 1, 30, 1*HOUR+30*MINUTE}, | |
49 | {2006, UCAL_APRIL, 2, 2, 00, 2*HOUR}, | |
50 | {2006, UCAL_APRIL, 2, 2, 30, 2*HOUR+30*MINUTE}, | |
51 | {2006, UCAL_APRIL, 2, 3, 00, 3*HOUR}, | |
52 | {2006, UCAL_APRIL, 2, 3, 30, 3*HOUR+30*MINUTE}, | |
53 | {2006, UCAL_OCTOBER, 29, 0, 30, 0*HOUR+30*MINUTE}, | |
54 | {2006, UCAL_OCTOBER, 29, 1, 00, 1*HOUR}, | |
55 | {2006, UCAL_OCTOBER, 29, 1, 30, 1*HOUR+30*MINUTE}, | |
56 | {2006, UCAL_OCTOBER, 29, 2, 00, 2*HOUR}, | |
57 | {2006, UCAL_OCTOBER, 29, 2, 30, 2*HOUR+30*MINUTE}, | |
58 | }; | |
59 | ||
60 | // Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, | |
61 | // uint8_t dayOfWeek, int32_t millis, UErrorCode& status) | |
62 | const int32_t OFFSETS1[NUM_DATES] = { | |
63 | // April 2, 2006 | |
64 | -8*HOUR, | |
65 | -7*HOUR, | |
66 | -7*HOUR, | |
67 | -7*HOUR, | |
68 | -7*HOUR, | |
69 | ||
70 | // October 29, 2006 | |
71 | -7*HOUR, | |
72 | -8*HOUR, | |
73 | -8*HOUR, | |
74 | -8*HOUR, | |
75 | -8*HOUR, | |
76 | }; | |
77 | ||
78 | // Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset, | |
79 | // int32_t& dstOffset, UErrorCode& ec) with local=TRUE | |
80 | // or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, | |
81 | // int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with | |
82 | // nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard | |
83 | const int32_t OFFSETS2[NUM_DATES][2] = { | |
84 | // April 2, 2006 | |
85 | {-8*HOUR, 0}, | |
86 | {-8*HOUR, 0}, | |
87 | {-8*HOUR, 0}, | |
88 | {-8*HOUR, 1*HOUR}, | |
89 | {-8*HOUR, 1*HOUR}, | |
90 | ||
91 | // Oct 29, 2006 | |
92 | {-8*HOUR, 1*HOUR}, | |
93 | {-8*HOUR, 0}, | |
94 | {-8*HOUR, 0}, | |
95 | {-8*HOUR, 0}, | |
96 | {-8*HOUR, 0}, | |
97 | }; | |
98 | ||
99 | // Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, | |
100 | // int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with | |
101 | // nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight | |
102 | const int32_t OFFSETS3[][2] = { | |
103 | // April 2, 2006 | |
104 | {-8*HOUR, 0}, | |
105 | {-8*HOUR, 1*HOUR}, | |
106 | {-8*HOUR, 1*HOUR}, | |
107 | {-8*HOUR, 1*HOUR}, | |
108 | {-8*HOUR, 1*HOUR}, | |
109 | ||
110 | // October 29, 2006 | |
111 | {-8*HOUR, 1*HOUR}, | |
112 | {-8*HOUR, 1*HOUR}, | |
113 | {-8*HOUR, 1*HOUR}, | |
114 | {-8*HOUR, 0}, | |
115 | {-8*HOUR, 0}, | |
116 | }; | |
117 | ||
118 | UErrorCode status = U_ZERO_ERROR; | |
119 | ||
120 | int32_t rawOffset, dstOffset; | |
121 | TimeZone* utc = TimeZone::createTimeZone("UTC"); | |
122 | Calendar* cal = Calendar::createInstance(*utc, status); | |
123 | if (U_FAILURE(status)) { | |
124 | dataerrln("Calendar::createInstance failed: %s", u_errorName(status)); | |
125 | return; | |
126 | } | |
127 | cal->clear(); | |
128 | ||
129 | // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone | |
130 | BasicTimeZone *TESTZONES[NUM_TIMEZONES]; | |
131 | ||
132 | TESTZONES[0] = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles"); | |
133 | TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time", | |
134 | UCAL_APRIL, 1, UCAL_SUNDAY, 2*HOUR, | |
135 | UCAL_OCTOBER, -1, UCAL_SUNDAY, 2*HOUR, status); | |
136 | if (U_FAILURE(status)) { | |
137 | errln("SimpleTimeZone constructor failed"); | |
138 | return; | |
139 | } | |
140 | ||
141 | InitialTimeZoneRule *ir = new InitialTimeZoneRule( | |
142 | "Pacific Standard Time", // Initial time Name | |
143 | -8*HOUR, // Raw offset | |
144 | 0*HOUR); // DST saving amount | |
145 | ||
146 | RuleBasedTimeZone *rbPT = new RuleBasedTimeZone("Rule based Pacific Time", ir); | |
147 | ||
148 | DateTimeRule *dtr; | |
149 | AnnualTimeZoneRule *atzr; | |
150 | const int32_t STARTYEAR = 2000; | |
151 | ||
152 | dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY, | |
153 | 2*HOUR, DateTimeRule::WALL_TIME); // 1st Sunday in April, at 2AM wall time | |
154 | atzr = new AnnualTimeZoneRule("Pacific Daylight Time", | |
155 | -8*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr, | |
156 | STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); | |
157 | rbPT->addTransitionRule(atzr, status); | |
158 | if (U_FAILURE(status)) { | |
159 | errln("Could not add DST start rule to the RuleBasedTimeZone rbPT"); | |
160 | return; | |
161 | } | |
162 | ||
163 | dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY, | |
164 | 2*HOUR, DateTimeRule::WALL_TIME); // last Sunday in October, at 2AM wall time | |
165 | atzr = new AnnualTimeZoneRule("Pacific Standard Time", | |
166 | -8*HOUR /* rawOffset */, 0 /* dstSavings */, dtr, | |
167 | STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); | |
168 | rbPT->addTransitionRule(atzr, status); | |
169 | if (U_FAILURE(status)) { | |
170 | errln("Could not add STD start rule to the RuleBasedTimeZone rbPT"); | |
171 | return; | |
172 | } | |
173 | ||
174 | rbPT->complete(status); | |
175 | if (U_FAILURE(status)) { | |
176 | errln("complete() failed for RuleBasedTimeZone rbPT"); | |
177 | return; | |
178 | } | |
179 | ||
180 | TESTZONES[2] = rbPT; | |
181 | ||
182 | // Calculate millis | |
183 | UDate MILLIS[NUM_DATES]; | |
184 | for (int32_t i = 0; i < NUM_DATES; i++) { | |
185 | cal->clear(); | |
186 | cal->set(DATES[i][0], DATES[i][1], DATES[i][2], DATES[i][3], DATES[i][4]); | |
187 | MILLIS[i] = cal->getTime(status); | |
188 | if (U_FAILURE(status)) { | |
189 | errln("cal->getTime failed"); | |
190 | return; | |
191 | } | |
192 | } | |
193 | ||
194 | SimpleDateFormat df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status); | |
195 | if (U_FAILURE(status)) { | |
196 | dataerrln("Failed to initialize a SimpleDateFormat - %s", u_errorName(status)); | |
197 | } | |
198 | df.setTimeZone(*utc); | |
199 | UnicodeString dateStr; | |
200 | ||
201 | // Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, | |
202 | // uint8_t dayOfWeek, int32_t millis, UErrorCode& status) | |
203 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
204 | for (int32_t d = 0; d < NUM_DATES; d++) { | |
205 | status = U_ZERO_ERROR; | |
206 | int32_t offset = TESTZONES[i]->getOffset(GregorianCalendar::AD, DATES[d][0], DATES[d][1], DATES[d][2], | |
207 | UCAL_SUNDAY, DATES[d][5], status); | |
208 | if (U_FAILURE(status)) { | |
209 | errln((UnicodeString)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i + "]"); | |
210 | } else if (offset != OFFSETS1[d]) { | |
211 | dateStr.remove(); | |
212 | df.format(MILLIS[d], dateStr); | |
213 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
214 | + dateStr + "(standard) - Got: " + offset + " Expected: " + OFFSETS1[d]); | |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | // Test getOffset(UDate date, UBool local, int32_t& rawOffset, | |
220 | // int32_t& dstOffset, UErrorCode& ec) with local = TRUE | |
221 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
222 | for (int32_t m = 0; m < NUM_DATES; m++) { | |
223 | status = U_ZERO_ERROR; | |
224 | TESTZONES[i]->getOffset(MILLIS[m], TRUE, rawOffset, dstOffset, status); | |
225 | if (U_FAILURE(status)) { | |
226 | errln((UnicodeString)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i + "]"); | |
227 | } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) { | |
228 | dateStr.remove(); | |
229 | df.format(MILLIS[m], dateStr); | |
230 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
231 | + dateStr + "(wall) - Got: " | |
232 | + rawOffset + "/" + dstOffset | |
233 | + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]); | |
234 | } | |
235 | } | |
236 | } | |
237 | ||
238 | // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, | |
239 | // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status) | |
240 | // with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard | |
241 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
242 | for (int m = 0; m < NUM_DATES; m++) { | |
243 | status = U_ZERO_ERROR; | |
244 | TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kStandard, BasicTimeZone::kStandard, | |
245 | rawOffset, dstOffset, status); | |
246 | if (U_FAILURE(status)) { | |
247 | errln((UnicodeString)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i + "]"); | |
248 | } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) { | |
249 | dateStr.remove(); | |
250 | df.format(MILLIS[m], dateStr); | |
251 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
252 | + dateStr + "(wall/kStandard/kStandard) - Got: " | |
253 | + rawOffset + "/" + dstOffset | |
254 | + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]); | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, | |
260 | // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status) | |
261 | // with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight | |
262 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
263 | for (int m = 0; m < NUM_DATES; m++) { | |
264 | status = U_ZERO_ERROR; | |
265 | TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, | |
266 | rawOffset, dstOffset, status); | |
267 | if (U_FAILURE(status)) { | |
268 | errln((UnicodeString)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i + "]"); | |
269 | } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) { | |
270 | dateStr.remove(); | |
271 | df.format(MILLIS[m], dateStr); | |
272 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
273 | + dateStr + "(wall/kDaylight/kDaylight) - Got: " | |
274 | + rawOffset + "/" + dstOffset | |
275 | + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]); | |
276 | } | |
277 | } | |
278 | } | |
279 | ||
280 | // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, | |
281 | // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status) | |
282 | // with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter | |
283 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
284 | for (int m = 0; m < NUM_DATES; m++) { | |
285 | status = U_ZERO_ERROR; | |
286 | TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kFormer, BasicTimeZone::kLatter, | |
287 | rawOffset, dstOffset, status); | |
288 | if (U_FAILURE(status)) { | |
289 | errln((UnicodeString)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i + "]"); | |
290 | } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) { | |
291 | dateStr.remove(); | |
292 | df.format(MILLIS[m], dateStr); | |
293 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
294 | + dateStr + "(wall/kFormer/kLatter) - Got: " | |
295 | + rawOffset + "/" + dstOffset | |
296 | + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]); | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
301 | // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, | |
302 | // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status) | |
303 | // with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer | |
304 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
305 | for (int m = 0; m < NUM_DATES; m++) { | |
306 | status = U_ZERO_ERROR; | |
307 | TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kLatter, BasicTimeZone::kFormer, | |
308 | rawOffset, dstOffset, status); | |
309 | if (U_FAILURE(status)) { | |
310 | errln((UnicodeString)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i + "]"); | |
311 | } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) { | |
312 | dateStr.remove(); | |
313 | df.format(MILLIS[m], dateStr); | |
314 | dataerrln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at " | |
315 | + dateStr + "(wall/kLatter/kFormer) - Got: " | |
316 | + rawOffset + "/" + dstOffset | |
317 | + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]); | |
318 | } | |
319 | } | |
320 | } | |
321 | ||
322 | for (int32_t i = 0; i < NUM_TIMEZONES; i++) { | |
323 | delete TESTZONES[i]; | |
324 | } | |
325 | delete utc; | |
326 | delete cal; | |
327 | } | |
328 | ||
329 | #endif /* #if !UCONFIG_NO_FORMATTING */ |