|
1 /* |
|
2 ******************************************************************************* |
|
3 * Copyright (C) 2007-2013, International Business Machines Corporation and |
|
4 * others. All Rights Reserved. |
|
5 ******************************************************************************* |
|
6 */ |
|
7 |
|
8 #include "unicode/utypes.h" |
|
9 |
|
10 #if !UCONFIG_NO_FORMATTING |
|
11 |
|
12 #include "unicode/basictz.h" |
|
13 #include "gregoimp.h" |
|
14 #include "uvector.h" |
|
15 #include "cmemory.h" |
|
16 |
|
17 U_NAMESPACE_BEGIN |
|
18 |
|
19 #define MILLIS_PER_YEAR (365*24*60*60*1000.0) |
|
20 |
|
21 BasicTimeZone::BasicTimeZone() |
|
22 : TimeZone() { |
|
23 } |
|
24 |
|
25 BasicTimeZone::BasicTimeZone(const UnicodeString &id) |
|
26 : TimeZone(id) { |
|
27 } |
|
28 |
|
29 BasicTimeZone::BasicTimeZone(const BasicTimeZone& source) |
|
30 : TimeZone(source) { |
|
31 } |
|
32 |
|
33 BasicTimeZone::~BasicTimeZone() { |
|
34 } |
|
35 |
|
36 UBool |
|
37 BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end, |
|
38 UBool ignoreDstAmount, UErrorCode& status) const { |
|
39 if (U_FAILURE(status)) { |
|
40 return FALSE; |
|
41 } |
|
42 if (hasSameRules(tz)) { |
|
43 return TRUE; |
|
44 } |
|
45 // Check the offsets at the start time |
|
46 int32_t raw1, raw2, dst1, dst2; |
|
47 getOffset(start, FALSE, raw1, dst1, status); |
|
48 if (U_FAILURE(status)) { |
|
49 return FALSE; |
|
50 } |
|
51 tz.getOffset(start, FALSE, raw2, dst2, status); |
|
52 if (U_FAILURE(status)) { |
|
53 return FALSE; |
|
54 } |
|
55 if (ignoreDstAmount) { |
|
56 if ((raw1 + dst1 != raw2 + dst2) |
|
57 || (dst1 != 0 && dst2 == 0) |
|
58 || (dst1 == 0 && dst2 != 0)) { |
|
59 return FALSE; |
|
60 } |
|
61 } else { |
|
62 if (raw1 != raw2 || dst1 != dst2) { |
|
63 return FALSE; |
|
64 } |
|
65 } |
|
66 // Check transitions in the range |
|
67 UDate time = start; |
|
68 TimeZoneTransition tr1, tr2; |
|
69 while (TRUE) { |
|
70 UBool avail1 = getNextTransition(time, FALSE, tr1); |
|
71 UBool avail2 = tz.getNextTransition(time, FALSE, tr2); |
|
72 |
|
73 if (ignoreDstAmount) { |
|
74 // Skip a transition which only differ the amount of DST savings |
|
75 while (TRUE) { |
|
76 if (avail1 |
|
77 && tr1.getTime() <= end |
|
78 && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings() |
|
79 == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()) |
|
80 && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) { |
|
81 getNextTransition(tr1.getTime(), FALSE, tr1); |
|
82 } else { |
|
83 break; |
|
84 } |
|
85 } |
|
86 while (TRUE) { |
|
87 if (avail2 |
|
88 && tr2.getTime() <= end |
|
89 && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() |
|
90 == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) |
|
91 && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { |
|
92 tz.getNextTransition(tr2.getTime(), FALSE, tr2); |
|
93 } else { |
|
94 break; |
|
95 } |
|
96 } |
|
97 } |
|
98 |
|
99 UBool inRange1 = (avail1 && tr1.getTime() <= end); |
|
100 UBool inRange2 = (avail2 && tr2.getTime() <= end); |
|
101 if (!inRange1 && !inRange2) { |
|
102 // No more transition in the range |
|
103 break; |
|
104 } |
|
105 if (!inRange1 || !inRange2) { |
|
106 return FALSE; |
|
107 } |
|
108 if (tr1.getTime() != tr2.getTime()) { |
|
109 return FALSE; |
|
110 } |
|
111 if (ignoreDstAmount) { |
|
112 if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings() |
|
113 != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings() |
|
114 || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0) |
|
115 || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) { |
|
116 return FALSE; |
|
117 } |
|
118 } else { |
|
119 if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() || |
|
120 tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) { |
|
121 return FALSE; |
|
122 } |
|
123 } |
|
124 time = tr1.getTime(); |
|
125 } |
|
126 return TRUE; |
|
127 } |
|
128 |
|
129 void |
|
130 BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, |
|
131 AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const { |
|
132 initial = NULL; |
|
133 std = NULL; |
|
134 dst = NULL; |
|
135 if (U_FAILURE(status)) { |
|
136 return; |
|
137 } |
|
138 int32_t initialRaw, initialDst; |
|
139 UnicodeString initialName; |
|
140 |
|
141 AnnualTimeZoneRule *ar1 = NULL; |
|
142 AnnualTimeZoneRule *ar2 = NULL; |
|
143 UnicodeString name; |
|
144 |
|
145 UBool avail; |
|
146 TimeZoneTransition tr; |
|
147 // Get the next transition |
|
148 avail = getNextTransition(date, FALSE, tr); |
|
149 if (avail) { |
|
150 tr.getFrom()->getName(initialName); |
|
151 initialRaw = tr.getFrom()->getRawOffset(); |
|
152 initialDst = tr.getFrom()->getDSTSavings(); |
|
153 |
|
154 // Check if the next transition is either DST->STD or STD->DST and |
|
155 // within roughly 1 year from the specified date |
|
156 UDate nextTransitionTime = tr.getTime(); |
|
157 if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) |
|
158 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) |
|
159 && (date + MILLIS_PER_YEAR > nextTransitionTime)) { |
|
160 |
|
161 int32_t year, month, dom, dow, doy, mid; |
|
162 UDate d; |
|
163 |
|
164 // Get local wall time for the next transition time |
|
165 Grego::timeToFields(nextTransitionTime + initialRaw + initialDst, |
|
166 year, month, dom, dow, doy, mid); |
|
167 int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); |
|
168 // Create DOW rule |
|
169 DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); |
|
170 tr.getTo()->getName(name); |
|
171 |
|
172 // Note: SimpleTimeZone does not support raw offset change. |
|
173 // So we always use raw offset of the given time for the rule, |
|
174 // even raw offset is changed. This will result that the result |
|
175 // zone to return wrong offset after the transition. |
|
176 // When we encounter such case, we do not inspect next next |
|
177 // transition for another rule. |
|
178 ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(), |
|
179 dtr, year, AnnualTimeZoneRule::MAX_YEAR); |
|
180 |
|
181 if (tr.getTo()->getRawOffset() == initialRaw) { |
|
182 // Get the next next transition |
|
183 avail = getNextTransition(nextTransitionTime, FALSE, tr); |
|
184 if (avail) { |
|
185 // Check if the next next transition is either DST->STD or STD->DST |
|
186 // and within roughly 1 year from the next transition |
|
187 if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) |
|
188 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) |
|
189 && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) { |
|
190 |
|
191 // Get local wall time for the next transition time |
|
192 Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), |
|
193 year, month, dom, dow, doy, mid); |
|
194 weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); |
|
195 // Generate another DOW rule |
|
196 dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); |
|
197 tr.getTo()->getName(name); |
|
198 ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), |
|
199 dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR); |
|
200 |
|
201 // Make sure this rule can be applied to the specified date |
|
202 avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d); |
|
203 if (!avail || d > date |
|
204 || initialRaw != tr.getTo()->getRawOffset() |
|
205 || initialDst != tr.getTo()->getDSTSavings()) { |
|
206 // We cannot use this rule as the second transition rule |
|
207 delete ar2; |
|
208 ar2 = NULL; |
|
209 } |
|
210 } |
|
211 } |
|
212 } |
|
213 if (ar2 == NULL) { |
|
214 // Try previous transition |
|
215 avail = getPreviousTransition(date, TRUE, tr); |
|
216 if (avail) { |
|
217 // Check if the previous transition is either DST->STD or STD->DST. |
|
218 // The actual transition time does not matter here. |
|
219 if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) |
|
220 || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) { |
|
221 |
|
222 // Generate another DOW rule |
|
223 Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), |
|
224 year, month, dom, dow, doy, mid); |
|
225 weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); |
|
226 dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); |
|
227 tr.getTo()->getName(name); |
|
228 |
|
229 // second rule raw/dst offsets should match raw/dst offsets |
|
230 // at the given time |
|
231 ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst, |
|
232 dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR); |
|
233 |
|
234 // Check if this rule start after the first rule after the specified date |
|
235 avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d); |
|
236 if (!avail || d <= nextTransitionTime) { |
|
237 // We cannot use this rule as the second transition rule |
|
238 delete ar2; |
|
239 ar2 = NULL; |
|
240 } |
|
241 } |
|
242 } |
|
243 } |
|
244 if (ar2 == NULL) { |
|
245 // Cannot find a good pair of AnnualTimeZoneRule |
|
246 delete ar1; |
|
247 ar1 = NULL; |
|
248 } else { |
|
249 // The initial rule should represent the rule before the previous transition |
|
250 ar1->getName(initialName); |
|
251 initialRaw = ar1->getRawOffset(); |
|
252 initialDst = ar1->getDSTSavings(); |
|
253 } |
|
254 } |
|
255 } |
|
256 else { |
|
257 // Try the previous one |
|
258 avail = getPreviousTransition(date, TRUE, tr); |
|
259 if (avail) { |
|
260 tr.getTo()->getName(initialName); |
|
261 initialRaw = tr.getTo()->getRawOffset(); |
|
262 initialDst = tr.getTo()->getDSTSavings(); |
|
263 } else { |
|
264 // No transitions in the past. Just use the current offsets |
|
265 getOffset(date, FALSE, initialRaw, initialDst, status); |
|
266 if (U_FAILURE(status)) { |
|
267 return; |
|
268 } |
|
269 } |
|
270 } |
|
271 // Set the initial rule |
|
272 initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst); |
|
273 |
|
274 // Set the standard and daylight saving rules |
|
275 if (ar1 != NULL && ar2 != NULL) { |
|
276 if (ar1->getDSTSavings() != 0) { |
|
277 dst = ar1; |
|
278 std = ar2; |
|
279 } else { |
|
280 std = ar1; |
|
281 dst = ar2; |
|
282 } |
|
283 } |
|
284 } |
|
285 |
|
286 void |
|
287 BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, |
|
288 UVector*& transitionRules, UErrorCode& status) const { |
|
289 if (U_FAILURE(status)) { |
|
290 return; |
|
291 } |
|
292 |
|
293 const InitialTimeZoneRule *orgini; |
|
294 const TimeZoneRule **orgtrs = NULL; |
|
295 TimeZoneTransition tzt; |
|
296 UBool avail; |
|
297 UVector *orgRules = NULL; |
|
298 int32_t ruleCount; |
|
299 TimeZoneRule *r = NULL; |
|
300 UBool *done = NULL; |
|
301 InitialTimeZoneRule *res_initial = NULL; |
|
302 UVector *filteredRules = NULL; |
|
303 UnicodeString name; |
|
304 int32_t i; |
|
305 UDate time, t; |
|
306 UDate *newTimes = NULL; |
|
307 UDate firstStart; |
|
308 UBool bFinalStd = FALSE, bFinalDst = FALSE; |
|
309 |
|
310 // Original transition rules |
|
311 ruleCount = countTransitionRules(status); |
|
312 if (U_FAILURE(status)) { |
|
313 return; |
|
314 } |
|
315 orgRules = new UVector(ruleCount, status); |
|
316 if (U_FAILURE(status)) { |
|
317 return; |
|
318 } |
|
319 orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount); |
|
320 if (orgtrs == NULL) { |
|
321 status = U_MEMORY_ALLOCATION_ERROR; |
|
322 goto error; |
|
323 } |
|
324 getTimeZoneRules(orgini, orgtrs, ruleCount, status); |
|
325 if (U_FAILURE(status)) { |
|
326 goto error; |
|
327 } |
|
328 for (i = 0; i < ruleCount; i++) { |
|
329 orgRules->addElement(orgtrs[i]->clone(), status); |
|
330 if (U_FAILURE(status)) { |
|
331 goto error; |
|
332 } |
|
333 } |
|
334 uprv_free(orgtrs); |
|
335 orgtrs = NULL; |
|
336 |
|
337 avail = getPreviousTransition(start, TRUE, tzt); |
|
338 if (!avail) { |
|
339 // No need to filter out rules only applicable to time before the start |
|
340 initial = orgini->clone(); |
|
341 transitionRules = orgRules; |
|
342 return; |
|
343 } |
|
344 |
|
345 done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount); |
|
346 if (done == NULL) { |
|
347 status = U_MEMORY_ALLOCATION_ERROR; |
|
348 goto error; |
|
349 } |
|
350 filteredRules = new UVector(status); |
|
351 if (U_FAILURE(status)) { |
|
352 goto error; |
|
353 } |
|
354 |
|
355 // Create initial rule |
|
356 tzt.getTo()->getName(name); |
|
357 res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), |
|
358 tzt.getTo()->getDSTSavings()); |
|
359 |
|
360 // Mark rules which does not need to be processed |
|
361 for (i = 0; i < ruleCount; i++) { |
|
362 r = (TimeZoneRule*)orgRules->elementAt(i); |
|
363 avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time); |
|
364 done[i] = !avail; |
|
365 } |
|
366 |
|
367 time = start; |
|
368 while (!bFinalStd || !bFinalDst) { |
|
369 avail = getNextTransition(time, FALSE, tzt); |
|
370 if (!avail) { |
|
371 break; |
|
372 } |
|
373 UDate updatedTime = tzt.getTime(); |
|
374 if (updatedTime == time) { |
|
375 // Can get here if rules for start & end of daylight time have exactly |
|
376 // the same time. |
|
377 // TODO: fix getNextTransition() to prevent it? |
|
378 status = U_INVALID_STATE_ERROR; |
|
379 goto error; |
|
380 } |
|
381 time = updatedTime; |
|
382 |
|
383 const TimeZoneRule *toRule = tzt.getTo(); |
|
384 for (i = 0; i < ruleCount; i++) { |
|
385 r = (TimeZoneRule*)orgRules->elementAt(i); |
|
386 if (*r == *toRule) { |
|
387 break; |
|
388 } |
|
389 } |
|
390 if (i >= ruleCount) { |
|
391 // This case should never happen |
|
392 status = U_INVALID_STATE_ERROR; |
|
393 goto error; |
|
394 } |
|
395 if (done[i]) { |
|
396 continue; |
|
397 } |
|
398 const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule); |
|
399 const AnnualTimeZoneRule *ar; |
|
400 if (tar != NULL) { |
|
401 // Get the previous raw offset and DST savings before the very first start time |
|
402 TimeZoneTransition tzt0; |
|
403 t = start; |
|
404 while (TRUE) { |
|
405 avail = getNextTransition(t, FALSE, tzt0); |
|
406 if (!avail) { |
|
407 break; |
|
408 } |
|
409 if (*(tzt0.getTo()) == *tar) { |
|
410 break; |
|
411 } |
|
412 t = tzt0.getTime(); |
|
413 } |
|
414 if (avail) { |
|
415 // Check if the entire start times to be added |
|
416 tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); |
|
417 if (firstStart > start) { |
|
418 // Just add the rule as is |
|
419 filteredRules->addElement(tar->clone(), status); |
|
420 if (U_FAILURE(status)) { |
|
421 goto error; |
|
422 } |
|
423 } else { |
|
424 // Colllect transitions after the start time |
|
425 int32_t startTimes; |
|
426 DateTimeRule::TimeRuleType timeType; |
|
427 int32_t idx; |
|
428 |
|
429 startTimes = tar->countStartTimes(); |
|
430 timeType = tar->getTimeType(); |
|
431 for (idx = 0; idx < startTimes; idx++) { |
|
432 tar->getStartTimeAt(idx, t); |
|
433 if (timeType == DateTimeRule::STANDARD_TIME) { |
|
434 t -= tzt.getFrom()->getRawOffset(); |
|
435 } |
|
436 if (timeType == DateTimeRule::WALL_TIME) { |
|
437 t -= tzt.getFrom()->getDSTSavings(); |
|
438 } |
|
439 if (t > start) { |
|
440 break; |
|
441 } |
|
442 } |
|
443 int32_t asize = startTimes - idx; |
|
444 if (asize > 0) { |
|
445 newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize); |
|
446 if (newTimes == NULL) { |
|
447 status = U_MEMORY_ALLOCATION_ERROR; |
|
448 goto error; |
|
449 } |
|
450 for (int32_t newidx = 0; newidx < asize; newidx++) { |
|
451 tar->getStartTimeAt(idx + newidx, newTimes[newidx]); |
|
452 if (U_FAILURE(status)) { |
|
453 uprv_free(newTimes); |
|
454 newTimes = NULL; |
|
455 goto error; |
|
456 } |
|
457 } |
|
458 tar->getName(name); |
|
459 TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name, |
|
460 tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType); |
|
461 uprv_free(newTimes); |
|
462 filteredRules->addElement(newTar, status); |
|
463 if (U_FAILURE(status)) { |
|
464 goto error; |
|
465 } |
|
466 } |
|
467 } |
|
468 } |
|
469 } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) { |
|
470 ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); |
|
471 if (firstStart == tzt.getTime()) { |
|
472 // Just add the rule as is |
|
473 filteredRules->addElement(ar->clone(), status); |
|
474 if (U_FAILURE(status)) { |
|
475 goto error; |
|
476 } |
|
477 } else { |
|
478 // Calculate the transition year |
|
479 int32_t year, month, dom, dow, doy, mid; |
|
480 Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid); |
|
481 // Re-create the rule |
|
482 ar->getName(name); |
|
483 AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(), |
|
484 *(ar->getRule()), year, ar->getEndYear()); |
|
485 filteredRules->addElement(newAr, status); |
|
486 if (U_FAILURE(status)) { |
|
487 goto error; |
|
488 } |
|
489 } |
|
490 // check if this is a final rule |
|
491 if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { |
|
492 // After bot final standard and dst rules are processed, |
|
493 // exit this while loop. |
|
494 if (ar->getDSTSavings() == 0) { |
|
495 bFinalStd = TRUE; |
|
496 } else { |
|
497 bFinalDst = TRUE; |
|
498 } |
|
499 } |
|
500 } |
|
501 done[i] = TRUE; |
|
502 } |
|
503 |
|
504 // Set the results |
|
505 if (orgRules != NULL) { |
|
506 while (!orgRules->isEmpty()) { |
|
507 r = (TimeZoneRule*)orgRules->orphanElementAt(0); |
|
508 delete r; |
|
509 } |
|
510 delete orgRules; |
|
511 } |
|
512 if (done != NULL) { |
|
513 uprv_free(done); |
|
514 } |
|
515 |
|
516 initial = res_initial; |
|
517 transitionRules = filteredRules; |
|
518 return; |
|
519 |
|
520 error: |
|
521 if (orgtrs != NULL) { |
|
522 uprv_free(orgtrs); |
|
523 } |
|
524 if (orgRules != NULL) { |
|
525 while (!orgRules->isEmpty()) { |
|
526 r = (TimeZoneRule*)orgRules->orphanElementAt(0); |
|
527 delete r; |
|
528 } |
|
529 delete orgRules; |
|
530 } |
|
531 if (done != NULL) { |
|
532 if (filteredRules != NULL) { |
|
533 while (!filteredRules->isEmpty()) { |
|
534 r = (TimeZoneRule*)filteredRules->orphanElementAt(0); |
|
535 delete r; |
|
536 } |
|
537 delete filteredRules; |
|
538 } |
|
539 delete res_initial; |
|
540 uprv_free(done); |
|
541 } |
|
542 |
|
543 initial = NULL; |
|
544 transitionRules = NULL; |
|
545 } |
|
546 |
|
547 void |
|
548 BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/, |
|
549 int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const { |
|
550 if (U_FAILURE(status)) { |
|
551 return; |
|
552 } |
|
553 status = U_UNSUPPORTED_ERROR; |
|
554 } |
|
555 |
|
556 U_NAMESPACE_END |
|
557 |
|
558 #endif /* #if !UCONFIG_NO_FORMATTING */ |
|
559 |
|
560 //eof |