Coverage Report

Created: 2025-06-13 06:34

/src/icu/icu4c/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() const {
78
0
    return fRawOffset;
79
0
}
80
81
int32_t
82
0
TimeZoneRule::getDSTSavings() 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() 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
    UErrorCode status = U_ZERO_ERROR;
359
0
    int32_t year = Grego::timeToYear(base, status);
360
0
    U_ASSERT(U_SUCCESS(status));
361
0
    if (year < fStartYear) {
362
0
        return getFirstStart(prevRawOffset, prevDSTSavings, result);
363
0
    }
364
0
    UDate tmp;
365
0
    if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
366
0
        if (tmp < base || (!inclusive && (tmp == base))) {
367
            // Return the next one
368
0
            return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
369
0
        } else {
370
0
            result = tmp;
371
0
            return true;
372
0
        }
373
0
    }
374
0
    return false;
375
0
}
376
377
UBool
378
AnnualTimeZoneRule::getPreviousStart(UDate base,
379
                                     int32_t prevRawOffset,
380
                                     int32_t prevDSTSavings,
381
                                     UBool inclusive,
382
0
                                     UDate& result) const {
383
0
    UErrorCode status = U_ZERO_ERROR;
384
0
    int32_t year = Grego::timeToYear(base, status);
385
0
    U_ASSERT(U_SUCCESS(status));
386
0
    if (year > fEndYear) {
387
0
        return getFinalStart(prevRawOffset, prevDSTSavings, result);
388
0
    }
389
0
    UDate tmp;
390
0
    if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
391
0
        if (tmp > base || (!inclusive && (tmp == base))) {
392
            // Return the previous one
393
0
            return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
394
0
        } else {
395
0
            result = tmp;
396
0
            return true;
397
0
        }
398
0
    }
399
0
    return false;
400
0
}
401
402
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
403
404
TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
405
                                             int32_t rawOffset,
406
                                             int32_t dstSavings,
407
                                             const UDate* startTimes,
408
                                             int32_t numStartTimes,
409
                                             DateTimeRule::TimeRuleType timeRuleType)
410
0
: TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
411
0
  fStartTimes(nullptr) {
412
0
    UErrorCode status = U_ZERO_ERROR;
413
0
    initStartTimes(startTimes, numStartTimes, status);
414
    //TODO - status?
415
0
}
416
417
418
TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
419
0
: TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(nullptr) {
420
0
    UErrorCode status = U_ZERO_ERROR;
421
0
    initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
422
    //TODO - status?
423
0
}
424
425
426
0
TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
427
0
    if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
428
0
        uprv_free(fStartTimes);
429
0
    }
430
0
}
431
432
TimeArrayTimeZoneRule*
433
0
TimeArrayTimeZoneRule::clone() const {
434
0
    return new TimeArrayTimeZoneRule(*this);
435
0
}
436
437
438
TimeArrayTimeZoneRule&
439
0
TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
440
0
    if (this != &right) {
441
0
        TimeZoneRule::operator=(right);
442
0
        UErrorCode status = U_ZERO_ERROR;
443
0
        initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
444
        //TODO - status?
445
0
        fTimeRuleType = right.fTimeRuleType;        
446
0
    }
447
0
    return *this;
448
0
}
449
450
bool
451
0
TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
452
0
    if (this == &that) {
453
0
        return true;
454
0
    }
455
0
    if (typeid(*this) != typeid(that) || !TimeZoneRule::operator==(that)) {
456
0
        return false;
457
0
    }
458
0
    TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
459
0
    if (fTimeRuleType != tatzr->fTimeRuleType ||
460
0
        fNumStartTimes != tatzr->fNumStartTimes) {
461
0
        return false;
462
0
    }
463
    // Compare start times
464
0
    bool res = true;
465
0
    for (int32_t i = 0; i < fNumStartTimes; i++) {
466
0
        if (fStartTimes[i] != tatzr->fStartTimes[i]) {
467
0
            res = false;
468
0
            break;
469
0
        }
470
0
    }
471
0
    return res;
472
0
}
473
474
bool
475
0
TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
476
0
    return !operator==(that);
477
0
}
478
479
DateTimeRule::TimeRuleType
480
0
TimeArrayTimeZoneRule::getTimeType() const {
481
0
    return fTimeRuleType;
482
0
}
483
484
UBool
485
0
TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
486
0
    if (index >= fNumStartTimes || index < 0) {
487
0
        return false;
488
0
    }
489
0
    result = fStartTimes[index];
490
0
    return true;
