~ubuntu-branches/ubuntu/vivid/mozjs24/vivid

« back to all changes in this revision

Viewing changes to intl/icu/source/i18n/rbtz.cpp

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-02-11 21:55:34 UTC
  • Revision ID: package-import@ubuntu.com-20140211215534-m1zyq5aj59md3y07
Tags: upstream-24.2.0
ImportĀ upstreamĀ versionĀ 24.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
*******************************************************************************
 
3
* Copyright (C) 2007-2012, International Business Machines Corporation and
 
4
* others. All Rights Reserved.
 
5
*******************************************************************************
 
6
*/
 
7
 
 
8
#include "utypeinfo.h"  // for 'typeid' to work
 
9
 
 
10
#include "unicode/utypes.h"
 
11
 
 
12
#if !UCONFIG_NO_FORMATTING
 
13
 
 
14
#include "unicode/rbtz.h"
 
15
#include "unicode/gregocal.h"
 
16
#include "uvector.h"
 
17
#include "gregoimp.h"
 
18
#include "cmemory.h"
 
19
 
 
20
U_NAMESPACE_BEGIN
 
21
 
 
22
/**
 
23
 * A struct representing a time zone transition
 
24
 */
 
25
struct Transition {
 
26
    UDate time;
 
27
    TimeZoneRule* from;
 
28
    TimeZoneRule* to;
 
29
};
 
30
 
 
31
static UBool compareRules(UVector* rules1, UVector* rules2) {
 
32
    if (rules1 == NULL && rules2 == NULL) {
 
33
        return TRUE;
 
34
    } else if (rules1 == NULL || rules2 == NULL) {
 
35
        return FALSE;
 
36
    }
 
37
    int32_t size = rules1->size();
 
38
    if (size != rules2->size()) {
 
39
        return FALSE;
 
40
    }
 
41
    for (int32_t i = 0; i < size; i++) {
 
42
        TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i);
 
43
        TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i);
 
44
        if (*r1 != *r2) {
 
45
            return FALSE;
 
46
        }
 
47
    }
 
48
    return TRUE;
 
49
}
 
50
 
 
51
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone)
 
52
 
 
53
RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule)
 
54
: BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL),
 
55
  fHistoricTransitions(NULL), fUpToDate(FALSE) {
 
56
}
 
57
 
 
58
RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source)
 
59
: BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()),
 
60
  fHistoricTransitions(NULL), fUpToDate(FALSE) {
 
61
    fHistoricRules = copyRules(source.fHistoricRules);
 
62
    fFinalRules = copyRules(source.fFinalRules);
 
63
    if (source.fUpToDate) {
 
64
        UErrorCode status = U_ZERO_ERROR;
 
65
        complete(status);
 
66
    }
 
67
}
 
68
 
 
69
RuleBasedTimeZone::~RuleBasedTimeZone() {
 
70
    deleteTransitions();
 
71
    deleteRules();
 
72
}
 
73
 
 
74
RuleBasedTimeZone&
 
75
RuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) {
 
76
    if (*this != right) {
 
77
        BasicTimeZone::operator=(right);
 
78
        deleteRules();
 
79
        fInitialRule = right.fInitialRule->clone();
 
80
        fHistoricRules = copyRules(right.fHistoricRules);
 
81
        fFinalRules = copyRules(right.fFinalRules);
 
82
        deleteTransitions();
 
83
        fUpToDate = FALSE;
 
84
    }
 
85
    return *this;
 
86
}
 
87
 
 
88
UBool
 
89
RuleBasedTimeZone::operator==(const TimeZone& that) const {
 
90
    if (this == &that) {
 
91
        return TRUE;
 
92
    }
 
93
    if (typeid(*this) != typeid(that)
 
94
        || BasicTimeZone::operator==(that) == FALSE) {
 
95
        return FALSE;
 
96
    }
 
97
    RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that;
 
98
    if (*fInitialRule != *(rbtz->fInitialRule)) {
 
99
        return FALSE;
 
100
    }
 
101
    if (compareRules(fHistoricRules, rbtz->fHistoricRules)
 
102
        && compareRules(fFinalRules, rbtz->fFinalRules)) {
 
103
        return TRUE;
 
104
    }
 
105
    return FALSE;
 
106
}
 
