1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2007-2011, International Business Machines Corporation and *
6 * others. All Rights Reserved. *
7 *******************************************************************************
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/ucal.h"
16 #include "unicode/timezone.h"
17 #include "unicode/calendar.h"
18 #include "unicode/dtrule.h"
19 #include "unicode/tzrule.h"
20 #include "unicode/rbtz.h"
21 #include "unicode/simpletz.h"
22 #include "unicode/tzrule.h"
23 #include "unicode/smpdtfmt.h"
24 #include "unicode/gregocal.h"
27 TimeZoneOffsetLocalTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
30 logln("TestSuite TimeZoneOffsetLocalTest");
33 TESTCASE(0, TestGetOffsetAroundTransition
);
34 default: name
= ""; break;
39 * Testing getOffset APIs around rule transition by local standard/wall time.
42 TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() {
43 const int32_t NUM_DATES
= 10;
44 const int32_t NUM_TIMEZONES
= 3;
46 const int32_t HOUR
= 60*60*1000;
47 const int32_t MINUTE
= 60*1000;
49 const int32_t DATES
[NUM_DATES
][6] = {
50 {2006, UCAL_APRIL
, 2, 1, 30, 1*HOUR
+30*MINUTE
},
51 {2006, UCAL_APRIL
, 2, 2, 00, 2*HOUR
},
52 {2006, UCAL_APRIL
, 2, 2, 30, 2*HOUR
+30*MINUTE
},
53 {2006, UCAL_APRIL
, 2, 3, 00, 3*HOUR
},
54 {2006, UCAL_APRIL
, 2, 3, 30, 3*HOUR
+30*MINUTE
},
55 {2006, UCAL_OCTOBER
, 29, 0, 30, 0*HOUR
+30*MINUTE
},
56 {2006, UCAL_OCTOBER
, 29, 1, 00, 1*HOUR
},
57 {2006, UCAL_OCTOBER
, 29, 1, 30, 1*HOUR
+30*MINUTE
},
58 {2006, UCAL_OCTOBER
, 29, 2, 00, 2*HOUR
},
59 {2006, UCAL_OCTOBER
, 29, 2, 30, 2*HOUR
+30*MINUTE
},
62 // Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
63 // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
64 const int32_t OFFSETS1
[NUM_DATES
] = {
80 // Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset,
81 // int32_t& dstOffset, UErrorCode& ec) with local=TRUE
82 // or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
83 // int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
84 // nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
85 const int32_t OFFSETS2
[NUM_DATES
][2] = {
101 // Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt,
102 // int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
103 // nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
104 const int32_t OFFSETS3
[][2] = {
120 UErrorCode status
= U_ZERO_ERROR
;
122 int32_t rawOffset
, dstOffset
;
123 TimeZone
* utc
= TimeZone::createTimeZone("UTC");
124 Calendar
* cal
= Calendar::createInstance(*utc
, status
);
125 if (U_FAILURE(status
)) {
126 dataerrln("Calendar::createInstance failed: %s", u_errorName(status
));
131 // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
132 BasicTimeZone
*TESTZONES
[NUM_TIMEZONES
];
134 TESTZONES
[0] = (BasicTimeZone
*)TimeZone::createTimeZone("America/Los_Angeles");
135 TESTZONES
[1] = new SimpleTimeZone(-8*HOUR
, "Simple Pacific Time",
136 UCAL_APRIL
, 1, UCAL_SUNDAY
, 2*HOUR
,
137 UCAL_OCTOBER
, -1, UCAL_SUNDAY
, 2*HOUR
, status
);
138 if (U_FAILURE(status
)) {
139 errln("SimpleTimeZone constructor failed");
143 InitialTimeZoneRule
*ir
= new InitialTimeZoneRule(
144 "Pacific Standard Time", // Initial time Name
145 -8*HOUR
, // Raw offset
146 0*HOUR
); // DST saving amount
148 RuleBasedTimeZone
*rbPT
= new RuleBasedTimeZone("Rule based Pacific Time", ir
);
151 AnnualTimeZoneRule
*atzr
;
152 const int32_t STARTYEAR
= 2000;
154 dtr
= new DateTimeRule(UCAL_APRIL
, 1, UCAL_SUNDAY
,
155 2*HOUR
, DateTimeRule::WALL_TIME
); // 1st Sunday in April, at 2AM wall time
156 atzr
= new AnnualTimeZoneRule("Pacific Daylight Time",
157 -8*HOUR
/* rawOffset */, 1*HOUR
/* dstSavings */, dtr
,
158 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
159 rbPT
->addTransitionRule(atzr
, status
);
160 if (U_FAILURE(status
)) {
161 errln("Could not add DST start rule to the RuleBasedTimeZone rbPT");
165 dtr
= new DateTimeRule(UCAL_OCTOBER
, -1, UCAL_SUNDAY
,
166 2*HOUR
, DateTimeRule::WALL_TIME
); // last Sunday in October, at 2AM wall time
167 atzr
= new AnnualTimeZoneRule("Pacific Standard Time",
168 -8*HOUR
/* rawOffset */, 0 /* dstSavings */, dtr
,
169 STARTYEAR
, AnnualTimeZoneRule::MAX_YEAR
);
170 rbPT
->addTransitionRule(atzr
, status
);
171 if (U_FAILURE(status
)) {
172 errln("Could not add STD start rule to the RuleBasedTimeZone rbPT");
176 rbPT
->complete(status
);
177 if (U_FAILURE(status
)) {
178 errln("complete() failed for RuleBasedTimeZone rbPT");
185 UDate MILLIS
[NUM_DATES
];
186 for (int32_t i
= 0; i
< NUM_DATES
; i
++) {
188 cal
->set(DATES
[i
][0], DATES
[i
][1], DATES
[i
][2], DATES
[i
][3], DATES
[i
][4]);
189 MILLIS
[i
] = cal
->getTime(status
);
190 if (U_FAILURE(status
)) {
191 errln("cal->getTime failed");
196 SimpleDateFormat
df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status
);
197 if (U_FAILURE(status
)) {
198 dataerrln("Failed to initialize a SimpleDateFormat - %s", u_errorName(status
));
200 df
.setTimeZone(*utc
);
201 UnicodeString dateStr
;
203 // Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
204 // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
205 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
206 for (int32_t d
= 0; d
< NUM_DATES
; d
++) {
207 status
= U_ZERO_ERROR
;
208 int32_t offset
= TESTZONES
[i
]->getOffset(GregorianCalendar::AD
, DATES
[d
][0], DATES
[d
][1], DATES
[d
][2],
209 UCAL_SUNDAY
, DATES
[d
][5], status
);
210 if (U_FAILURE(status
)) {
211 errln((UnicodeString
)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i
+ "]");
212 } else if (offset
!= OFFSETS1
[d
]) {
214 df
.format(MILLIS
[d
], dateStr
);
215 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
216 + dateStr
+ "(standard) - Got: " + offset
+ " Expected: " + OFFSETS1
[d
]);
221 // Test getOffset(UDate date, UBool local, int32_t& rawOffset,
222 // int32_t& dstOffset, UErrorCode& ec) with local = TRUE
223 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
224 for (int32_t m
= 0; m
< NUM_DATES
; m
++) {
225 status
= U_ZERO_ERROR
;
226 TESTZONES
[i
]->getOffset(MILLIS
[m
], TRUE
, rawOffset
, dstOffset
, status
);
227 if (U_FAILURE(status
)) {
228 errln((UnicodeString
)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i
+ "]");
229 } else if (rawOffset
!= OFFSETS2
[m
][0] || dstOffset
!= OFFSETS2
[m
][1]) {
231 df
.format(MILLIS
[m
], dateStr
);
232 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
233 + dateStr
+ "(wall) - Got: "
234 + rawOffset
+ "/" + dstOffset
235 + " Expected: " + OFFSETS2
[m
][0] + "/" + OFFSETS2
[m
][1]);
240 // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
241 // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
242 // with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
243 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
244 for (int m
= 0; m
< NUM_DATES
; m
++) {
245 status
= U_ZERO_ERROR
;
246 TESTZONES
[i
]->getOffsetFromLocal(MILLIS
[m
], BasicTimeZone::kStandard
, BasicTimeZone::kStandard
,
247 rawOffset
, dstOffset
, status
);
248 if (U_FAILURE(status
)) {
249 errln((UnicodeString
)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i
+ "]");
250 } else if (rawOffset
!= OFFSETS2
[m
][0] || dstOffset
!= OFFSETS2
[m
][1]) {
252 df
.format(MILLIS
[m
], dateStr
);
253 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
254 + dateStr
+ "(wall/kStandard/kStandard) - Got: "
255 + rawOffset
+ "/" + dstOffset
256 + " Expected: " + OFFSETS2
[m
][0] + "/" + OFFSETS2
[m
][1]);
261 // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
262 // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
263 // with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
264 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
265 for (int m
= 0; m
< NUM_DATES
; m
++) {
266 status
= U_ZERO_ERROR
;
267 TESTZONES
[i
]->getOffsetFromLocal(MILLIS
[m
], BasicTimeZone::kDaylight
, BasicTimeZone::kDaylight
,
268 rawOffset
, dstOffset
, status
);
269 if (U_FAILURE(status
)) {
270 errln((UnicodeString
)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i
+ "]");
271 } else if (rawOffset
!= OFFSETS3
[m
][0] || dstOffset
!= OFFSETS3
[m
][1]) {
273 df
.format(MILLIS
[m
], dateStr
);
274 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
275 + dateStr
+ "(wall/kDaylight/kDaylight) - Got: "
276 + rawOffset
+ "/" + dstOffset
277 + " Expected: " + OFFSETS3
[m
][0] + "/" + OFFSETS3
[m
][1]);
282 // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
283 // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
284 // with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter
285 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
286 for (int m
= 0; m
< NUM_DATES
; m
++) {
287 status
= U_ZERO_ERROR
;
288 TESTZONES
[i
]->getOffsetFromLocal(MILLIS
[m
], BasicTimeZone::kFormer
, BasicTimeZone::kLatter
,
289 rawOffset
, dstOffset
, status
);
290 if (U_FAILURE(status
)) {
291 errln((UnicodeString
)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i
+ "]");
292 } else if (rawOffset
!= OFFSETS2
[m
][0] || dstOffset
!= OFFSETS2
[m
][1]) {
294 df
.format(MILLIS
[m
], dateStr
);
295 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
296 + dateStr
+ "(wall/kFormer/kLatter) - Got: "
297 + rawOffset
+ "/" + dstOffset
298 + " Expected: " + OFFSETS2
[m
][0] + "/" + OFFSETS2
[m
][1]);
303 // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
304 // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
305 // with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer
306 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
307 for (int m
= 0; m
< NUM_DATES
; m
++) {
308 status
= U_ZERO_ERROR
;
309 TESTZONES
[i
]->getOffsetFromLocal(MILLIS
[m
], BasicTimeZone::kLatter
, BasicTimeZone::kFormer
,
310 rawOffset
, dstOffset
, status
);
311 if (U_FAILURE(status
)) {
312 errln((UnicodeString
)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i
+ "]");
313 } else if (rawOffset
!= OFFSETS3
[m
][0] || dstOffset
!= OFFSETS3
[m
][1]) {
315 df
.format(MILLIS
[m
], dateStr
);
316 dataerrln((UnicodeString
)"Bad offset returned by TESTZONES[" + i
+ "] at "
317 + dateStr
+ "(wall/kLatter/kFormer) - Got: "
318 + rawOffset
+ "/" + dstOffset
319 + " Expected: " + OFFSETS3
[m
][0] + "/" + OFFSETS3
[m
][1]);
324 for (int32_t i
= 0; i
< NUM_TIMEZONES
; i
++) {
331 #endif /* #if !UCONFIG_NO_FORMATTING */