1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2007-2012, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9 
10 #include "utypeinfo.h"  // for 'typeid' to work
11 
12 #include "unicode/utypes.h"
13 
14 #if !UCONFIG_NO_FORMATTING
15 
16 #include "unicode/tzrule.h"
17 #include "unicode/ucal.h"
18 #include "gregoimp.h"
19 #include "cmemory.h"
20 #include "uarrsort.h"
21 
22 U_CDECL_BEGIN
23 // UComparator function for sorting start times
24 static int32_t U_CALLCONV
compareDates(const void *,const void * left,const void * right)25 compareDates(const void * /*context*/, const void *left, const void *right) {
26     UDate l = *((UDate*)left);
27     UDate r = *((UDate*)right);
28     int32_t res = l < r ? -1 : (l == r ? 0 : 1);
29     return res;
30 }
31 U_CDECL_END
32 
33 U_NAMESPACE_BEGIN
34 
TimeZoneRule(const UnicodeString & name,int32_t rawOffset,int32_t dstSavings)35 TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
36 : UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
37 }
38 
TimeZoneRule(const TimeZoneRule & source)39 TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
40 : UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
41 }
42 
~TimeZoneRule()43 TimeZoneRule::~TimeZoneRule() {
44 }
45 
46 TimeZoneRule&
operator =(const TimeZoneRule & right)47 TimeZoneRule::operator=(const TimeZoneRule& right) {
48     if (this != &right) {
49         fName = right.fName;
50         fRawOffset = right.fRawOffset;
51         fDSTSavings = right.fDSTSavings;
52     }
53     return *this;
54 }
55 
56 UBool
operator ==(const TimeZoneRule & that) const57 TimeZoneRule::operator==(const TimeZoneRule& that) const {
58     return ((this == &that) ||
59             (typeid(*this) == typeid(that) &&
60             fName == that.fName &&
61             fRawOffset == that.fRawOffset &&
62             fDSTSavings == that.fDSTSavings));
63 }
64 
65 UBool
operator !=(const TimeZoneRule & that) const66 TimeZoneRule::operator!=(const TimeZoneRule& that) const {
67     return !operator==(that);
68 }
69 
70 UnicodeString&
getName(UnicodeString & name) const71 TimeZoneRule::getName(UnicodeString& name) const {
72     name = fName;
73     return name;
74 }
75 
76 int32_t
getRawOffset(void) const77 TimeZoneRule::getRawOffset(void) const {
78     return fRawOffset;
79 }
80 
81 int32_t
getDSTSavings(void) const82 TimeZoneRule::getDSTSavings(void) const {
83     return fDSTSavings;
84 }
85 
86 UBool
isEquivalentTo(const TimeZoneRule & other) const87 TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
88     return ((this == &other) ||
89             (typeid(*this) == typeid(other) &&
90             fRawOffset == other.fRawOffset &&
91             fDSTSavings == other.fDSTSavings));
92 }
93 
94 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)95 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
96 
97 InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
98                                          int32_t rawOffset,
99                                          int32_t dstSavings)
100 : TimeZoneRule(name, rawOffset, dstSavings) {
101 }
102 
InitialTimeZoneRule(const InitialTimeZoneRule & source)103 InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
104 : TimeZoneRule(source) {
105 }
106 
~InitialTimeZoneRule()107 InitialTimeZoneRule::~InitialTimeZoneRule() {
108 }
109 
110 InitialTimeZoneRule*
clone() const111 InitialTimeZoneRule::clone() const {
112     return new InitialTimeZoneRule(*this);
113 }
114 
115 InitialTimeZoneRule&
operator =(const InitialTimeZoneRule & right)116 InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
117     if (this != &right) {
118         TimeZoneRule::operator=(right);
119     }
120     return *this;
121 }
122 
123 UBool
operator ==(const TimeZoneRule & that) const124 InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
125     return ((this == &that) ||
126             (typeid(*this) == typeid(that) &&
127             TimeZoneRule::operator==(that)));
128 }
129 
130 UBool
operator !=(const TimeZoneRule & that) const131 InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
132     return !operator==(that);
133 }
134 
135 UBool
isEquivalentTo(const TimeZoneRule & other) const136 InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
137     if (this == &other) {
138         return TRUE;
139     }
140     if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
141         return FALSE;
142     }
143     return TRUE;
144 }
145 
146 UBool
getFirstStart(int32_t,int32_t,UDate &) const147 InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
148                                   int32_t /*prevDSTSavings*/,
149                                   UDate& /*result*/) const {
150     return FALSE;
151 }
152 
153 UBool
getFinalStart(int32_t,int32_t,UDate &) const154 InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
155                                   int32_t /*prevDSTSavings*/,
156                                   UDate& /*result*/) const {
157     return FALSE;
158 }
159 
160 UBool
getNextStart(UDate,int32_t,int32_t,UBool,UDate &) const161 InitialTimeZoneRule::getNextStart(UDate /*base*/,
162                                  int32_t /*prevRawOffset*/,
163                                  int32_t /*prevDSTSavings*/,
164                                  UBool /*inclusive*/,
165                                  UDate& /*result*/) const {
166     return FALSE;
167 }
168 
169 UBool
getPreviousStart(UDate,int32_t,int32_t,UBool,UDate &) const170 InitialTimeZoneRule::getPreviousStart(UDate /*base*/,
171                                      int32_t /*prevRawOffset*/,
172                                      int32_t /*prevDSTSavings*/,
173                                      UBool /*inclusive*/,
174                                      UDate& /*result*/) const {
175     return FALSE;
176 }
177 
178 
179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
180 
181 const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
182 
AnnualTimeZoneRule(const UnicodeString & name,int32_t rawOffset,int32_t dstSavings,const DateTimeRule & dateTimeRule,int32_t startYear,int32_t endYear)183 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
184                                        int32_t rawOffset,
185                                        int32_t dstSavings,
186                                        const DateTimeRule& dateTimeRule,
187                                        int32_t startYear,
188                                        int32_t endYear)
189 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
190   fStartYear(startYear), fEndYear(endYear) {
191 }
192 
AnnualTimeZoneRule(const UnicodeString & name,int32_t rawOffset,int32_t dstSavings,DateTimeRule * dateTimeRule,int32_t startYear,int32_t endYear)193 AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
194                                        int32_t rawOffset,
195                                        int32_t dstSavings,
196                                        DateTimeRule* dateTimeRule,
197                                        int32_t startYear,
198                                        int32_t endYear)
199 : TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
200   fStartYear(startYear), fEndYear(endYear) {
201 }
202 
AnnualTimeZoneRule(const AnnualTimeZoneRule & source)203 AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
204 : TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
205   fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
206 }
207 
~AnnualTimeZoneRule()208 AnnualTimeZoneRule::~AnnualTimeZoneRule() {
209     delete fDateTimeRule;
210 }
211 
212 AnnualTimeZoneRule*
clone(void) const213 AnnualTimeZoneRule::clone(void) const {
214     return new AnnualTimeZoneRule(*this);
215 }
216 
217 AnnualTimeZoneRule&
operator =(const AnnualTimeZoneRule & right)218 AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
219     if (this != &right) {
220         TimeZoneRule::operator=(right);
221         delete fDateTimeRule;
222         fDateTimeRule = right.fDateTimeRule->clone();
223         fStartYear = right.fStartYear;
224         fEndYear = right.fEndYear;
225     }
226     return *this;
227 }
228 
229 UBool
operator ==(const TimeZoneRule & that) const230 AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
231     if (this == &that) {
232         return TRUE;
233     }
234     if (typeid(*this) != typeid(that)) {
235         return FALSE;
236     }
237     AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
238     return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
239             fStartYear == atzr->fStartYear &&
240             fEndYear == atzr->fEndYear);
241 }
242 
243 UBool
operator !=(const TimeZoneRule & that) const244 AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
245     return !operator==(that);
246 }
247 
248 const DateTimeRule*
getRule() const249 AnnualTimeZoneRule::getRule() const {
250     return fDateTimeRule;
251 }
252 
253 int32_t
getStartYear() const254 AnnualTimeZoneRule::getStartYear() const {
255     return fStartYear;
256 }
257 
258 int32_t
getEndYear() const259 AnnualTimeZoneRule::getEndYear() const {
260     return fEndYear;
261 }
262 
263 UBool
getStartInYear(int32_t year,int32_t prevRawOffset,int32_t prevDSTSavings,UDate & result) const264 AnnualTimeZoneRule::getStartInYear(int32_t year,
265                                    int32_t prevRawOffset,
266                                    int32_t prevDSTSavings,
267                                    UDate &result) const {
268     if (year < fStartYear || year > fEndYear) {
269         return FALSE;
270     }
271     double ruleDay;
272     DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
273     if (type == DateTimeRule::DOM) {
274         ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
275     } else {
276         UBool after = TRUE;
277         if (type == DateTimeRule::DOW) {
278             // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
279             int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
280             if (weeks > 0) {
281                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
282                 ruleDay += 7 * (weeks - 1);
283             } else {
284                 after = FALSE;
285                 ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
286                     Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
287                 ruleDay += 7 * (weeks + 1);
288            }
289         } else {
290             int32_t month = fDateTimeRule->getRuleMonth();
291             int32_t dom = fDateTimeRule->getRuleDayOfMonth();
292             if (type == DateTimeRule::DOW_LEQ_DOM) {
293                 after = FALSE;
294                 // Handle Feb <=29
295                 if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
296                     dom--;
297                 }
298             }
299             ruleDay = Grego::fieldsToDay(year, month, dom);
300         }
301         int32_t dow = Grego::dayOfWeek(ruleDay);
302         int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
303         if (after) {
304             delta = delta < 0 ? delta + 7 : delta;
305         } else {
306             delta = delta > 0 ? delta - 7 : delta;
307         }
308         ruleDay += delta;
309     }
310 
311     result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
312     if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
313         result -= prevRawOffset;
314     }
315     if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
316         result -= prevDSTSavings;
317     }
318     return TRUE;
319 }
320 
321 UBool
isEquivalentTo(const TimeZoneRule & other) const322 AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
323     if (this == &other) {
324         return TRUE;
325     }
326     if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
327         return FALSE;
328     }
329     AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
330     return (*fDateTimeRule == *(that->fDateTimeRule) &&
331             fStartYear == that->fStartYear &&
332             fEndYear == that->fEndYear);
333 }
334 
335 UBool
getFirstStart(int32_t prevRawOffset,int32_t prevDSTSavings,UDate & result) const336 AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
337                                   int32_t prevDSTSavings,
338                                   UDate& result) const {
339     return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
340 }
341 
342 UBool
getFinalStart(int32_t prevRawOffset,int32_t prevDSTSavings,UDate & result) const343 AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset,
344                                   int32_t prevDSTSavings,
345                                   UDate& result) const {
346     if (fEndYear == MAX_YEAR) {
347         return FALSE;
348     }
349     return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result);
350 }
351 
352 UBool
getNextStart(UDate base,int32_t prevRawOffset,int32_t prevDSTSavings,UBool inclusive,UDate & result) const353 AnnualTimeZoneRule::getNextStart(UDate base,
354                                  int32_t prevRawOffset,
355                                  int32_t prevDSTSavings,
356                                  UBool inclusive,
357                                  UDate& result) const {
358     int32_t year, month, dom, dow, doy, mid;
359     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
360     if (year < fStartYear) {
361         return getFirstStart(prevRawOffset, prevDSTSavings, result);
362     }
363     UDate tmp;
364     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
365         if (tmp < base || (!inclusive && (tmp == base))) {
366             // Return the next one
367             return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
368         } else {
369             result = tmp;
370             return TRUE;
371         }
372     }
373     return FALSE;
374 }
375 
376 UBool
getPreviousStart(UDate base,int32_t prevRawOffset,int32_t prevDSTSavings,UBool inclusive,UDate & result) const377 AnnualTimeZoneRule::getPreviousStart(UDate base,
378                                      int32_t prevRawOffset,
379                                      int32_t prevDSTSavings,
380                                      UBool inclusive,
381                                      UDate& result) const {
382     int32_t year, month, dom, dow, doy, mid;
383     Grego::timeToFields(base, year, month, dom, dow, doy, mid);
384     if (year > fEndYear) {
385         return getFinalStart(prevRawOffset, prevDSTSavings, result);
386     }
387     UDate tmp;
388     if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
389         if (tmp > base || (!inclusive && (tmp == base))) {
390             // Return the previous one
391             return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
392         } else {
393             result = tmp;
394             return TRUE;
395         }
396     }
397     return FALSE;
398 }
399 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)400 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
401 
402 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
403                                              int32_t rawOffset,
404                                              int32_t dstSavings,
405                                              const UDate* startTimes,
406                                              int32_t numStartTimes,
407                                              DateTimeRule::TimeRuleType timeRuleType)
408 : TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
409   fStartTimes(NULL) {
410     UErrorCode status = U_ZERO_ERROR;
411     initStartTimes(startTimes, numStartTimes, status);
412     //TODO - status?
413 }
414 
415 
TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule & source)416 TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
417 : TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) {
418     UErrorCode status = U_ZERO_ERROR;
419     initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
420     //TODO - status?
421 }
422 
423 
~TimeArrayTimeZoneRule()424 TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
425     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
426         uprv_free(fStartTimes);
427     }
428 }
429 
430 TimeArrayTimeZoneRule*
clone(void) const431 TimeArrayTimeZoneRule::clone(void) const {
432     return new TimeArrayTimeZoneRule(*this);
433 }
434 
435 
436 TimeArrayTimeZoneRule&
operator =(const TimeArrayTimeZoneRule & right)437 TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
438     if (this != &right) {
439         TimeZoneRule::operator=(right);
440         UErrorCode status = U_ZERO_ERROR;
441         initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
442         //TODO - status?
443         fTimeRuleType = right.fTimeRuleType;
444     }
445     return *this;
446 }
447 
448 UBool
operator ==(const TimeZoneRule & that) const449 TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
450     if (this == &that) {
451         return TRUE;
452     }
453     if (typeid(*this) != typeid(that) || TimeZoneRule::operator==(that) == FALSE) {
454         return FALSE;
455     }
456     TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
457     if (fTimeRuleType != tatzr->fTimeRuleType ||
458         fNumStartTimes != tatzr->fNumStartTimes) {
459         return FALSE;
460     }
461     // Compare start times
462     UBool res = TRUE;
463     for (int32_t i = 0; i < fNumStartTimes; i++) {
464         if (fStartTimes[i] != tatzr->fStartTimes[i]) {
465             res = FALSE;
466             break;
467         }
468     }
469     return res;
470 }
471 
472 UBool
operator !=(const TimeZoneRule & that) const473 TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
474     return !operator==(that);
475 }
476 
477 DateTimeRule::TimeRuleType
getTimeType(void) const478 TimeArrayTimeZoneRule::getTimeType(void) const {
479     return fTimeRuleType;
480 }
481 
482 UBool
getStartTimeAt(int32_t index,UDate & result) const483 TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
484     if (index >= fNumStartTimes || index < 0) {
485         return FALSE;
486     }
487     result = fStartTimes[index];
488     return TRUE;
489 }
490 
491 int32_t
countStartTimes(void) const492 TimeArrayTimeZoneRule::countStartTimes(void) const {
493     return fNumStartTimes;
494 }
495 
496 UBool
isEquivalentTo(const TimeZoneRule & other) const497 TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
498     if (this == &other) {
499         return TRUE;
500     }
501     if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == FALSE) {
502         return FALSE;
503     }
504     TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
505     if (fTimeRuleType != that->fTimeRuleType ||
506         fNumStartTimes != that->fNumStartTimes) {
507         return FALSE;
508     }
509     // Compare start times
510     UBool res = TRUE;
511     for (int32_t i = 0; i < fNumStartTimes; i++) {
512         if (fStartTimes[i] != that->fStartTimes[i]) {
513             res = FALSE;
514             break;
515         }
516     }
517     return res;
518 }
519 
520 UBool
getFirstStart(int32_t prevRawOffset,int32_t prevDSTSavings,UDate & result) const521 TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
522                                              int32_t prevDSTSavings,
523                                              UDate& result) const {
524     if (fNumStartTimes <= 0 || fStartTimes == NULL) {
525         return FALSE;
526     }
527     result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
528     return TRUE;
529 }
530 
531 UBool
getFinalStart(int32_t prevRawOffset,int32_t prevDSTSavings,UDate & result) const532 TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
533                                      int32_t prevDSTSavings,
534                                      UDate& result) const {
535     if (fNumStartTimes <= 0 || fStartTimes == NULL) {
536         return FALSE;
537     }
538     result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
539     return TRUE;
540 }
541 
542 UBool
getNextStart(UDate base,int32_t prevRawOffset,int32_t prevDSTSavings,UBool inclusive,UDate & result) const543 TimeArrayTimeZoneRule::getNextStart(UDate base,
544                                     int32_t prevRawOffset,
545                                     int32_t prevDSTSavings,
546                                     UBool inclusive,
547                                     UDate& result) const {
548     int32_t i = fNumStartTimes - 1;
549     for (; i >= 0; i--) {
550         UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
551         if (time < base || (!inclusive && time == base)) {
552             break;
553         }
554         result = time;
555     }
556     if (i == fNumStartTimes - 1) {
557         return FALSE;
558     }
559     return TRUE;
560 }
561 
562 UBool
getPreviousStart(UDate base,int32_t prevRawOffset,int32_t prevDSTSavings,UBool inclusive,UDate & result) const563 TimeArrayTimeZoneRule::getPreviousStart(UDate base,
564                                         int32_t prevRawOffset,
565                                         int32_t prevDSTSavings,
566                                         UBool inclusive,
567                                         UDate& result) const {
568     int32_t i = fNumStartTimes - 1;
569     for (; i >= 0; i--) {
570         UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
571         if (time < base || (inclusive && time == base)) {
572             result = time;
573             return TRUE;
574         }
575     }
576     return FALSE;
577 }
578 
579 
580 // ---- private methods ------
581 
582 UBool
initStartTimes(const UDate source[],int32_t size,UErrorCode & status)583 TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
584     // Free old array
585     if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
586         uprv_free(fStartTimes);
587     }
588     // Allocate new one if needed
589     if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
590         fStartTimes = (UDate*)uprv_malloc(sizeof(UDate)*size);
591         if (fStartTimes == NULL) {
592             status = U_MEMORY_ALLOCATION_ERROR;
593             fNumStartTimes = 0;
594             return FALSE;
595         }
596     } else {
597         fStartTimes = (UDate*)fLocalStartTimes;
598     }
599     uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
600     fNumStartTimes = size;
601     // Sort dates
602     uprv_sortArray(fStartTimes, fNumStartTimes, (int32_t)sizeof(UDate), compareDates, NULL, TRUE, &status);
603     if (U_FAILURE(status)) {
604         if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
605             uprv_free(fStartTimes);
606         }
607         fNumStartTimes = 0;
608         return FALSE;
609     }
610     return TRUE;
611 }
612 
613 UDate
getUTC(UDate time,int32_t raw,int32_t dst) const614 TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
615     if (fTimeRuleType != DateTimeRule::UTC_TIME) {
616         time -= raw;
617     }
618     if (fTimeRuleType == DateTimeRule::WALL_TIME) {
619         time -= dst;
620     }
621     return time;
622 }
623 
624 U_NAMESPACE_END
625 
626 #endif /* #if !UCONFIG_NO_FORMATTING */
627 
628 //eof
629 
630