107
 
 
108
UBool
 
109
RuleBasedTimeZone::operator!=(const TimeZone& that) const {
 
110
    return !operator==(that);
 
111
}
 
112
 
 
113
void
 
114
RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
 
115
    if (U_FAILURE(status)) {
 
116
        return;
 
117
    }
 
118
    AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule);
 
119
    if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
 
120
        // A final rule
 
121
        if (fFinalRules == NULL) {
 
122
            fFinalRules = new UVector(status);
 
123
            if (U_FAILURE(status)) {
 
124
                return;
 
125
            }
 
126
        } else if (fFinalRules->size() >= 2) {
 
127
            // Cannot handle more than two final rules
 
128
            status = U_INVALID_STATE_ERROR;
 
129
            return;
 
130
        }
 
131
        fFinalRules->addElement((void*)rule, status);
 
132
    } else {
 
133
        // Non-final rule
 
134
        if (fHistoricRules == NULL) {
 
135
            fHistoricRules = new UVector(status);
 
136
            if (U_FAILURE(status)) {
 
137
                return;
 
138
            }
 
139
        }
 
140
        fHistoricRules->addElement((void*)rule, status);
 
141
    }
 
142
    // Mark dirty, so transitions are recalculated at next complete() call
 
143
    fUpToDate = FALSE;
 
144
}
 
145
 
 
146
void
 
147
RuleBasedTimeZone::complete(UErrorCode& status) {
 
148
    if (U_FAILURE(status)) {
 
149
        return;
 
150
    }
 
151
    if (fUpToDate) {
 
152
        return;
 
153
    }
 
154
    // Make sure either no final rules or a pair of AnnualTimeZoneRules
 
155
    // are available.
 
156
    if (fFinalRules != NULL && fFinalRules->size() != 2) {
 
157
        status = U_INVALID_STATE_ERROR;
 
158
        return;
 
159
    }
 
160
 
 
161
    UBool *done = NULL;
 
162
    // Create a TimezoneTransition and add to the list
 
163
    if (fHistoricRules != NULL || fFinalRules != NULL) {
 
164
        TimeZoneRule *curRule = fInitialRule;
 
165
        UDate lastTransitionTime = MIN_MILLIS;
 
166
 
 
167
        // Build the transition array which represents historical time zone
 
168
        // transitions.
 
169
        if (fHistoricRules != NULL && fHistoricRules->size() > 0) {
 
170
            int32_t i;
 
171
            int32_t historicCount = fHistoricRules->size();
 
172
            done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount);
 
173
            if (done == NULL) {
 
174
                status = U_MEMORY_ALLOCATION_ERROR;
 
175
                goto cleanup;
 
176
            }
 
177
            for (i = 0; i < historicCount; i++) {
 
178
                done[i] = FALSE;
 
179
            }
 
180
            while (TRUE) {
 
181
                int32_t curStdOffset = curRule->getRawOffset();
 
182
                int32_t curDstSavings = curRule->getDSTSavings();
 
183
                UDate nextTransitionTime = MAX_MILLIS;
 
184
                TimeZoneRule *nextRule = NULL;
 
185
                TimeZoneRule *r = NULL;
 
186
                UBool avail;
 
187
                UDate tt;
 
188
                UnicodeString curName, name;
 
189
                curRule->getName(curName);
 
190
 
 
191
                for (i = 0; i < historicCount; i++) {
 
192
                    if (done[i]) {
 
193
                        continue;
 
194
                    }
 
195
                    r = (TimeZoneRule*)fHistoricRules->elementAt(i);
 
196
                    avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
 
197
                    if (!avail) {
 
198
                        // No more transitions from this rule - skip this rule next time
 
199
                        done[i] = TRUE;
 
200
                    } else {
 
201
                        r->getName(name);
 
202
                        if (*r == *curRule ||
 
203
                            (name == curName && r->getRawOffset() == curRule->getRawOffset()
 
204
                            && r->getDSTSavings() == curRule->getDSTSavings())) {
 
205
                            continue;
 
206
                        }
 
207
                        if (tt < nextTransitionTime) {
 
208
                            nextTransitionTime = tt;
 
209
                            nextRule = r;
 
210
                        }
 
211
                    }
 
212
                }
 
213
 
 
214
                if (nextRule ==  NULL) {
 
215
                    // Check if all historic rules are done
 
216
                    UBool bDoneAll = TRUE;
 
217
                    for (int32_t j = 0; j < historicCount; j++) {
 
218
                        if (!done[j]) {
 
219
                            bDoneAll = FALSE;
 
220
                            break;
 
221
                        }
 
222
                    }
 
223
                    if (bDoneAll) {
 
224
                        break;
 
225
                    }
 
226
                }
 
227
 
 
228
                if (fFinalRules != NULL) {
 
229
                    // Check if one of final rules has earlier transition date
 
230
                    for (i = 0; i < 2 /* fFinalRules->size() */; i++) {
 
231
                        TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i);
 
232
                        if (*fr == *curRule) {
 
233
                            continue;
 
234
                        }
 
235
                        r = (TimeZoneRule*)fFinalRules->elementAt(i);
 
236
                        avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
 
237
                        if (avail) {
 
238
                            if (tt < nextTransitionTime) {
 
239
                                nextTransitionTime = tt;
 
240
                                nextRule = r;
 
241
                            }
 
242
                        }
 
243
                    }
 
244
                }
 
245
 
 
246
                if (nextRule == NULL) {
 
247
                    // Nothing more
 
248
                    break;
 
249
                }
 
250
 
 
251
                if (fHistoricTransitions == NULL) {
 
252
                    fHistoricTransitions = new UVector(status);
 
253
                    if (U_FAILURE(status)) {
 
254
                        goto cleanup;
 
255
                    }
 
256
                }
 
257
                Transition *trst = (Transition*)uprv_malloc(sizeof(Transition));
 
258
                if (trst == NULL) {
 
259
                    status = U_MEMORY_ALLOCATION_ERROR;
 
260
                    goto cleanup;
 
261
                }
 
262
                trst->time = nextTransitionTime;
 
263
                trst->from = curRule;
 
264
                trst->to = nextRule;
 
265
                fHistoricTransitions->addElement(trst, status);
 
266
                if (U_FAILURE(status)) {
 
267
                    goto cleanup;
 
268
                }
 
269
                lastTransitionTime = nextTransitionTime;
 
270
                curRule = nextRule;
 
271
            }
 
272
        }
 
