Coverage Report

Created: 2025-06-24 06:43

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