491
0
}
492
493
int32_t
494
0
TimeArrayTimeZoneRule::countStartTimes() const {
495
0
    return fNumStartTimes;
496
0
}
497
498
UBool
499
0
TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
500
0
    if (this == &other) {
501
0
        return true;
502
0
    }
503
0
    if (typeid(*this) != typeid(other) || TimeZoneRule::isEquivalentTo(other) == false) {
504
0
        return false;
505
0
    }
506
0
    TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
507
0
    if (fTimeRuleType != that->fTimeRuleType ||
508
0
        fNumStartTimes != that->fNumStartTimes) {
509
0
        return false;
510
0
    }
511
    // Compare start times
512
0
    UBool res = true;
513
0
    for (int32_t i = 0; i < fNumStartTimes; i++) {
514
0
        if (fStartTimes[i] != that->fStartTimes[i]) {
515
0
            res = false;
516
0
            break;
517
0
        }
518
0
    }
519
0
    return res;
520
0
}
521
522
UBool
523
TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
524
                                             int32_t prevDSTSavings,
525
0
                                             UDate& result) const {
526
0
    if (fNumStartTimes <= 0 || fStartTimes == nullptr) {
527
0
        return false;
528
0
    }
529
0
    result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
530
0
    return true;
531
0
}
532
533
UBool
534
TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
535
                                     int32_t prevDSTSavings,
536
0
                                     UDate& result) const {
537
0
    if (fNumStartTimes <= 0 || fStartTimes == nullptr) {
538
0
        return false;
539
0
    }
540
0
    result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
541
0
    return true;
542
0
}
543
544
UBool
545
TimeArrayTimeZoneRule::getNextStart(UDate base,
546
                                    int32_t prevRawOffset,
547
                                    int32_t prevDSTSavings,
548
                                    UBool inclusive,
549
0
                                    UDate& result) const {
550
0
    int32_t i = fNumStartTimes - 1;
551
0
    for (; i >= 0; i--) {
552
0
        UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
553
0
        if (time < base || (!inclusive && time == base)) {
554
0
            break;
555
0
        }
556
0
        result = time;
557
0
    }
558
0
    if (i == fNumStartTimes - 1) {
559
0
        return false;
560
0
    }
561
0
    return true;
562
0
}
563
564
UBool
565
TimeArrayTimeZoneRule::getPreviousStart(UDate base,
566
                                        int32_t prevRawOffset,
567
                                        int32_t prevDSTSavings,
568
                                        UBool inclusive,
569
0
                                        UDate& result) const {
570
0
    int32_t i = fNumStartTimes - 1;
571
0
    for (; i >= 0; i--) {
572
0
        UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
573
0
        if (time < base || (inclusive && time == base)) {
574
0
            result = time;
575
0
            return true;
576
0
        }
577
0
    }
578
0
    return false;
579
0
}
580
581
582
// ---- private methods ------
583
584
UBool
585
0
TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
586
    // Free old array
587
0
    if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
588
0
        uprv_free(fStartTimes);
589
0
    }
590
    // Allocate new one if needed
591
0
    if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
592
0
        fStartTimes = static_cast<UDate*>(uprv_malloc(sizeof(UDate) * size));
593
0
        if (fStartTimes == nullptr) {
594
0
            status = U_MEMORY_ALLOCATION_ERROR;
595
0
            fNumStartTimes = 0;
596
0
            return false;
597
0
        }
598
0
    } else {
599
0
        fStartTimes = (UDate*)fLocalStartTimes;
600
0
    }
601
0
    uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
602
0
    fNumStartTimes = size;
603
    // Sort dates
604
0
    uprv_sortArray(fStartTimes, fNumStartTimes, static_cast<int32_t>(sizeof(UDate)), compareDates, nullptr, true, &status);
605
0
    if (U_FAILURE(status)) {
606
0
        if (fStartTimes != nullptr && fStartTimes != fLocalStartTimes) {
607
0
            uprv_free(fStartTimes);
608
0
        }
609
0
        fNumStartTimes = 0;
610
0
        return false;
611
0
    }
612
0
    return true;
613
0
}
614
615
UDate
616
0
TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
617
0
    if (fTimeRuleType != DateTimeRule::UTC_TIME) {
618
0
        time -= raw;
619
0
    }
620
0
    if (fTimeRuleType == DateTimeRule::WALL_TIME) {
621
0
        time -= dst;
622
0
    }
623
0
    return time;
624
0
}
625
626
U_NAMESPACE_END
627
628
#endif /* #if !UCONFIG_NO_FORMATTING */
629
630
//eof
631