273
        if (fFinalRules != NULL) {
 
274
            if (fHistoricTransitions == NULL) {
 
275
                fHistoricTransitions = new UVector(status);
 
276
                if (U_FAILURE(status)) {
 
277
                    goto cleanup;
 
278
                }
 
279
            }
 
280
            // Append the first transition for each
 
281
            TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0);
 
282
            TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1);
 
283
            UDate tt0, tt1;
 
284
            UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0);
 
285
            UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1);
 
286
            if (!avail0 || !avail1) {
 
287
                // Should not happen, because both rules are permanent
 
288
                status = U_INVALID_STATE_ERROR;
 
289
                goto cleanup;
 
290
            }
 
291
            Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition));
 
292
            if (final0 == NULL) {
 
293
                status = U_MEMORY_ALLOCATION_ERROR;
 
294
                goto cleanup;
 
295
            }
 
296
            Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition));
 
297
            if (final1 == NULL) {
 
298
                uprv_free(final0);
 
299
                status = U_MEMORY_ALLOCATION_ERROR;
 
300
                goto cleanup;
 
301
            }
 
302
            if (tt0 < tt1) {
 
303
                final0->time = tt0;
 
304
                final0->from = curRule;
 
305
                final0->to = rule0;
 
306
                rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time);
 
307
                final1->from = rule0;
 
308
                final1->to = rule1;
 
309
            } else {
 
310
                final0->time = tt1;
 
311
                final0->from = curRule;
 
312
                final0->to = rule1;
 
313
                rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time);
 
314
                final1->from = rule1;
 
315
                final1->to = rule0;
 
316
            }
 
317
            fHistoricTransitions->addElement(final0, status);
 
318
            if (U_FAILURE(status)) {
 
319
                goto cleanup;
 
320
            }
 
321
            fHistoricTransitions->addElement(final1, status);
 
322
            if (U_FAILURE(status)) {
 
323
                goto cleanup;
 
324
            }
 
325
        }
 
326
    }
 
327
    fUpToDate = TRUE;
 
328
    if (done != NULL) {
 
329
        uprv_free(done);
 
330
    }
 
331
    return;
 
332
 
 
333
cleanup:
 
334
    deleteTransitions();
 
335
    if (done != NULL) {
 
336
        uprv_free(done);
 
337
    }
 
338
    fUpToDate = FALSE;
 
339
}
 
340
 
 
341
TimeZone*
 
342
RuleBasedTimeZone::clone(void) const {
 
343
    return new RuleBasedTimeZone(*this);
 
344
}
 
345
 
 
346
int32_t
 
347
RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
 
348
                             uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
 
349
    if (U_FAILURE(status)) {
 
350
        return 0;
 
351
    }
 
352
    if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
 
353
        status = U_ILLEGAL_ARGUMENT_ERROR;
 
354
        return 0;
 
355
    } else {
 
356
        return getOffset(era, year, month, day, dayOfWeek, millis,
 
357
                         Grego::monthLength(year, month), status);
 
358
    }
 
359
}
 
360
 
 
361
int32_t
 
362
RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
 
363
                             uint8_t /*dayOfWeek*/, int32_t millis,
 
364
                             int32_t /*monthLength*/, UErrorCode& status) const {
 
365
    // dayOfWeek and monthLength are unused
 
366
    if (U_FAILURE(status)) {
 
367
        return 0;
 
368
    }
 
369
    if (era == GregorianCalendar::BC) {
 
370
        // Convert to extended year
 
371
        year = 1 - year;
 
372
    }
 
373
    int32_t rawOffset, dstOffset;
 
374
    UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis;
 
375
    getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status);
 
376
    if (U_FAILURE(status)) {
 
377
        return 0;
 
378
    }
 
379
    return (rawOffset + dstOffset);
 
380
}
 
381
 
 
382
void
 
383
RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
 
384
                             int32_t& dstOffset, UErrorCode& status) const {
 
385
    getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status);
 
386
}
 
387
 
 
388
void
 
389
RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
 
390
                                      int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
 
391
    getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
 
392
}
 
393
 
 
394
 
 
395
/*
 
396
 * The internal getOffset implementation
 
397
 */
 
398
void
 
399
RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
 
400
                                     int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
 
401
                                     int32_t& rawOffset, int32_t& dstOffset,
 
402
                                     UErrorCode& status) const {
 
403
    rawOffset = 0;
 
404
    dstOffset = 0;
 
405
 
 
406
    if (U_FAILURE(status)) {
 
407
        return;
 
408
    }
 
409
    if (!fUpToDate) {
 
410
        // Transitions are not yet resolved.  We cannot do it here
 
411
        // because this method is const.  Thus, do nothing and return
 
412
        // error status.
 
413
        status = U_INVALID_STATE_ERROR;
 
414
        return;
 
415
    }
 
416
    const TimeZoneRule *rule = NULL;
 
417
    if (fHistoricTransitions == NULL) {
 
418
        rule = fInitialRule;
 
419
    } else {
 
420
        UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0),
 
421
            local, NonExistingTimeOpt, DuplicatedTimeOpt);
 
422
        if (date < tstart) {
 
423
            rule = fInitialRule;
 
424
        } else {
 
425
            int32_t idx = fHistoricTransitions->size() - 1;
 
426
            UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
 
427
                local, NonExistingTimeOpt, DuplicatedTimeOpt);
 
428
            if (date > tend) {
 
429
                if (fFinalRules != NULL) {
 
430
                    rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
 
431
                }
 
432
                if (rule == NULL) {
 
433
                    // no final rules or the given time is before the first transition
 
434
                    // specified by the final rules -> use the last rule 
 
435
                    rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
 
436
                }
 
437
            } else {
 
438
                // Find a historical transition
 
439
                while (idx >= 0) {
 
440
                    if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
 
441
                        local, NonExistingTimeOpt, DuplicatedTimeOpt)) {
 
442
                        break;
 
443
                    }
 
444
                    idx--;
 
445
                }
 
446
                rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
 
447
            }
 
448
        }
 
449
    }
 
450
    if (rule != NULL) {
 
451
        rawOffset = rule->getRawOffset();
 
452
        dstOffset = rule->getDSTSavings();
 
453
    }
 
454
}
 
455
 
 
456
void
 
457
RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
 
458
    // We don't support this operation at this moment.
 
459
    // Nothing to do!
 
460
}
 
461
 
 
462
int32_t
 
463
RuleBasedTimeZone::getRawOffset(void) const {
 
464
    // Note: This implementation returns standard GMT offset
 
465
    // as of current time.
 
466
    UErrorCode status = U_ZERO_ERROR;
 
467
    int32_t raw, dst;
 
468
    getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND,
 
469
        FALSE, raw, dst, status);
 
470
    return raw;
 
471
}
 
472
 
 
473
UBool
 
474
RuleBasedTimeZone::useDaylightTime(void) const {
 
475
    // Note: This implementation returns true when
 
476
    // daylight saving time is used as of now or
 
477
    // after the next transition.
 
478
    UErrorCode status = U_ZERO_ERROR;
 
479
    UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND;
 
480
    int32_t raw, dst;
 
481
    getOffset(now, FALSE, raw, dst, status);
 
482
    if (dst != 0) {
 
483
        return TRUE;
 
484
    }
 
485
    // If DST is not used now, check if DST is used after the next transition
 
486
    UDate time;
 
487
    TimeZoneRule *from, *to;
 
488
    UBool avail = findNext(now, FALSE, time, from, to);
 
489
    if (avail && to->getDSTSavings() != 0) {
 
490
        return TRUE;
 
491
    }
 
492
    return FALSE;
 
493
}
 
494
 
 
495
UBool
 
496
RuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
 
497
    if (U_FAILURE(status)) {
 
498
        return FALSE;
 
499
    }
 
500
    int32_t raw, dst;
 
501
    getOffset(date, FALSE, raw, dst, status);
 
502
    if (dst != 0) {
 
503
        return TRUE;
 
504
    }
 
505
    return FALSE;
 
506
}
 
507
 
 
508
UBool
 
509
RuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
 
510
    if (this == &other) {
 
511
        return TRUE;
 
512
    }
 
513
    if (typeid(*this) != typeid(other)) {
 
514
        return FALSE;
 
515
    }
 
516
    const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other;
 
517
    if (*fInitialRule != *(that.fInitialRule)) {
 
518
        return FALSE;
 
519
    }
 
520
    if (compareRules(fHistoricRules, that.fHistoricRules)
 
521
        && compareRules(fFinalRules, that.fFinalRules)) {
 
522
        return TRUE;
 
523
    }
 
524
    return FALSE;
 
525
}
 
526
 
 
527
UBool
 
528
RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
 
529
    UErrorCode status = U_ZERO_ERROR;
 
530
    complete(status);
 
531
    if (U_FAILURE(status)) {
 
532
        return FALSE;
 
533
    }
 
534
    UDate transitionTime;
 
535
    TimeZoneRule *fromRule, *toRule;
 
536
    UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule);
 
537
    if (found) {
 
538
        result.setTime(transitionTime);
 
539
        result.setFrom((const TimeZoneRule&)*fromRule);
 
540
        result.setTo((const TimeZoneRule&)*toRule);
 
541
        return TRUE;
 
542
    }
 
543
    return FALSE;
 
544
}
 
545
 
 
546
UBool
 
547
RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
 
548
    UErrorCode status = U_ZERO_ERROR;
 
549
    complete(status);
 
550
    if (U_FAILURE(status)) {
 
551
        return FALSE;
 
552
    }
 
553
    UDate transitionTime;
 
554
    TimeZoneRule *fromRule, *toRule;
 
555
    UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule);
 
556
    if (found) {
 
557
        result.setTime(transitionTime);
 
558
        result.setFrom((const TimeZoneRule&)*fromRule);
 
559
        result.setTo((const TimeZoneRule&)*toRule);
 
560
        return TRUE;
 
561
    }
 
562
    return FALSE;
 
563
}
 
564
 
 
565
int32_t
 
566
RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
 
567
    int32_t count = 0;
 
568
    if (fHistoricRules != NULL) {
 
569
        count += fHistoricRules->size();
 
570
    }
 
571
    if (fFinalRules != NULL) {
 
572
        count += fFinalRules->size();
 
573
    }
 
574
    return count;
 
575
}
 
576
 
 
577
void
 
578
RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
 
579
                                    const TimeZoneRule* trsrules[],
 
580
                                    int32_t& trscount,
 
581
                                    UErrorCode& status) /*const*/ {
 
582
    if (U_FAILURE(status)) {
 
583
        return;
 
584
    }
 
585
    // Initial rule
 
586
    initial = fInitialRule;
 
587
 
 
588
    // Transition rules
 
589
    int32_t cnt = 0;
 
590
    int32_t idx;
 
591
    if (fHistoricRules != NULL && cnt < trscount) {
 
592
        int32_t historicCount = fHistoricRules->size();
 
593
        idx = 0;
 
594
        while (cnt < trscount && idx < historicCount) {
 
595
            trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++);
 
596
        }
 
597
    }
 
598
    if (fFinalRules != NULL && cnt < trscount) {
 
599
        int32_t finalCount = fFinalRules->size();
 
600
        idx = 0;
 
601
        while (cnt < trscount && idx < finalCount) {
 
602
            trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++);
 
603
        }
 
604
    }
 
605
    // Set the result length
 
606
    trscount = cnt;
 
607
}
 
608
 
 
609
void
 
610
RuleBasedTimeZone::deleteRules(void) {
 
611
    delete fInitialRule;
 
612
    fInitialRule = NULL;
 
613
    if (fHistoricRules != NULL) {
 
614
        while (!fHistoricRules->isEmpty()) {
 
615
            delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0));
 
616
        }
 
617
        delete fHistoricRules;
 
618
        fHistoricRules = NULL;
 
619
    }
 
620
    if (fFinalRules != NULL) {
 
621
        while (!fFinalRules->isEmpty()) {
 
622
            delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0));
 
623
        }
 
624
        delete fFinalRules;
 
625
        fFinalRules = NULL;
 
626
    }
 
627
}
 
628
 
 
629
void
 
630
RuleBasedTimeZone::deleteTransitions(void) {
 
631
    if (fHistoricTransitions != NULL) {
 
632
        while (!fHistoricTransitions->isEmpty()) {
 
633
            Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0);
 
634
            uprv_free(trs);
 
635
        }
 
636
        delete fHistoricTransitions;
 
637
    }
 
638
    fHistoricTransitions = NULL;
 
639
}
 
640
 
 
641
UVector*
 
642
RuleBasedTimeZone::copyRules(UVector* source) {
 
643
    if (source == NULL) {
 
644
        return NULL;
 
645
    }
 
646
    UErrorCode ec = U_ZERO_ERROR;
 
647
    int32_t size = source->size();
 
648
    UVector *rules = new UVector(size, ec);
 
649
    if (U_FAILURE(ec)) {
 
650
        return NULL;
 
651
    }
 
652
    int32_t i;
 
653
    for (i = 0; i < size; i++) {
 
654
        rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec);
 
655
        if (U_FAILURE(ec)) {
 
656
            break;
 
657
        }
 
658
    }
 
659
    if (U_FAILURE(ec)) {
 
660
        // In case of error, clean up
 
661
        for (i = 0; i < rules->size(); i++) {
 
662
            TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i);
 
663
            delete rule;
 
664
        }
 
665
        delete rules;
 
666
        return NULL;
 
667
    }
 
668
    return rules;
 
669
}
 
670
 
 
671
TimeZoneRule*
 
672
RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
 
673
                                   int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
 
674
    if (fFinalRules == NULL) {
 
675
        return NULL;
 
676
    }
 
677
 
 
678
    AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0);
 
679
    AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1);
 
680
    if (fr0 == NULL || fr1 == NULL) {
 
681
        return NULL;
 
682
    }
 
683
 
 
684
    UDate start0, start1;
 
685
    UDate base;
 
686
    int32_t localDelta;
 
687
 
 
688
    base = date;
 
689
    if (local) {
 
690
        localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(),
 
691
                                   fr0->getRawOffset(), fr0->getDSTSavings(),
 
692
                                   NonExistingTimeOpt, DuplicatedTimeOpt);
 
693
        base -= localDelta;
 
694
    }
 
695
    UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0);
 
696
 
 
697
    base = date;
 
698
    if (local) {
 
699
        localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(),
 
700
                                   fr1->getRawOffset(), fr1->getDSTSavings(),
 
701
                                   NonExistingTimeOpt, DuplicatedTimeOpt);
 
702
        base -= localDelta;
 
703
    }
 
704
    UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
 
705
 
 
706
    if (!avail0 || !avail1) {
 
707
        if (avail0) {
 
708
            return fr0;
 
709
        } else if (avail1) {
 
710
            return fr1;
 
711
        }
 
712
        // Both rules take effect after the given time
 
713
        return NULL;
 
714
    }
 
715
 
 
716
    return (start0 > start1) ? fr0 : fr1;
 
717
}
 
718
 
 
719
UBool
 
720
RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
 
721
                            TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
 
722
    if (fHistoricTransitions == NULL) {
 
723
        return FALSE;
 
724
    }
 
725
    UBool isFinal = FALSE;
 
726
    UBool found = FALSE;
 
727
    Transition result;
 
728
    Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
 
729
    UDate tt = tzt->time;
 
730
    if (tt > base || (inclusive && tt == base)) {
 
731
        result = *tzt;
 
732
        found = TRUE;
 
733
    } else {
 
734
        int32_t idx = fHistoricTransitions->size() - 1;        
 
735
        tzt = (Transition*)fHistoricTransitions->elementAt(idx);
 
736
        tt = tzt->time;
 
737
        if (inclusive && tt == base) {
 
738
            result = *tzt;
 
739
            found = TRUE;
 
740
        } else if (tt <= base) {
 
741
            if (fFinalRules != NULL) {
 
742
                // Find a transion time with finalRules
 
743
                TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
 
744
                TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
 
745
                UDate start0, start1;
 
746
                UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
 
747
                UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
 
748
                //  avail0/avail1 should be always TRUE
 
749
                if (!avail0 && !avail1) {
 
750
                    return FALSE;
 
751
                }
 
752
                if (!avail1 || start0 < start1) {
 
753
                    result.time = start0;
 
754
                    result.from = r1;
 
755
                    result.to = r0;
 
756
                } else {
 
757
                    result.time = start1;
 
758
                    result.from = r0;
 
759
                    result.to = r1;
 
760
                }
 
761
                isFinal = TRUE;
 
762
                found = TRUE;
 
763
            }
 
764
        } else {
 
765
            // Find a transition within the historic transitions
 
766
            idx--;
 
767
            Transition *prev = tzt;
 
768
            while (idx > 0) {
 
769
                tzt = (Transition*)fHistoricTransitions->elementAt(idx);
 
770
                tt = tzt->time;
 
771
                if (tt < base || (!inclusive && tt == base)) {
 
772
                    break;
 
773
                }
 
774
                idx--;
 
775
                prev = tzt;
 
776
            }
 
777
            result.time = prev->time;
 
778
            result.from = prev->from;
 
779
            result.to = prev->to;
 
780
            found = TRUE;
 
781
        }
 
782
    }
 
783
    if (found) {
 
784
        // For now, this implementation ignore transitions with only zone name changes.
 
785
        if (result.from->getRawOffset() == result.to->getRawOffset()
 
786
            && result.from->getDSTSavings() == result.to->getDSTSavings()) {
 
787
            if (isFinal) {
 
788
                return FALSE;
 
789
            } else {
 
790
                // No offset changes.  Try next one if not final
 
791
                return findNext(result.time, FALSE /* always exclusive */,
 
792
                    transitionTime, fromRule, toRule);
 
793
            }
 
794
        }
 
795
        transitionTime = result.time;
 
796
        fromRule = result.from;
 
797
        toRule = result.to;
 
798
        return TRUE;
 
799
    }
 
800
    return FALSE;
 
801
}
 
802
 
 
803
UBool
 
804
RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
 
805
                            TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
 
806
    if (fHistoricTransitions == NULL) {
 
807
        return FALSE;
 
808
    }
 
809
    UBool found = FALSE;
 
810
    Transition result;
 
811
    Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
 
812
    UDate tt = tzt->time;
 
813
    if (inclusive && tt == base) {
 
814
        result = *tzt;
 
815
        found = TRUE;
 
816
    } else if (tt < base) {
 
817
        int32_t idx = fHistoricTransitions->size() - 1;        
 
818
        tzt = (Transition*)fHistoricTransitions->elementAt(idx);
 
819
        tt = tzt->time;
 
820
        if (inclusive && tt == base) {
 
821
            result = *tzt;
 
822
            found = TRUE;
 
823
        } else if (tt < base) {
 
824
            if (fFinalRules != NULL) {
 
825
                // Find a transion time with finalRules
 
826
                TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
 
827
                TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
 
828
                UDate start0, start1;
 
829
                UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
 
830
                UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
 
831
                //  avail0/avail1 should be always TRUE
 
832
                if (!avail0 && !avail1) {
 
833
                    return FALSE;
 
834
                }
 
835
                if (!avail1 || start0 > start1) {
 
836
                    result.time = start0;
 
837
                    result.from = r1;
 
838
                    result.to = r0;
 
839
                } else {
 
840
                    result.time = start1;
 
841
                    result.from = r0;
 
842
                    result.to = r1;
 
843
                }
 
844
            } else {
 
845
                result = *tzt;
 
846
            }
 
847
            found = TRUE;
 
848
        } else {
 
849
            // Find a transition within the historic transitions
 
850
            idx--;
 
851
            while (idx >= 0) {
 
852
                tzt = (Transition*)fHistoricTransitions->elementAt(idx);
 
853
                tt = tzt->time;
 
854
                if (tt < base || (inclusive && tt == base)) {
 
855
                    break;
 
856
                }
 
857
                idx--;
 
858
            }
 
859
            result = *tzt;
 
860
            found = TRUE;
 
861
        }
 
862
    }
 
863
    if (found) {
 
864
        // For now, this implementation ignore transitions with only zone name changes.
 
865
        if (result.from->getRawOffset() == result.to->getRawOffset()
 
866
            && result.from->getDSTSavings() == result.to->getDSTSavings()) {
 
867
            // No offset changes.  Try next one if not final
 
868
            return findPrev(result.time, FALSE /* always exclusive */,
 
869
                transitionTime, fromRule, toRule);
 
870
        }
 
871
        transitionTime = result.time;
 
872
        fromRule = result.from;
 
873
        toRule = result.to;
 
874
        return TRUE;
 
875
    }
 
876
    return FALSE;
 
877
}
 
878
 
 
879
UDate
 
880
RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local,
 
881
                                     int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
 
882
    UDate time = transition->time;
 
883
    if (local) {
 
884
        time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(),
 
885
                              transition->to->getRawOffset(), transition->to->getDSTSavings(),
 
886
                              NonExistingTimeOpt, DuplicatedTimeOpt);
 
887
    }
 
888
    return time;
 
889
}
 
890
 
 
891
int32_t
 
892
RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
 
893
                             int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
 
894
    int32_t delta = 0;
 
895
 
 
896
    int32_t offsetBefore = rawBefore + dstBefore;
 
897
    int32_t offsetAfter = rawAfter + dstAfter;
 
898
 
 
899
    UBool dstToStd = (dstBefore != 0) && (dstAfter == 0);
 
900
    UBool stdToDst = (dstBefore == 0) && (dstAfter != 0);
 
901
 
 
902
    if (offsetAfter - offsetBefore >= 0) {
 
903
        // Positive transition, which makes a non-existing local time range
 
904
        if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
 
905
                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
 
906
            delta = offsetBefore;
 
907
        } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
 
908
                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
 
909
            delta = offsetAfter;
 
910
        } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
 
911
            delta = offsetBefore;
 
912
        } else {
 
913
            // Interprets the time with rule before the transition,
 
914
            // default for non-existing time range
 
915
            delta = offsetAfter;
 
916
        }
 
917
    } else {
 
918
        // Negative transition, which makes a duplicated local time range
 
919
        if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
 
920
                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
 
921
            delta = offsetAfter;
 
922
        } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
 
923
                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
 
924
            delta = offsetBefore;
 
925
        } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
 
926
            delta = offsetBefore;
 
927
        } else {
 
928
            // Interprets the time with rule after the transition,
 
929
            // default for duplicated local time range
 
930
            delta = offsetAfter;
 
931
        }
 
932
    }
 
933
    return delta;
 
934
}
 
935
 
 
936
U_NAMESPACE_END
 
937
 
 
938
#endif /* #if !UCONFIG_NO_FORMATTING */
 
939
 
 
940
//eof
 
941