11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
31cb0ef41Sopenharmony_ci/*
41cb0ef41Sopenharmony_ci *******************************************************************************
51cb0ef41Sopenharmony_ci * Copyright (C) 1997-2013, International Business Machines Corporation and
61cb0ef41Sopenharmony_ci * others. All Rights Reserved.
71cb0ef41Sopenharmony_ci *******************************************************************************
81cb0ef41Sopenharmony_ci *
91cb0ef41Sopenharmony_ci * File SIMPLETZ.H
101cb0ef41Sopenharmony_ci *
111cb0ef41Sopenharmony_ci * Modification History:
121cb0ef41Sopenharmony_ci *
131cb0ef41Sopenharmony_ci *   Date        Name        Description
141cb0ef41Sopenharmony_ci *   12/05/96    clhuang     Creation.
151cb0ef41Sopenharmony_ci *   04/21/97    aliu        Fixed miscellaneous bugs found by inspection and
161cb0ef41Sopenharmony_ci *                           testing.
171cb0ef41Sopenharmony_ci *   07/29/97    aliu        Ported source bodies back from Java version with
181cb0ef41Sopenharmony_ci *                           numerous feature enhancements and bug fixes.
191cb0ef41Sopenharmony_ci *   08/10/98    stephen     JDK 1.2 sync.
201cb0ef41Sopenharmony_ci *   09/17/98    stephen     Fixed getOffset() for last hour of year and DST
211cb0ef41Sopenharmony_ci *   12/02/99    aliu        Added TimeMode and constructor and setStart/EndRule
221cb0ef41Sopenharmony_ci *                           methods that take TimeMode. Whitespace cleanup.
231cb0ef41Sopenharmony_ci ********************************************************************************
241cb0ef41Sopenharmony_ci */
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci#include "utypeinfo.h"  // for 'typeid' to work
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci#include "unicode/utypes.h"
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci#include "unicode/simpletz.h"
331cb0ef41Sopenharmony_ci#include "unicode/gregocal.h"
341cb0ef41Sopenharmony_ci#include "unicode/smpdtfmt.h"
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci#include "cmemory.h"
371cb0ef41Sopenharmony_ci#include "gregoimp.h"
381cb0ef41Sopenharmony_ci#include "umutex.h"
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleTimeZone)
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci// Use only for decodeStartRule() and decodeEndRule() where the year is not
451cb0ef41Sopenharmony_ci// available. Set February to 29 days to accommodate rules with that date
461cb0ef41Sopenharmony_ci// and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).
471cb0ef41Sopenharmony_ci// The compareToRule() method adjusts to February 28 in non-leap years.
481cb0ef41Sopenharmony_ci//
491cb0ef41Sopenharmony_ci// For actual getOffset() calculations, use Grego::monthLength() and
501cb0ef41Sopenharmony_ci// Grego::previousMonthLength() which take leap years into account.
511cb0ef41Sopenharmony_ci// We handle leap years assuming always
521cb0ef41Sopenharmony_ci// Gregorian, since we know they didn't have daylight time when
531cb0ef41Sopenharmony_ci// Gregorian calendar started.
541cb0ef41Sopenharmony_ciconst int8_t SimpleTimeZone::STATICMONTHLENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cistatic const char16_t DST_STR[] = {0x0028,0x0044,0x0053,0x0054,0x0029,0}; // "(DST)"
571cb0ef41Sopenharmony_cistatic const char16_t STD_STR[] = {0x0028,0x0053,0x0054,0x0044,0x0029,0}; // "(STD)"
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci// *****************************************************************************
611cb0ef41Sopenharmony_ci// class SimpleTimeZone
621cb0ef41Sopenharmony_ci// *****************************************************************************
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciSimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID)
661cb0ef41Sopenharmony_ci:   BasicTimeZone(ID),
671cb0ef41Sopenharmony_ci    startMonth(0),
681cb0ef41Sopenharmony_ci    startDay(0),
691cb0ef41Sopenharmony_ci    startDayOfWeek(0),
701cb0ef41Sopenharmony_ci    startTime(0),
711cb0ef41Sopenharmony_ci    startTimeMode(WALL_TIME),
721cb0ef41Sopenharmony_ci    endTimeMode(WALL_TIME),
731cb0ef41Sopenharmony_ci    endMonth(0),
741cb0ef41Sopenharmony_ci    endDay(0),
751cb0ef41Sopenharmony_ci    endDayOfWeek(0),
761cb0ef41Sopenharmony_ci    endTime(0),
771cb0ef41Sopenharmony_ci    startYear(0),
781cb0ef41Sopenharmony_ci    rawOffset(rawOffsetGMT),
791cb0ef41Sopenharmony_ci    useDaylight(false),
801cb0ef41Sopenharmony_ci    startMode(DOM_MODE),
811cb0ef41Sopenharmony_ci    endMode(DOM_MODE),
821cb0ef41Sopenharmony_ci    dstSavings(U_MILLIS_PER_HOUR)
831cb0ef41Sopenharmony_ci{
841cb0ef41Sopenharmony_ci    clearTransitionRules();
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci// -------------------------------------
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciSimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
901cb0ef41Sopenharmony_ci    int8_t savingsStartMonth, int8_t savingsStartDay,
911cb0ef41Sopenharmony_ci    int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
921cb0ef41Sopenharmony_ci    int8_t savingsEndMonth, int8_t savingsEndDay,
931cb0ef41Sopenharmony_ci    int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
941cb0ef41Sopenharmony_ci    UErrorCode& status)
951cb0ef41Sopenharmony_ci:   BasicTimeZone(ID)
961cb0ef41Sopenharmony_ci{
971cb0ef41Sopenharmony_ci    clearTransitionRules();
981cb0ef41Sopenharmony_ci    construct(rawOffsetGMT,
991cb0ef41Sopenharmony_ci              savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
1001cb0ef41Sopenharmony_ci              savingsStartTime, WALL_TIME,
1011cb0ef41Sopenharmony_ci              savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
1021cb0ef41Sopenharmony_ci              savingsEndTime, WALL_TIME,
1031cb0ef41Sopenharmony_ci              U_MILLIS_PER_HOUR, status);
1041cb0ef41Sopenharmony_ci}
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci// -------------------------------------
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciSimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
1091cb0ef41Sopenharmony_ci    int8_t savingsStartMonth, int8_t savingsStartDay,
1101cb0ef41Sopenharmony_ci    int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
1111cb0ef41Sopenharmony_ci    int8_t savingsEndMonth, int8_t savingsEndDay,
1121cb0ef41Sopenharmony_ci    int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
1131cb0ef41Sopenharmony_ci    int32_t savingsDST, UErrorCode& status)
1141cb0ef41Sopenharmony_ci:   BasicTimeZone(ID)
1151cb0ef41Sopenharmony_ci{
1161cb0ef41Sopenharmony_ci    clearTransitionRules();
1171cb0ef41Sopenharmony_ci    construct(rawOffsetGMT,
1181cb0ef41Sopenharmony_ci              savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
1191cb0ef41Sopenharmony_ci              savingsStartTime, WALL_TIME,
1201cb0ef41Sopenharmony_ci              savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
1211cb0ef41Sopenharmony_ci              savingsEndTime, WALL_TIME,
1221cb0ef41Sopenharmony_ci              savingsDST, status);
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci// -------------------------------------
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ciSimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
1281cb0ef41Sopenharmony_ci    int8_t savingsStartMonth, int8_t savingsStartDay,
1291cb0ef41Sopenharmony_ci    int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
1301cb0ef41Sopenharmony_ci    TimeMode savingsStartTimeMode,
1311cb0ef41Sopenharmony_ci    int8_t savingsEndMonth, int8_t savingsEndDay,
1321cb0ef41Sopenharmony_ci    int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
1331cb0ef41Sopenharmony_ci    TimeMode savingsEndTimeMode,
1341cb0ef41Sopenharmony_ci    int32_t savingsDST, UErrorCode& status)
1351cb0ef41Sopenharmony_ci:   BasicTimeZone(ID)
1361cb0ef41Sopenharmony_ci{
1371cb0ef41Sopenharmony_ci    clearTransitionRules();
1381cb0ef41Sopenharmony_ci    construct(rawOffsetGMT,
1391cb0ef41Sopenharmony_ci              savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
1401cb0ef41Sopenharmony_ci              savingsStartTime, savingsStartTimeMode,
1411cb0ef41Sopenharmony_ci              savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
1421cb0ef41Sopenharmony_ci              savingsEndTime, savingsEndTimeMode,
1431cb0ef41Sopenharmony_ci              savingsDST, status);
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci/**
1471cb0ef41Sopenharmony_ci * Internal construction method.
1481cb0ef41Sopenharmony_ci */
1491cb0ef41Sopenharmony_civoid SimpleTimeZone::construct(int32_t rawOffsetGMT,
1501cb0ef41Sopenharmony_ci                               int8_t savingsStartMonth,
1511cb0ef41Sopenharmony_ci                               int8_t savingsStartDay,
1521cb0ef41Sopenharmony_ci                               int8_t savingsStartDayOfWeek,
1531cb0ef41Sopenharmony_ci                               int32_t savingsStartTime,
1541cb0ef41Sopenharmony_ci                               TimeMode savingsStartTimeMode,
1551cb0ef41Sopenharmony_ci                               int8_t savingsEndMonth,
1561cb0ef41Sopenharmony_ci                               int8_t savingsEndDay,
1571cb0ef41Sopenharmony_ci                               int8_t savingsEndDayOfWeek,
1581cb0ef41Sopenharmony_ci                               int32_t savingsEndTime,
1591cb0ef41Sopenharmony_ci                               TimeMode savingsEndTimeMode,
1601cb0ef41Sopenharmony_ci                               int32_t savingsDST,
1611cb0ef41Sopenharmony_ci                               UErrorCode& status)
1621cb0ef41Sopenharmony_ci{
1631cb0ef41Sopenharmony_ci    this->rawOffset      = rawOffsetGMT;
1641cb0ef41Sopenharmony_ci    this->startMonth     = savingsStartMonth;
1651cb0ef41Sopenharmony_ci    this->startDay       = savingsStartDay;
1661cb0ef41Sopenharmony_ci    this->startDayOfWeek = savingsStartDayOfWeek;
1671cb0ef41Sopenharmony_ci    this->startTime      = savingsStartTime;
1681cb0ef41Sopenharmony_ci    this->startTimeMode  = savingsStartTimeMode;
1691cb0ef41Sopenharmony_ci    this->endMonth       = savingsEndMonth;
1701cb0ef41Sopenharmony_ci    this->endDay         = savingsEndDay;
1711cb0ef41Sopenharmony_ci    this->endDayOfWeek   = savingsEndDayOfWeek;
1721cb0ef41Sopenharmony_ci    this->endTime        = savingsEndTime;
1731cb0ef41Sopenharmony_ci    this->endTimeMode    = savingsEndTimeMode;
1741cb0ef41Sopenharmony_ci    this->dstSavings     = savingsDST;
1751cb0ef41Sopenharmony_ci    this->startYear      = 0;
1761cb0ef41Sopenharmony_ci    this->startMode      = DOM_MODE;
1771cb0ef41Sopenharmony_ci    this->endMode        = DOM_MODE;
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci    decodeRules(status);
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci    if (savingsDST == 0) {
1821cb0ef41Sopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci// -------------------------------------
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ciSimpleTimeZone::~SimpleTimeZone()
1891cb0ef41Sopenharmony_ci{
1901cb0ef41Sopenharmony_ci    deleteTransitionRules();
1911cb0ef41Sopenharmony_ci}
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci// -------------------------------------
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci// Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
1961cb0ef41Sopenharmony_ciSimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source)
1971cb0ef41Sopenharmony_ci:   BasicTimeZone(source)
1981cb0ef41Sopenharmony_ci{
1991cb0ef41Sopenharmony_ci    *this = source;
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci// -------------------------------------
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci// Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
2051cb0ef41Sopenharmony_ciSimpleTimeZone &
2061cb0ef41Sopenharmony_ciSimpleTimeZone::operator=(const SimpleTimeZone &right)
2071cb0ef41Sopenharmony_ci{
2081cb0ef41Sopenharmony_ci    if (this != &right)
2091cb0ef41Sopenharmony_ci    {
2101cb0ef41Sopenharmony_ci        TimeZone::operator=(right);
2111cb0ef41Sopenharmony_ci        rawOffset      = right.rawOffset;
2121cb0ef41Sopenharmony_ci        startMonth     = right.startMonth;
2131cb0ef41Sopenharmony_ci        startDay       = right.startDay;
2141cb0ef41Sopenharmony_ci        startDayOfWeek = right.startDayOfWeek;
2151cb0ef41Sopenharmony_ci        startTime      = right.startTime;
2161cb0ef41Sopenharmony_ci        startTimeMode  = right.startTimeMode;
2171cb0ef41Sopenharmony_ci        startMode      = right.startMode;
2181cb0ef41Sopenharmony_ci        endMonth       = right.endMonth;
2191cb0ef41Sopenharmony_ci        endDay         = right.endDay;
2201cb0ef41Sopenharmony_ci        endDayOfWeek   = right.endDayOfWeek;
2211cb0ef41Sopenharmony_ci        endTime        = right.endTime;
2221cb0ef41Sopenharmony_ci        endTimeMode    = right.endTimeMode;
2231cb0ef41Sopenharmony_ci        endMode        = right.endMode;
2241cb0ef41Sopenharmony_ci        startYear      = right.startYear;
2251cb0ef41Sopenharmony_ci        dstSavings     = right.dstSavings;
2261cb0ef41Sopenharmony_ci        useDaylight    = right.useDaylight;
2271cb0ef41Sopenharmony_ci        clearTransitionRules();
2281cb0ef41Sopenharmony_ci    }
2291cb0ef41Sopenharmony_ci    return *this;
2301cb0ef41Sopenharmony_ci}
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci// -------------------------------------
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_cibool
2351cb0ef41Sopenharmony_ciSimpleTimeZone::operator==(const TimeZone& that) const
2361cb0ef41Sopenharmony_ci{
2371cb0ef41Sopenharmony_ci    return ((this == &that) ||
2381cb0ef41Sopenharmony_ci            (typeid(*this) == typeid(that) &&
2391cb0ef41Sopenharmony_ci            TimeZone::operator==(that) &&
2401cb0ef41Sopenharmony_ci            hasSameRules(that)));
2411cb0ef41Sopenharmony_ci}
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci// -------------------------------------
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci// Called by TimeZone::createDefault() inside a Mutex - be careful.
2461cb0ef41Sopenharmony_ciSimpleTimeZone*
2471cb0ef41Sopenharmony_ciSimpleTimeZone::clone() const
2481cb0ef41Sopenharmony_ci{
2491cb0ef41Sopenharmony_ci    return new SimpleTimeZone(*this);
2501cb0ef41Sopenharmony_ci}
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci// -------------------------------------
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci/**
2551cb0ef41Sopenharmony_ci * Sets the daylight savings starting year, that is, the year this time zone began
2561cb0ef41Sopenharmony_ci * observing its specified daylight savings time rules.  The time zone is considered
2571cb0ef41Sopenharmony_ci * not to observe daylight savings time prior to that year; SimpleTimeZone doesn't
2581cb0ef41Sopenharmony_ci * support historical daylight-savings-time rules.
2591cb0ef41Sopenharmony_ci * @param year the daylight savings starting year.
2601cb0ef41Sopenharmony_ci */
2611cb0ef41Sopenharmony_civoid
2621cb0ef41Sopenharmony_ciSimpleTimeZone::setStartYear(int32_t year)
2631cb0ef41Sopenharmony_ci{
2641cb0ef41Sopenharmony_ci    startYear = year;
2651cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
2661cb0ef41Sopenharmony_ci}
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci// -------------------------------------
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci/**
2711cb0ef41Sopenharmony_ci * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
2721cb0ef41Sopenharmony_ci * Time starts at the first Sunday in April, at 2 AM in standard time.
2731cb0ef41Sopenharmony_ci * Therefore, you can set the start rule by calling:
2741cb0ef41Sopenharmony_ci * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
2751cb0ef41Sopenharmony_ci * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
2761cb0ef41Sopenharmony_ci * the exact starting date.  Their exact meaning depend on their respective signs,
2771cb0ef41Sopenharmony_ci * allowing various types of rules to be constructed, as follows:<ul>
2781cb0ef41Sopenharmony_ci *   <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
2791cb0ef41Sopenharmony_ci *       day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
2801cb0ef41Sopenharmony_ci *       of the month).
2811cb0ef41Sopenharmony_ci *   <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
2821cb0ef41Sopenharmony_ci *       the day of week in the month counting backward from the end of the month.
2831cb0ef41Sopenharmony_ci *       (e.g., (-1, MONDAY) is the last Monday in the month)
2841cb0ef41Sopenharmony_ci *   <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
2851cb0ef41Sopenharmony_ci *       specifies the day of the month, regardless of what day of the week it is.
2861cb0ef41Sopenharmony_ci *       (e.g., (10, 0) is the tenth day of the month)
2871cb0ef41Sopenharmony_ci *   <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
2881cb0ef41Sopenharmony_ci *       specifies the day of the month counting backward from the end of the
2891cb0ef41Sopenharmony_ci *       month, regardless of what day of the week it is (e.g., (-2, 0) is the
2901cb0ef41Sopenharmony_ci *       next-to-last day of the month).
2911cb0ef41Sopenharmony_ci *   <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
2921cb0ef41Sopenharmony_ci *       first specified day of the week on or after the specified day of the month.
2931cb0ef41Sopenharmony_ci *       (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
2941cb0ef41Sopenharmony_ci *       [or the 15th itself if the 15th is a Sunday].)
2951cb0ef41Sopenharmony_ci *   <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
2961cb0ef41Sopenharmony_ci *       last specified day of the week on or before the specified day of the month.
2971cb0ef41Sopenharmony_ci *       (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
2981cb0ef41Sopenharmony_ci *       [or the 20th itself if the 20th is a Tuesday].)</ul>
2991cb0ef41Sopenharmony_ci * @param month the daylight savings starting month. Month is 0-based.
3001cb0ef41Sopenharmony_ci * eg, 0 for January.
3011cb0ef41Sopenharmony_ci * @param dayOfWeekInMonth the daylight savings starting
3021cb0ef41Sopenharmony_ci * day-of-week-in-month. Please see the member description for an example.
3031cb0ef41Sopenharmony_ci * @param dayOfWeek the daylight savings starting day-of-week. Please see
3041cb0ef41Sopenharmony_ci * the member description for an example.
3051cb0ef41Sopenharmony_ci * @param time the daylight savings starting time. Please see the member
3061cb0ef41Sopenharmony_ci * description for an example.
3071cb0ef41Sopenharmony_ci */
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_civoid
3101cb0ef41Sopenharmony_ciSimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
3111cb0ef41Sopenharmony_ci                             int32_t time, TimeMode mode, UErrorCode& status)
3121cb0ef41Sopenharmony_ci{
3131cb0ef41Sopenharmony_ci    startMonth     = (int8_t)month;
3141cb0ef41Sopenharmony_ci    startDay       = (int8_t)dayOfWeekInMonth;
3151cb0ef41Sopenharmony_ci    startDayOfWeek = (int8_t)dayOfWeek;
3161cb0ef41Sopenharmony_ci    startTime      = time;
3171cb0ef41Sopenharmony_ci    startTimeMode  = mode;
3181cb0ef41Sopenharmony_ci    decodeStartRule(status);
3191cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
3201cb0ef41Sopenharmony_ci}
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci// -------------------------------------
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_civoid
3251cb0ef41Sopenharmony_ciSimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
3261cb0ef41Sopenharmony_ci                             int32_t time, TimeMode mode, UErrorCode& status)
3271cb0ef41Sopenharmony_ci{
3281cb0ef41Sopenharmony_ci    setStartRule(month, dayOfMonth, 0, time, mode, status);
3291cb0ef41Sopenharmony_ci}
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci// -------------------------------------
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_civoid
3341cb0ef41Sopenharmony_ciSimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
3351cb0ef41Sopenharmony_ci                             int32_t time, TimeMode mode, UBool after, UErrorCode& status)
3361cb0ef41Sopenharmony_ci{
3371cb0ef41Sopenharmony_ci    setStartRule(month, after ? dayOfMonth : -dayOfMonth,
3381cb0ef41Sopenharmony_ci                 -dayOfWeek, time, mode, status);
3391cb0ef41Sopenharmony_ci}
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci// -------------------------------------
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci/**
3441cb0ef41Sopenharmony_ci * Sets the daylight savings ending rule. For example, in the U.S., Daylight
3451cb0ef41Sopenharmony_ci * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
3461cb0ef41Sopenharmony_ci * Therefore, you can set the end rule by calling:
3471cb0ef41Sopenharmony_ci * setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
3481cb0ef41Sopenharmony_ci * Various other types of rules can be specified by manipulating the dayOfWeek
3491cb0ef41Sopenharmony_ci * and dayOfWeekInMonth parameters.  For complete details, see the documentation
3501cb0ef41Sopenharmony_ci * for setStartRule().
3511cb0ef41Sopenharmony_ci * @param month the daylight savings ending month. Month is 0-based.
3521cb0ef41Sopenharmony_ci * eg, 0 for January.
3531cb0ef41Sopenharmony_ci * @param dayOfWeekInMonth the daylight savings ending
3541cb0ef41Sopenharmony_ci * day-of-week-in-month. See setStartRule() for a complete explanation.
3551cb0ef41Sopenharmony_ci * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
3561cb0ef41Sopenharmony_ci * for a complete explanation.
3571cb0ef41Sopenharmony_ci * @param time the daylight savings ending time. Please see the member
3581cb0ef41Sopenharmony_ci * description for an example.
3591cb0ef41Sopenharmony_ci */
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_civoid
3621cb0ef41Sopenharmony_ciSimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
3631cb0ef41Sopenharmony_ci                           int32_t time, TimeMode mode, UErrorCode& status)
3641cb0ef41Sopenharmony_ci{
3651cb0ef41Sopenharmony_ci    endMonth     = (int8_t)month;
3661cb0ef41Sopenharmony_ci    endDay       = (int8_t)dayOfWeekInMonth;
3671cb0ef41Sopenharmony_ci    endDayOfWeek = (int8_t)dayOfWeek;
3681cb0ef41Sopenharmony_ci    endTime      = time;
3691cb0ef41Sopenharmony_ci    endTimeMode  = mode;
3701cb0ef41Sopenharmony_ci    decodeEndRule(status);
3711cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci// -------------------------------------
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_civoid
3771cb0ef41Sopenharmony_ciSimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
3781cb0ef41Sopenharmony_ci                           int32_t time, TimeMode mode, UErrorCode& status)
3791cb0ef41Sopenharmony_ci{
3801cb0ef41Sopenharmony_ci    setEndRule(month, dayOfMonth, 0, time, mode, status);
3811cb0ef41Sopenharmony_ci}
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci// -------------------------------------
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_civoid
3861cb0ef41Sopenharmony_ciSimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
3871cb0ef41Sopenharmony_ci                           int32_t time, TimeMode mode, UBool after, UErrorCode& status)
3881cb0ef41Sopenharmony_ci{
3891cb0ef41Sopenharmony_ci    setEndRule(month, after ? dayOfMonth : -dayOfMonth,
3901cb0ef41Sopenharmony_ci               -dayOfWeek, time, mode, status);
3911cb0ef41Sopenharmony_ci}
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ci// -------------------------------------
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ciint32_t
3961cb0ef41Sopenharmony_ciSimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
3971cb0ef41Sopenharmony_ci                          uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const
3981cb0ef41Sopenharmony_ci{
3991cb0ef41Sopenharmony_ci    // Check the month before calling Grego::monthLength(). This
4001cb0ef41Sopenharmony_ci    // duplicates the test that occurs in the 7-argument getOffset(),
4011cb0ef41Sopenharmony_ci    // however, this is unavoidable. We don't mind because this method, in
4021cb0ef41Sopenharmony_ci    // fact, should not be called; internal code should always call the
4031cb0ef41Sopenharmony_ci    // 7-argument getOffset(), and outside code should use Calendar.get(int
4041cb0ef41Sopenharmony_ci    // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
4051cb0ef41Sopenharmony_ci    // this method because it's public API. - liu 8/10/98
4061cb0ef41Sopenharmony_ci    if(month < UCAL_JANUARY || month > UCAL_DECEMBER) {
4071cb0ef41Sopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
4081cb0ef41Sopenharmony_ci        return 0;
4091cb0ef41Sopenharmony_ci    }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci    return getOffset(era, year, month, day, dayOfWeek, millis, Grego::monthLength(year, month), status);
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ciint32_t
4151cb0ef41Sopenharmony_ciSimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
4161cb0ef41Sopenharmony_ci                          uint8_t dayOfWeek, int32_t millis,
4171cb0ef41Sopenharmony_ci                          int32_t /*monthLength*/, UErrorCode& status) const
4181cb0ef41Sopenharmony_ci{
4191cb0ef41Sopenharmony_ci    // Check the month before calling Grego::monthLength(). This
4201cb0ef41Sopenharmony_ci    // duplicates a test that occurs in the 9-argument getOffset(),
4211cb0ef41Sopenharmony_ci    // however, this is unavoidable. We don't mind because this method, in
4221cb0ef41Sopenharmony_ci    // fact, should not be called; internal code should always call the
4231cb0ef41Sopenharmony_ci    // 9-argument getOffset(), and outside code should use Calendar.get(int
4241cb0ef41Sopenharmony_ci    // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
4251cb0ef41Sopenharmony_ci    // this method because it's public API. - liu 8/10/98
4261cb0ef41Sopenharmony_ci    if (month < UCAL_JANUARY
4271cb0ef41Sopenharmony_ci        || month > UCAL_DECEMBER) {
4281cb0ef41Sopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
4291cb0ef41Sopenharmony_ci        return -1;
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci    // We ignore monthLength because it can be derived from year and month.
4331cb0ef41Sopenharmony_ci    // This is so that February in leap years is calculated correctly.
4341cb0ef41Sopenharmony_ci    // We keep this argument in this function for backwards compatibility.
4351cb0ef41Sopenharmony_ci    return getOffset(era, year, month, day, dayOfWeek, millis,
4361cb0ef41Sopenharmony_ci                     Grego::monthLength(year, month),
4371cb0ef41Sopenharmony_ci                     Grego::previousMonthLength(year, month),
4381cb0ef41Sopenharmony_ci                     status);
4391cb0ef41Sopenharmony_ci}
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ciint32_t
4421cb0ef41Sopenharmony_ciSimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
4431cb0ef41Sopenharmony_ci                          uint8_t dayOfWeek, int32_t millis,
4441cb0ef41Sopenharmony_ci                          int32_t monthLength, int32_t prevMonthLength,
4451cb0ef41Sopenharmony_ci                          UErrorCode& status) const
4461cb0ef41Sopenharmony_ci{
4471cb0ef41Sopenharmony_ci    if(U_FAILURE(status)) return 0;
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci    if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
4501cb0ef41Sopenharmony_ci        || month < UCAL_JANUARY
4511cb0ef41Sopenharmony_ci        || month > UCAL_DECEMBER
4521cb0ef41Sopenharmony_ci        || day < 1
4531cb0ef41Sopenharmony_ci        || day > monthLength
4541cb0ef41Sopenharmony_ci        || dayOfWeek < UCAL_SUNDAY
4551cb0ef41Sopenharmony_ci        || dayOfWeek > UCAL_SATURDAY
4561cb0ef41Sopenharmony_ci        || millis < 0
4571cb0ef41Sopenharmony_ci        || millis >= U_MILLIS_PER_DAY
4581cb0ef41Sopenharmony_ci        || monthLength < 28
4591cb0ef41Sopenharmony_ci        || monthLength > 31
4601cb0ef41Sopenharmony_ci        || prevMonthLength < 28
4611cb0ef41Sopenharmony_ci        || prevMonthLength > 31) {
4621cb0ef41Sopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
4631cb0ef41Sopenharmony_ci        return -1;
4641cb0ef41Sopenharmony_ci    }
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci    int32_t result = rawOffset;
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci    // Bail out if we are before the onset of daylight savings time
4691cb0ef41Sopenharmony_ci    if(!useDaylight || year < startYear || era != GregorianCalendar::AD)
4701cb0ef41Sopenharmony_ci        return result;
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci    // Check for southern hemisphere.  We assume that the start and end
4731cb0ef41Sopenharmony_ci    // month are different.
4741cb0ef41Sopenharmony_ci    UBool southern = (startMonth > endMonth);
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci    // Compare the date to the starting and ending rules.+1 = date>rule, -1
4771cb0ef41Sopenharmony_ci    // = date<rule, 0 = date==rule.
4781cb0ef41Sopenharmony_ci    int32_t startCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
4791cb0ef41Sopenharmony_ci                                         (int8_t)day, (int8_t)dayOfWeek, millis,
4801cb0ef41Sopenharmony_ci                                         startTimeMode == UTC_TIME ? -rawOffset : 0,
4811cb0ef41Sopenharmony_ci                                         startMode, (int8_t)startMonth, (int8_t)startDayOfWeek,
4821cb0ef41Sopenharmony_ci                                         (int8_t)startDay, startTime);
4831cb0ef41Sopenharmony_ci    int32_t endCompare = 0;
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci    /* We don't always have to compute endCompare.  For many instances,
4861cb0ef41Sopenharmony_ci     * startCompare is enough to determine if we are in DST or not.  In the
4871cb0ef41Sopenharmony_ci     * northern hemisphere, if we are before the start rule, we can't have
4881cb0ef41Sopenharmony_ci     * DST.  In the southern hemisphere, if we are after the start rule, we
4891cb0ef41Sopenharmony_ci     * must have DST.  This is reflected in the way the next if statement
4901cb0ef41Sopenharmony_ci     * (not the one immediately following) short circuits. */
4911cb0ef41Sopenharmony_ci    if(southern != (startCompare >= 0)) {
4921cb0ef41Sopenharmony_ci        endCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
4931cb0ef41Sopenharmony_ci                                   (int8_t)day, (int8_t)dayOfWeek, millis,
4941cb0ef41Sopenharmony_ci                                   endTimeMode == WALL_TIME ? dstSavings :
4951cb0ef41Sopenharmony_ci                                    (endTimeMode == UTC_TIME ? -rawOffset : 0),
4961cb0ef41Sopenharmony_ci                                   endMode, (int8_t)endMonth, (int8_t)endDayOfWeek,
4971cb0ef41Sopenharmony_ci                                   (int8_t)endDay, endTime);
4981cb0ef41Sopenharmony_ci    }
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci    // Check for both the northern and southern hemisphere cases.  We
5011cb0ef41Sopenharmony_ci    // assume that in the northern hemisphere, the start rule is before the
5021cb0ef41Sopenharmony_ci    // end rule within the calendar year, and vice versa for the southern
5031cb0ef41Sopenharmony_ci    // hemisphere.
5041cb0ef41Sopenharmony_ci    if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
5051cb0ef41Sopenharmony_ci        (southern && (startCompare >= 0 || endCompare < 0)))
5061cb0ef41Sopenharmony_ci        result += dstSavings;
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci    return result;
5091cb0ef41Sopenharmony_ci}
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_civoid
5121cb0ef41Sopenharmony_ciSimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingTimeOpt,
5131cb0ef41Sopenharmony_ci                                   UTimeZoneLocalOption duplicatedTimeOpt, int32_t& rawOffsetGMT,
5141cb0ef41Sopenharmony_ci                                   int32_t& savingsDST, UErrorCode& status) const
5151cb0ef41Sopenharmony_ci{
5161cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
5171cb0ef41Sopenharmony_ci        return;
5181cb0ef41Sopenharmony_ci    }
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci    rawOffsetGMT = getRawOffset();
5211cb0ef41Sopenharmony_ci    int32_t year, month, dom, dow, millis;
5221cb0ef41Sopenharmony_ci    int32_t day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci    Grego::dayToFields(day, year, month, dom, dow);
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci    savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
5271cb0ef41Sopenharmony_ci                          (uint8_t) dow, millis,
5281cb0ef41Sopenharmony_ci                          Grego::monthLength(year, month),
5291cb0ef41Sopenharmony_ci                          status) - rawOffsetGMT;
5301cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
5311cb0ef41Sopenharmony_ci        return;
5321cb0ef41Sopenharmony_ci    }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci    UBool recalc = false;
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci    // Now we need some adjustment
5371cb0ef41Sopenharmony_ci    if (savingsDST > 0) {
5381cb0ef41Sopenharmony_ci        if ((nonExistingTimeOpt & kStdDstMask) == kStandard
5391cb0ef41Sopenharmony_ci            || ((nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter)) {
5401cb0ef41Sopenharmony_ci            date -= getDSTSavings();
5411cb0ef41Sopenharmony_ci            recalc = true;
5421cb0ef41Sopenharmony_ci        }
5431cb0ef41Sopenharmony_ci    } else {
5441cb0ef41Sopenharmony_ci        if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
5451cb0ef41Sopenharmony_ci                || ((duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer)) {
5461cb0ef41Sopenharmony_ci            date -= getDSTSavings();
5471cb0ef41Sopenharmony_ci            recalc = true;
5481cb0ef41Sopenharmony_ci        }
5491cb0ef41Sopenharmony_ci    }
5501cb0ef41Sopenharmony_ci    if (recalc) {
5511cb0ef41Sopenharmony_ci        day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
5521cb0ef41Sopenharmony_ci        Grego::dayToFields(day, year, month, dom, dow);
5531cb0ef41Sopenharmony_ci        savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
5541cb0ef41Sopenharmony_ci                          (uint8_t) dow, millis,
5551cb0ef41Sopenharmony_ci                          Grego::monthLength(year, month),
5561cb0ef41Sopenharmony_ci                          status) - rawOffsetGMT;
5571cb0ef41Sopenharmony_ci    }
5581cb0ef41Sopenharmony_ci}
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ci// -------------------------------------
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ci/**
5631cb0ef41Sopenharmony_ci * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
5641cb0ef41Sopenharmony_ci * on whether the date is after, equal to, or before the rule date. The
5651cb0ef41Sopenharmony_ci * millis are compared directly against the ruleMillis, so any
5661cb0ef41Sopenharmony_ci * standard-daylight adjustments must be handled by the caller.
5671cb0ef41Sopenharmony_ci *
5681cb0ef41Sopenharmony_ci * @return  1 if the date is after the rule date, -1 if the date is before
5691cb0ef41Sopenharmony_ci *          the rule date, or 0 if the date is equal to the rule date.
5701cb0ef41Sopenharmony_ci */
5711cb0ef41Sopenharmony_ciint32_t
5721cb0ef41Sopenharmony_ciSimpleTimeZone::compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
5731cb0ef41Sopenharmony_ci                              int8_t dayOfMonth,
5741cb0ef41Sopenharmony_ci                              int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
5751cb0ef41Sopenharmony_ci                              EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
5761cb0ef41Sopenharmony_ci                              int8_t ruleDay, int32_t ruleMillis)
5771cb0ef41Sopenharmony_ci{
5781cb0ef41Sopenharmony_ci    // Make adjustments for startTimeMode and endTimeMode
5791cb0ef41Sopenharmony_ci    millis += millisDelta;
5801cb0ef41Sopenharmony_ci    while (millis >= U_MILLIS_PER_DAY) {
5811cb0ef41Sopenharmony_ci        millis -= U_MILLIS_PER_DAY;
5821cb0ef41Sopenharmony_ci        ++dayOfMonth;
5831cb0ef41Sopenharmony_ci        dayOfWeek = (int8_t)(1 + (dayOfWeek % 7)); // dayOfWeek is one-based
5841cb0ef41Sopenharmony_ci        if (dayOfMonth > monthLen) {
5851cb0ef41Sopenharmony_ci            dayOfMonth = 1;
5861cb0ef41Sopenharmony_ci            /* When incrementing the month, it is desirable to overflow
5871cb0ef41Sopenharmony_ci             * from DECEMBER to DECEMBER+1, since we use the result to
5881cb0ef41Sopenharmony_ci             * compare against a real month. Wraparound of the value
5891cb0ef41Sopenharmony_ci             * leads to bug 4173604. */
5901cb0ef41Sopenharmony_ci            ++month;
5911cb0ef41Sopenharmony_ci        }
5921cb0ef41Sopenharmony_ci    }
5931cb0ef41Sopenharmony_ci    while (millis < 0) {
5941cb0ef41Sopenharmony_ci        millis += U_MILLIS_PER_DAY;
5951cb0ef41Sopenharmony_ci        --dayOfMonth;
5961cb0ef41Sopenharmony_ci        dayOfWeek = (int8_t)(1 + ((dayOfWeek+5) % 7)); // dayOfWeek is one-based
5971cb0ef41Sopenharmony_ci        if (dayOfMonth < 1) {
5981cb0ef41Sopenharmony_ci            dayOfMonth = prevMonthLen;
5991cb0ef41Sopenharmony_ci            --month;
6001cb0ef41Sopenharmony_ci        }
6011cb0ef41Sopenharmony_ci    }
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci    // first compare months.  If they're different, we don't have to worry about days
6041cb0ef41Sopenharmony_ci    // and times
6051cb0ef41Sopenharmony_ci    if (month < ruleMonth) return -1;
6061cb0ef41Sopenharmony_ci    else if (month > ruleMonth) return 1;
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ci    // calculate the actual day of month for the rule
6091cb0ef41Sopenharmony_ci    int32_t ruleDayOfMonth = 0;
6101cb0ef41Sopenharmony_ci
6111cb0ef41Sopenharmony_ci    // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.
6121cb0ef41Sopenharmony_ci    if (ruleDay > monthLen) {
6131cb0ef41Sopenharmony_ci        ruleDay = monthLen;
6141cb0ef41Sopenharmony_ci    }
6151cb0ef41Sopenharmony_ci
6161cb0ef41Sopenharmony_ci    switch (ruleMode)
6171cb0ef41Sopenharmony_ci    {
6181cb0ef41Sopenharmony_ci    // if the mode is day-of-month, the day of month is given
6191cb0ef41Sopenharmony_ci    case DOM_MODE:
6201cb0ef41Sopenharmony_ci        ruleDayOfMonth = ruleDay;
6211cb0ef41Sopenharmony_ci        break;
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci    // if the mode is day-of-week-in-month, calculate the day-of-month from it
6241cb0ef41Sopenharmony_ci    case DOW_IN_MONTH_MODE:
6251cb0ef41Sopenharmony_ci        // In this case ruleDay is the day-of-week-in-month (this code is using
6261cb0ef41Sopenharmony_ci        // the dayOfWeek and dayOfMonth parameters to figure out the day-of-week
6271cb0ef41Sopenharmony_ci        // of the first day of the month, so it's trusting that they're really
6281cb0ef41Sopenharmony_ci        // consistent with each other)
6291cb0ef41Sopenharmony_ci        if (ruleDay > 0)
6301cb0ef41Sopenharmony_ci            ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
6311cb0ef41Sopenharmony_ci                (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
6321cb0ef41Sopenharmony_ci
6331cb0ef41Sopenharmony_ci        // if ruleDay is negative (we assume it's not zero here), we have to do
6341cb0ef41Sopenharmony_ci        // the same calculation figuring backward from the last day of the month.
6351cb0ef41Sopenharmony_ci        else
6361cb0ef41Sopenharmony_ci        {
6371cb0ef41Sopenharmony_ci            // (again, this code is trusting that dayOfWeek and dayOfMonth are
6381cb0ef41Sopenharmony_ci            // consistent with each other here, since we're using them to figure
6391cb0ef41Sopenharmony_ci            // the day of week of the first of the month)
6401cb0ef41Sopenharmony_ci            ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
6411cb0ef41Sopenharmony_ci                (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
6421cb0ef41Sopenharmony_ci        }
6431cb0ef41Sopenharmony_ci        break;
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci    case DOW_GE_DOM_MODE:
6461cb0ef41Sopenharmony_ci        ruleDayOfMonth = ruleDay +
6471cb0ef41Sopenharmony_ci            (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
6481cb0ef41Sopenharmony_ci        break;
6491cb0ef41Sopenharmony_ci
6501cb0ef41Sopenharmony_ci    case DOW_LE_DOM_MODE:
6511cb0ef41Sopenharmony_ci        ruleDayOfMonth = ruleDay -
6521cb0ef41Sopenharmony_ci            (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
6531cb0ef41Sopenharmony_ci        // Note at this point ruleDayOfMonth may be <1, although it will
6541cb0ef41Sopenharmony_ci        // be >=1 for well-formed rules.
6551cb0ef41Sopenharmony_ci        break;
6561cb0ef41Sopenharmony_ci    }
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci    // now that we have a real day-in-month for the rule, we can compare days...
6591cb0ef41Sopenharmony_ci    if (dayOfMonth < ruleDayOfMonth) return -1;
6601cb0ef41Sopenharmony_ci    else if (dayOfMonth > ruleDayOfMonth) return 1;
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci    // ...and if they're equal, we compare times
6631cb0ef41Sopenharmony_ci    if (millis < ruleMillis) return -1;
6641cb0ef41Sopenharmony_ci    else if (millis > ruleMillis) return 1;
6651cb0ef41Sopenharmony_ci    else return 0;
6661cb0ef41Sopenharmony_ci}
6671cb0ef41Sopenharmony_ci
6681cb0ef41Sopenharmony_ci// -------------------------------------
6691cb0ef41Sopenharmony_ci
6701cb0ef41Sopenharmony_ciint32_t
6711cb0ef41Sopenharmony_ciSimpleTimeZone::getRawOffset() const
6721cb0ef41Sopenharmony_ci{
6731cb0ef41Sopenharmony_ci    return rawOffset;
6741cb0ef41Sopenharmony_ci}
6751cb0ef41Sopenharmony_ci
6761cb0ef41Sopenharmony_ci// -------------------------------------
6771cb0ef41Sopenharmony_ci
6781cb0ef41Sopenharmony_civoid
6791cb0ef41Sopenharmony_ciSimpleTimeZone::setRawOffset(int32_t offsetMillis)
6801cb0ef41Sopenharmony_ci{
6811cb0ef41Sopenharmony_ci    rawOffset = offsetMillis;
6821cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
6831cb0ef41Sopenharmony_ci}
6841cb0ef41Sopenharmony_ci
6851cb0ef41Sopenharmony_ci// -------------------------------------
6861cb0ef41Sopenharmony_ci
6871cb0ef41Sopenharmony_civoid
6881cb0ef41Sopenharmony_ciSimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
6891cb0ef41Sopenharmony_ci{
6901cb0ef41Sopenharmony_ci    if (millisSavedDuringDST == 0) {
6911cb0ef41Sopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
6921cb0ef41Sopenharmony_ci    }
6931cb0ef41Sopenharmony_ci    else {
6941cb0ef41Sopenharmony_ci        dstSavings = millisSavedDuringDST;
6951cb0ef41Sopenharmony_ci    }
6961cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
6971cb0ef41Sopenharmony_ci}
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci// -------------------------------------
7001cb0ef41Sopenharmony_ci
7011cb0ef41Sopenharmony_ciint32_t
7021cb0ef41Sopenharmony_ciSimpleTimeZone::getDSTSavings() const
7031cb0ef41Sopenharmony_ci{
7041cb0ef41Sopenharmony_ci    return dstSavings;
7051cb0ef41Sopenharmony_ci}
7061cb0ef41Sopenharmony_ci
7071cb0ef41Sopenharmony_ci// -------------------------------------
7081cb0ef41Sopenharmony_ci
7091cb0ef41Sopenharmony_ciUBool
7101cb0ef41Sopenharmony_ciSimpleTimeZone::useDaylightTime() const
7111cb0ef41Sopenharmony_ci{
7121cb0ef41Sopenharmony_ci    return useDaylight;
7131cb0ef41Sopenharmony_ci}
7141cb0ef41Sopenharmony_ci
7151cb0ef41Sopenharmony_ci// -------------------------------------
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_ci/**
7181cb0ef41Sopenharmony_ci * Overrides TimeZone
7191cb0ef41Sopenharmony_ci * Queries if the given date is in Daylight Savings Time.
7201cb0ef41Sopenharmony_ci */
7211cb0ef41Sopenharmony_ciUBool SimpleTimeZone::inDaylightTime(UDate date, UErrorCode& status) const
7221cb0ef41Sopenharmony_ci{
7231cb0ef41Sopenharmony_ci    // This method is wasteful since it creates a new GregorianCalendar and
7241cb0ef41Sopenharmony_ci    // deletes it each time it is called.  However, this is a deprecated method
7251cb0ef41Sopenharmony_ci    // and provided only for Java compatibility as of 8/6/97 [LIU].
7261cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) return false;
7271cb0ef41Sopenharmony_ci    GregorianCalendar *gc = new GregorianCalendar(*this, status);
7281cb0ef41Sopenharmony_ci    /* test for nullptr */
7291cb0ef41Sopenharmony_ci    if (gc == 0) {
7301cb0ef41Sopenharmony_ci        status = U_MEMORY_ALLOCATION_ERROR;
7311cb0ef41Sopenharmony_ci        return false;
7321cb0ef41Sopenharmony_ci    }
7331cb0ef41Sopenharmony_ci    gc->setTime(date, status);
7341cb0ef41Sopenharmony_ci    UBool result = gc->inDaylightTime(status);
7351cb0ef41Sopenharmony_ci    delete gc;
7361cb0ef41Sopenharmony_ci    return result;
7371cb0ef41Sopenharmony_ci}
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci// -------------------------------------
7401cb0ef41Sopenharmony_ci
7411cb0ef41Sopenharmony_ci/**
7421cb0ef41Sopenharmony_ci * Return true if this zone has the same rules and offset as another zone.
7431cb0ef41Sopenharmony_ci * @param other the TimeZone object to be compared with
7441cb0ef41Sopenharmony_ci * @return true if the given zone has the same rules and offset as this one
7451cb0ef41Sopenharmony_ci */
7461cb0ef41Sopenharmony_ciUBool
7471cb0ef41Sopenharmony_ciSimpleTimeZone::hasSameRules(const TimeZone& other) const
7481cb0ef41Sopenharmony_ci{
7491cb0ef41Sopenharmony_ci    if (this == &other) return true;
7501cb0ef41Sopenharmony_ci    if (typeid(*this) != typeid(other)) return false;
7511cb0ef41Sopenharmony_ci    SimpleTimeZone *that = (SimpleTimeZone*)&other;
7521cb0ef41Sopenharmony_ci    return rawOffset     == that->rawOffset &&
7531cb0ef41Sopenharmony_ci        useDaylight     == that->useDaylight &&
7541cb0ef41Sopenharmony_ci        (!useDaylight
7551cb0ef41Sopenharmony_ci         // Only check rules if using DST
7561cb0ef41Sopenharmony_ci         || (dstSavings     == that->dstSavings &&
7571cb0ef41Sopenharmony_ci             startMode      == that->startMode &&
7581cb0ef41Sopenharmony_ci             startMonth     == that->startMonth &&
7591cb0ef41Sopenharmony_ci             startDay       == that->startDay &&
7601cb0ef41Sopenharmony_ci             startDayOfWeek == that->startDayOfWeek &&
7611cb0ef41Sopenharmony_ci             startTime      == that->startTime &&
7621cb0ef41Sopenharmony_ci             startTimeMode  == that->startTimeMode &&
7631cb0ef41Sopenharmony_ci             endMode        == that->endMode &&
7641cb0ef41Sopenharmony_ci             endMonth       == that->endMonth &&
7651cb0ef41Sopenharmony_ci             endDay         == that->endDay &&
7661cb0ef41Sopenharmony_ci             endDayOfWeek   == that->endDayOfWeek &&
7671cb0ef41Sopenharmony_ci             endTime        == that->endTime &&
7681cb0ef41Sopenharmony_ci             endTimeMode    == that->endTimeMode &&
7691cb0ef41Sopenharmony_ci             startYear      == that->startYear));
7701cb0ef41Sopenharmony_ci}
7711cb0ef41Sopenharmony_ci
7721cb0ef41Sopenharmony_ci// -------------------------------------
7731cb0ef41Sopenharmony_ci
7741cb0ef41Sopenharmony_ci//----------------------------------------------------------------------
7751cb0ef41Sopenharmony_ci// Rule representation
7761cb0ef41Sopenharmony_ci//
7771cb0ef41Sopenharmony_ci// We represent the following flavors of rules:
7781cb0ef41Sopenharmony_ci//       5        the fifth of the month
7791cb0ef41Sopenharmony_ci//       lastSun  the last Sunday in the month
7801cb0ef41Sopenharmony_ci//       lastMon  the last Monday in the month
7811cb0ef41Sopenharmony_ci//       Sun>=8   first Sunday on or after the eighth
7821cb0ef41Sopenharmony_ci//       Sun<=25  last Sunday on or before the 25th
7831cb0ef41Sopenharmony_ci// This is further complicated by the fact that we need to remain
7841cb0ef41Sopenharmony_ci// backward compatible with the 1.1 FCS.  Finally, we need to minimize
7851cb0ef41Sopenharmony_ci// API changes.  In order to satisfy these requirements, we support
7861cb0ef41Sopenharmony_ci// three representation systems, and we translate between them.
7871cb0ef41Sopenharmony_ci//
7881cb0ef41Sopenharmony_ci// INTERNAL REPRESENTATION
7891cb0ef41Sopenharmony_ci// This is the format SimpleTimeZone objects take after construction or
7901cb0ef41Sopenharmony_ci// streaming in is complete.  Rules are represented directly, using an
7911cb0ef41Sopenharmony_ci// unencoded format.  We will discuss the start rule only below; the end
7921cb0ef41Sopenharmony_ci// rule is analogous.
7931cb0ef41Sopenharmony_ci//   startMode      Takes on enumerated values DAY_OF_MONTH,
7941cb0ef41Sopenharmony_ci//                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
7951cb0ef41Sopenharmony_ci//   startDay       The day of the month, or for DOW_IN_MONTH mode, a
7961cb0ef41Sopenharmony_ci//                  value indicating which DOW, such as +1 for first,
7971cb0ef41Sopenharmony_ci//                  +2 for second, -1 for last, etc.
7981cb0ef41Sopenharmony_ci//   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
7991cb0ef41Sopenharmony_ci//
8001cb0ef41Sopenharmony_ci// ENCODED REPRESENTATION
8011cb0ef41Sopenharmony_ci// This is the format accepted by the constructor and by setStartRule()
8021cb0ef41Sopenharmony_ci// and setEndRule().  It uses various combinations of positive, negative,
8031cb0ef41Sopenharmony_ci// and zero values to encode the different rules.  This representation
8041cb0ef41Sopenharmony_ci// allows us to specify all the different rule flavors without altering
8051cb0ef41Sopenharmony_ci// the API.
8061cb0ef41Sopenharmony_ci//   MODE              startMonth    startDay    startDayOfWeek
8071cb0ef41Sopenharmony_ci//   DOW_IN_MONTH_MODE >=0           !=0         >0
8081cb0ef41Sopenharmony_ci//   DOM_MODE          >=0           >0          ==0
8091cb0ef41Sopenharmony_ci//   DOW_GE_DOM_MODE   >=0           >0          <0
8101cb0ef41Sopenharmony_ci//   DOW_LE_DOM_MODE   >=0           <0          <0
8111cb0ef41Sopenharmony_ci//   (no DST)          don't care    ==0         don't care
8121cb0ef41Sopenharmony_ci//
8131cb0ef41Sopenharmony_ci// STREAMED REPRESENTATION
8141cb0ef41Sopenharmony_ci// We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
8151cb0ef41Sopenharmony_ci// handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
8161cb0ef41Sopenharmony_ci// flag useDaylight.  When we stream an object out, we translate into an
8171cb0ef41Sopenharmony_ci// approximate DOW_IN_MONTH_MODE representation so the object can be parsed
8181cb0ef41Sopenharmony_ci// and used by 1.1 code.  Following that, we write out the full
8191cb0ef41Sopenharmony_ci// representation separately so that contemporary code can recognize and
8201cb0ef41Sopenharmony_ci// parse it.  The full representation is written in a "packed" format,
8211cb0ef41Sopenharmony_ci// consisting of a version number, a length, and an array of bytes.  Future
8221cb0ef41Sopenharmony_ci// versions of this class may specify different versions.  If they wish to
8231cb0ef41Sopenharmony_ci// include additional data, they should do so by storing them after the
8241cb0ef41Sopenharmony_ci// packed representation below.
8251cb0ef41Sopenharmony_ci//----------------------------------------------------------------------
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ci/**
8281cb0ef41Sopenharmony_ci * Given a set of encoded rules in startDay and startDayOfMonth, decode
8291cb0ef41Sopenharmony_ci * them and set the startMode appropriately.  Do the same for endDay and
8301cb0ef41Sopenharmony_ci * endDayOfMonth.  Upon entry, the day of week variables may be zero or
8311cb0ef41Sopenharmony_ci * negative, in order to indicate special modes.  The day of month
8321cb0ef41Sopenharmony_ci * variables may also be negative.  Upon exit, the mode variables will be
8331cb0ef41Sopenharmony_ci * set, and the day of week and day of month variables will be positive.
8341cb0ef41Sopenharmony_ci * This method also recognizes a startDay or endDay of zero as indicating
8351cb0ef41Sopenharmony_ci * no DST.
8361cb0ef41Sopenharmony_ci */
8371cb0ef41Sopenharmony_civoid
8381cb0ef41Sopenharmony_ciSimpleTimeZone::decodeRules(UErrorCode& status)
8391cb0ef41Sopenharmony_ci{
8401cb0ef41Sopenharmony_ci    decodeStartRule(status);
8411cb0ef41Sopenharmony_ci    decodeEndRule(status);
8421cb0ef41Sopenharmony_ci}
8431cb0ef41Sopenharmony_ci
8441cb0ef41Sopenharmony_ci/**
8451cb0ef41Sopenharmony_ci * Decode the start rule and validate the parameters.  The parameters are
8461cb0ef41Sopenharmony_ci * expected to be in encoded form, which represents the various rule modes
8471cb0ef41Sopenharmony_ci * by negating or zeroing certain values.  Representation formats are:
8481cb0ef41Sopenharmony_ci * <p>
8491cb0ef41Sopenharmony_ci * <pre>
8501cb0ef41Sopenharmony_ci *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
8511cb0ef41Sopenharmony_ci *            ------------  -----  --------  --------  ----------
8521cb0ef41Sopenharmony_ci * month       0..11        same    same      same     don't care
8531cb0ef41Sopenharmony_ci * day        -5..5         1..31   1..31    -1..-31   0
8541cb0ef41Sopenharmony_ci * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
8551cb0ef41Sopenharmony_ci * time        0..ONEDAY    same    same      same     don't care
8561cb0ef41Sopenharmony_ci * </pre>
8571cb0ef41Sopenharmony_ci * The range for month does not include UNDECIMBER since this class is
8581cb0ef41Sopenharmony_ci * really specific to GregorianCalendar, which does not use that month.
8591cb0ef41Sopenharmony_ci * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
8601cb0ef41Sopenharmony_ci * end rule is an exclusive limit point.  That is, the range of times that
8611cb0ef41Sopenharmony_ci * are in DST include those >= the start and < the end.  For this reason,
8621cb0ef41Sopenharmony_ci * it should be possible to specify an end of ONEDAY in order to include the
8631cb0ef41Sopenharmony_ci * entire day.  Although this is equivalent to time 0 of the following day,
8641cb0ef41Sopenharmony_ci * it's not always possible to specify that, for example, on December 31.
8651cb0ef41Sopenharmony_ci * While arguably the start range should still be 0..ONEDAY-1, we keep
8661cb0ef41Sopenharmony_ci * the start and end ranges the same for consistency.
8671cb0ef41Sopenharmony_ci */
8681cb0ef41Sopenharmony_civoid
8691cb0ef41Sopenharmony_ciSimpleTimeZone::decodeStartRule(UErrorCode& status)
8701cb0ef41Sopenharmony_ci{
8711cb0ef41Sopenharmony_ci    if(U_FAILURE(status)) return;
8721cb0ef41Sopenharmony_ci
8731cb0ef41Sopenharmony_ci    useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
8741cb0ef41Sopenharmony_ci    if (useDaylight && dstSavings == 0) {
8751cb0ef41Sopenharmony_ci        dstSavings = U_MILLIS_PER_HOUR;
8761cb0ef41Sopenharmony_ci    }
8771cb0ef41Sopenharmony_ci    if (startDay != 0) {
8781cb0ef41Sopenharmony_ci        if (startMonth < UCAL_JANUARY || startMonth > UCAL_DECEMBER) {
8791cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
8801cb0ef41Sopenharmony_ci            return;
8811cb0ef41Sopenharmony_ci        }
8821cb0ef41Sopenharmony_ci        if (startTime < 0 || startTime > U_MILLIS_PER_DAY ||
8831cb0ef41Sopenharmony_ci            startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {
8841cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
8851cb0ef41Sopenharmony_ci            return;
8861cb0ef41Sopenharmony_ci        }
8871cb0ef41Sopenharmony_ci        if (startDayOfWeek == 0) {
8881cb0ef41Sopenharmony_ci            startMode = DOM_MODE;
8891cb0ef41Sopenharmony_ci        } else {
8901cb0ef41Sopenharmony_ci            if (startDayOfWeek > 0) {
8911cb0ef41Sopenharmony_ci                startMode = DOW_IN_MONTH_MODE;
8921cb0ef41Sopenharmony_ci            } else {
8931cb0ef41Sopenharmony_ci                startDayOfWeek = (int8_t)-startDayOfWeek;
8941cb0ef41Sopenharmony_ci                if (startDay > 0) {
8951cb0ef41Sopenharmony_ci                    startMode = DOW_GE_DOM_MODE;
8961cb0ef41Sopenharmony_ci                } else {
8971cb0ef41Sopenharmony_ci                    startDay = (int8_t)-startDay;
8981cb0ef41Sopenharmony_ci                    startMode = DOW_LE_DOM_MODE;
8991cb0ef41Sopenharmony_ci                }
9001cb0ef41Sopenharmony_ci            }
9011cb0ef41Sopenharmony_ci            if (startDayOfWeek > UCAL_SATURDAY) {
9021cb0ef41Sopenharmony_ci                status = U_ILLEGAL_ARGUMENT_ERROR;
9031cb0ef41Sopenharmony_ci                return;
9041cb0ef41Sopenharmony_ci            }
9051cb0ef41Sopenharmony_ci        }
9061cb0ef41Sopenharmony_ci        if (startMode == DOW_IN_MONTH_MODE) {
9071cb0ef41Sopenharmony_ci            if (startDay < -5 || startDay > 5) {
9081cb0ef41Sopenharmony_ci                status = U_ILLEGAL_ARGUMENT_ERROR;
9091cb0ef41Sopenharmony_ci                return;
9101cb0ef41Sopenharmony_ci            }
9111cb0ef41Sopenharmony_ci        } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) {
9121cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
9131cb0ef41Sopenharmony_ci            return;
9141cb0ef41Sopenharmony_ci        }
9151cb0ef41Sopenharmony_ci    }
9161cb0ef41Sopenharmony_ci}
9171cb0ef41Sopenharmony_ci
9181cb0ef41Sopenharmony_ci/**
9191cb0ef41Sopenharmony_ci * Decode the end rule and validate the parameters.  This method is exactly
9201cb0ef41Sopenharmony_ci * analogous to decodeStartRule().
9211cb0ef41Sopenharmony_ci * @see decodeStartRule
9221cb0ef41Sopenharmony_ci */
9231cb0ef41Sopenharmony_civoid
9241cb0ef41Sopenharmony_ciSimpleTimeZone::decodeEndRule(UErrorCode& status)
9251cb0ef41Sopenharmony_ci{
9261cb0ef41Sopenharmony_ci    if(U_FAILURE(status)) return;
9271cb0ef41Sopenharmony_ci
9281cb0ef41Sopenharmony_ci    useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
9291cb0ef41Sopenharmony_ci    if (useDaylight && dstSavings == 0) {
9301cb0ef41Sopenharmony_ci        dstSavings = U_MILLIS_PER_HOUR;
9311cb0ef41Sopenharmony_ci    }
9321cb0ef41Sopenharmony_ci    if (endDay != 0) {
9331cb0ef41Sopenharmony_ci        if (endMonth < UCAL_JANUARY || endMonth > UCAL_DECEMBER) {
9341cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
9351cb0ef41Sopenharmony_ci            return;
9361cb0ef41Sopenharmony_ci        }
9371cb0ef41Sopenharmony_ci        if (endTime < 0 || endTime > U_MILLIS_PER_DAY ||
9381cb0ef41Sopenharmony_ci            endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {
9391cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
9401cb0ef41Sopenharmony_ci            return;
9411cb0ef41Sopenharmony_ci        }
9421cb0ef41Sopenharmony_ci        if (endDayOfWeek == 0) {
9431cb0ef41Sopenharmony_ci            endMode = DOM_MODE;
9441cb0ef41Sopenharmony_ci        } else {
9451cb0ef41Sopenharmony_ci            if (endDayOfWeek > 0) {
9461cb0ef41Sopenharmony_ci                endMode = DOW_IN_MONTH_MODE;
9471cb0ef41Sopenharmony_ci            } else {
9481cb0ef41Sopenharmony_ci                endDayOfWeek = (int8_t)-endDayOfWeek;
9491cb0ef41Sopenharmony_ci                if (endDay > 0) {
9501cb0ef41Sopenharmony_ci                    endMode = DOW_GE_DOM_MODE;
9511cb0ef41Sopenharmony_ci                } else {
9521cb0ef41Sopenharmony_ci                    endDay = (int8_t)-endDay;
9531cb0ef41Sopenharmony_ci                    endMode = DOW_LE_DOM_MODE;
9541cb0ef41Sopenharmony_ci                }
9551cb0ef41Sopenharmony_ci            }
9561cb0ef41Sopenharmony_ci            if (endDayOfWeek > UCAL_SATURDAY) {
9571cb0ef41Sopenharmony_ci                status = U_ILLEGAL_ARGUMENT_ERROR;
9581cb0ef41Sopenharmony_ci                return;
9591cb0ef41Sopenharmony_ci            }
9601cb0ef41Sopenharmony_ci        }
9611cb0ef41Sopenharmony_ci        if (endMode == DOW_IN_MONTH_MODE) {
9621cb0ef41Sopenharmony_ci            if (endDay < -5 || endDay > 5) {
9631cb0ef41Sopenharmony_ci                status = U_ILLEGAL_ARGUMENT_ERROR;
9641cb0ef41Sopenharmony_ci                return;
9651cb0ef41Sopenharmony_ci            }
9661cb0ef41Sopenharmony_ci        } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) {
9671cb0ef41Sopenharmony_ci            status = U_ILLEGAL_ARGUMENT_ERROR;
9681cb0ef41Sopenharmony_ci            return;
9691cb0ef41Sopenharmony_ci        }
9701cb0ef41Sopenharmony_ci    }
9711cb0ef41Sopenharmony_ci}
9721cb0ef41Sopenharmony_ci
9731cb0ef41Sopenharmony_ciUBool
9741cb0ef41Sopenharmony_ciSimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
9751cb0ef41Sopenharmony_ci    if (!useDaylight) {
9761cb0ef41Sopenharmony_ci        return false;
9771cb0ef41Sopenharmony_ci    }
9781cb0ef41Sopenharmony_ci
9791cb0ef41Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
9801cb0ef41Sopenharmony_ci    checkTransitionRules(status);
9811cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
9821cb0ef41Sopenharmony_ci        return false;
9831cb0ef41Sopenharmony_ci    }
9841cb0ef41Sopenharmony_ci
9851cb0ef41Sopenharmony_ci    UDate firstTransitionTime = firstTransition->getTime();
9861cb0ef41Sopenharmony_ci    if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
9871cb0ef41Sopenharmony_ci        result = *firstTransition;
9881cb0ef41Sopenharmony_ci    }
9891cb0ef41Sopenharmony_ci    UDate stdDate, dstDate;
9901cb0ef41Sopenharmony_ci    UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
9911cb0ef41Sopenharmony_ci    UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
9921cb0ef41Sopenharmony_ci    if (stdAvail && (!dstAvail || stdDate < dstDate)) {
9931cb0ef41Sopenharmony_ci        result.setTime(stdDate);
9941cb0ef41Sopenharmony_ci        result.setFrom(*dstRule);
9951cb0ef41Sopenharmony_ci        result.setTo(*stdRule);
9961cb0ef41Sopenharmony_ci        return true;
9971cb0ef41Sopenharmony_ci    }
9981cb0ef41Sopenharmony_ci    if (dstAvail && (!stdAvail || dstDate < stdDate)) {
9991cb0ef41Sopenharmony_ci        result.setTime(dstDate);
10001cb0ef41Sopenharmony_ci        result.setFrom(*stdRule);
10011cb0ef41Sopenharmony_ci        result.setTo(*dstRule);
10021cb0ef41Sopenharmony_ci        return true;
10031cb0ef41Sopenharmony_ci    }
10041cb0ef41Sopenharmony_ci    return false;
10051cb0ef41Sopenharmony_ci}
10061cb0ef41Sopenharmony_ci
10071cb0ef41Sopenharmony_ciUBool
10081cb0ef41Sopenharmony_ciSimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
10091cb0ef41Sopenharmony_ci    if (!useDaylight) {
10101cb0ef41Sopenharmony_ci        return false;
10111cb0ef41Sopenharmony_ci    }
10121cb0ef41Sopenharmony_ci
10131cb0ef41Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
10141cb0ef41Sopenharmony_ci    checkTransitionRules(status);
10151cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
10161cb0ef41Sopenharmony_ci        return false;
10171cb0ef41Sopenharmony_ci    }
10181cb0ef41Sopenharmony_ci
10191cb0ef41Sopenharmony_ci    UDate firstTransitionTime = firstTransition->getTime();
10201cb0ef41Sopenharmony_ci    if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
10211cb0ef41Sopenharmony_ci        return false;
10221cb0ef41Sopenharmony_ci    }
10231cb0ef41Sopenharmony_ci    UDate stdDate, dstDate;
10241cb0ef41Sopenharmony_ci    UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
10251cb0ef41Sopenharmony_ci    UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
10261cb0ef41Sopenharmony_ci    if (stdAvail && (!dstAvail || stdDate > dstDate)) {
10271cb0ef41Sopenharmony_ci        result.setTime(stdDate);
10281cb0ef41Sopenharmony_ci        result.setFrom(*dstRule);
10291cb0ef41Sopenharmony_ci        result.setTo(*stdRule);
10301cb0ef41Sopenharmony_ci        return true;
10311cb0ef41Sopenharmony_ci    }
10321cb0ef41Sopenharmony_ci    if (dstAvail && (!stdAvail || dstDate > stdDate)) {
10331cb0ef41Sopenharmony_ci        result.setTime(dstDate);
10341cb0ef41Sopenharmony_ci        result.setFrom(*stdRule);
10351cb0ef41Sopenharmony_ci        result.setTo(*dstRule);
10361cb0ef41Sopenharmony_ci        return true;
10371cb0ef41Sopenharmony_ci    }
10381cb0ef41Sopenharmony_ci    return false;
10391cb0ef41Sopenharmony_ci}
10401cb0ef41Sopenharmony_ci
10411cb0ef41Sopenharmony_civoid
10421cb0ef41Sopenharmony_ciSimpleTimeZone::clearTransitionRules() {
10431cb0ef41Sopenharmony_ci    initialRule = nullptr;
10441cb0ef41Sopenharmony_ci    firstTransition = nullptr;
10451cb0ef41Sopenharmony_ci    stdRule = nullptr;
10461cb0ef41Sopenharmony_ci    dstRule = nullptr;
10471cb0ef41Sopenharmony_ci    transitionRulesInitialized = false;
10481cb0ef41Sopenharmony_ci}
10491cb0ef41Sopenharmony_ci
10501cb0ef41Sopenharmony_civoid
10511cb0ef41Sopenharmony_ciSimpleTimeZone::deleteTransitionRules() {
10521cb0ef41Sopenharmony_ci    if (initialRule != nullptr) {
10531cb0ef41Sopenharmony_ci        delete initialRule;
10541cb0ef41Sopenharmony_ci    }
10551cb0ef41Sopenharmony_ci    if (firstTransition != nullptr) {
10561cb0ef41Sopenharmony_ci        delete firstTransition;
10571cb0ef41Sopenharmony_ci    }
10581cb0ef41Sopenharmony_ci    if (stdRule != nullptr) {
10591cb0ef41Sopenharmony_ci        delete stdRule;
10601cb0ef41Sopenharmony_ci    }
10611cb0ef41Sopenharmony_ci    if (dstRule != nullptr) {
10621cb0ef41Sopenharmony_ci        delete dstRule;
10631cb0ef41Sopenharmony_ci    }
10641cb0ef41Sopenharmony_ci    clearTransitionRules();
10651cb0ef41Sopenharmony_ci }
10661cb0ef41Sopenharmony_ci
10671cb0ef41Sopenharmony_ci/*
10681cb0ef41Sopenharmony_ci * Lazy transition rules initializer
10691cb0ef41Sopenharmony_ci *
10701cb0ef41Sopenharmony_ci *    Note On the removal of UMTX_CHECK from checkTransitionRules():
10711cb0ef41Sopenharmony_ci *
10721cb0ef41Sopenharmony_ci *         It would be faster to have a UInitOnce as part of a SimpleTimeZone object,
10731cb0ef41Sopenharmony_ci *         which would avoid needing to lock a mutex to check the initialization state.
10741cb0ef41Sopenharmony_ci *         But we can't easily because simpletz.h is a public header, and including
10751cb0ef41Sopenharmony_ci *         a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers.
10761cb0ef41Sopenharmony_ci *
10771cb0ef41Sopenharmony_ci *         Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object,
10781cb0ef41Sopenharmony_ci *         allocate it in the constructors. This would be a more intrusive change, but doable
10791cb0ef41Sopenharmony_ci *         if performance turns out to be an issue.
10801cb0ef41Sopenharmony_ci */
10811cb0ef41Sopenharmony_ci
10821cb0ef41Sopenharmony_civoid
10831cb0ef41Sopenharmony_ciSimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
10841cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
10851cb0ef41Sopenharmony_ci        return;
10861cb0ef41Sopenharmony_ci    }
10871cb0ef41Sopenharmony_ci    static UMutex gLock;
10881cb0ef41Sopenharmony_ci    umtx_lock(&gLock);
10891cb0ef41Sopenharmony_ci    if (!transitionRulesInitialized) {
10901cb0ef41Sopenharmony_ci        SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
10911cb0ef41Sopenharmony_ci        ncThis->initTransitionRules(status);
10921cb0ef41Sopenharmony_ci    }
10931cb0ef41Sopenharmony_ci    umtx_unlock(&gLock);
10941cb0ef41Sopenharmony_ci}
10951cb0ef41Sopenharmony_ci
10961cb0ef41Sopenharmony_civoid
10971cb0ef41Sopenharmony_ciSimpleTimeZone::initTransitionRules(UErrorCode& status) {
10981cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
10991cb0ef41Sopenharmony_ci        return;
11001cb0ef41Sopenharmony_ci    }
11011cb0ef41Sopenharmony_ci    if (transitionRulesInitialized) {
11021cb0ef41Sopenharmony_ci        return;
11031cb0ef41Sopenharmony_ci    }
11041cb0ef41Sopenharmony_ci    deleteTransitionRules();
11051cb0ef41Sopenharmony_ci    UnicodeString tzid;
11061cb0ef41Sopenharmony_ci    getID(tzid);
11071cb0ef41Sopenharmony_ci
11081cb0ef41Sopenharmony_ci    if (useDaylight) {
11091cb0ef41Sopenharmony_ci        DateTimeRule* dtRule;
11101cb0ef41Sopenharmony_ci        DateTimeRule::TimeRuleType timeRuleType;
11111cb0ef41Sopenharmony_ci        UDate firstStdStart, firstDstStart;
11121cb0ef41Sopenharmony_ci
11131cb0ef41Sopenharmony_ci        // Create a TimeZoneRule for daylight saving time
11141cb0ef41Sopenharmony_ci        timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
11151cb0ef41Sopenharmony_ci            ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
11161cb0ef41Sopenharmony_ci        switch (startMode) {
11171cb0ef41Sopenharmony_ci        case DOM_MODE:
11181cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
11191cb0ef41Sopenharmony_ci            break;
11201cb0ef41Sopenharmony_ci        case DOW_IN_MONTH_MODE:
11211cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);
11221cb0ef41Sopenharmony_ci            break;
11231cb0ef41Sopenharmony_ci        case DOW_GE_DOM_MODE:
11241cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);
11251cb0ef41Sopenharmony_ci            break;
11261cb0ef41Sopenharmony_ci        case DOW_LE_DOM_MODE:
11271cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);
11281cb0ef41Sopenharmony_ci            break;
11291cb0ef41Sopenharmony_ci        default:
11301cb0ef41Sopenharmony_ci            status = U_INVALID_STATE_ERROR;
11311cb0ef41Sopenharmony_ci            return;
11321cb0ef41Sopenharmony_ci        }
11331cb0ef41Sopenharmony_ci        // Check for Null pointer
11341cb0ef41Sopenharmony_ci        if (dtRule == nullptr) {
11351cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
11361cb0ef41Sopenharmony_ci            return;
11371cb0ef41Sopenharmony_ci        }
11381cb0ef41Sopenharmony_ci        // For now, use ID + "(DST)" as the name
11391cb0ef41Sopenharmony_ci        dstRule = new AnnualTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
11401cb0ef41Sopenharmony_ci            dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
11411cb0ef41Sopenharmony_ci
11421cb0ef41Sopenharmony_ci        // Check for Null pointer
11431cb0ef41Sopenharmony_ci        if (dstRule == nullptr) {
11441cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
11451cb0ef41Sopenharmony_ci            deleteTransitionRules();
11461cb0ef41Sopenharmony_ci            return;
11471cb0ef41Sopenharmony_ci        }
11481cb0ef41Sopenharmony_ci
11491cb0ef41Sopenharmony_ci        // Calculate the first DST start time
11501cb0ef41Sopenharmony_ci        dstRule->getFirstStart(getRawOffset(), 0, firstDstStart);
11511cb0ef41Sopenharmony_ci
11521cb0ef41Sopenharmony_ci        // Create a TimeZoneRule for standard time
11531cb0ef41Sopenharmony_ci        timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
11541cb0ef41Sopenharmony_ci            ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
11551cb0ef41Sopenharmony_ci        switch (endMode) {
11561cb0ef41Sopenharmony_ci        case DOM_MODE:
11571cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
11581cb0ef41Sopenharmony_ci            break;
11591cb0ef41Sopenharmony_ci        case DOW_IN_MONTH_MODE:
11601cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
11611cb0ef41Sopenharmony_ci            break;
11621cb0ef41Sopenharmony_ci        case DOW_GE_DOM_MODE:
11631cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);
11641cb0ef41Sopenharmony_ci            break;
11651cb0ef41Sopenharmony_ci        case DOW_LE_DOM_MODE:
11661cb0ef41Sopenharmony_ci            dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);
11671cb0ef41Sopenharmony_ci            break;
11681cb0ef41Sopenharmony_ci        }
11691cb0ef41Sopenharmony_ci
11701cb0ef41Sopenharmony_ci        // Check for Null pointer
11711cb0ef41Sopenharmony_ci        if (dtRule == nullptr) {
11721cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
11731cb0ef41Sopenharmony_ci            deleteTransitionRules();
11741cb0ef41Sopenharmony_ci            return;
11751cb0ef41Sopenharmony_ci        }
11761cb0ef41Sopenharmony_ci        // For now, use ID + "(STD)" as the name
11771cb0ef41Sopenharmony_ci        stdRule = new AnnualTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0,
11781cb0ef41Sopenharmony_ci            dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
11791cb0ef41Sopenharmony_ci
11801cb0ef41Sopenharmony_ci        //Check for Null pointer
11811cb0ef41Sopenharmony_ci        if (stdRule == nullptr) {
11821cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
11831cb0ef41Sopenharmony_ci            deleteTransitionRules();
11841cb0ef41Sopenharmony_ci            return;
11851cb0ef41Sopenharmony_ci        }
11861cb0ef41Sopenharmony_ci
11871cb0ef41Sopenharmony_ci        // Calculate the first STD start time
11881cb0ef41Sopenharmony_ci        stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstStdStart);
11891cb0ef41Sopenharmony_ci
11901cb0ef41Sopenharmony_ci        // Create a TimeZoneRule for initial time
11911cb0ef41Sopenharmony_ci        if (firstStdStart < firstDstStart) {
11921cb0ef41Sopenharmony_ci            initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
11931cb0ef41Sopenharmony_ci            if (initialRule == nullptr) {
11941cb0ef41Sopenharmony_ci                status = U_MEMORY_ALLOCATION_ERROR;
11951cb0ef41Sopenharmony_ci                deleteTransitionRules();
11961cb0ef41Sopenharmony_ci                return;
11971cb0ef41Sopenharmony_ci            }
11981cb0ef41Sopenharmony_ci            firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
11991cb0ef41Sopenharmony_ci        } else {
12001cb0ef41Sopenharmony_ci            initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
12011cb0ef41Sopenharmony_ci            if (initialRule == nullptr) {
12021cb0ef41Sopenharmony_ci                status = U_MEMORY_ALLOCATION_ERROR;
12031cb0ef41Sopenharmony_ci                deleteTransitionRules();
12041cb0ef41Sopenharmony_ci                return;
12051cb0ef41Sopenharmony_ci            }
12061cb0ef41Sopenharmony_ci            firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
12071cb0ef41Sopenharmony_ci        }
12081cb0ef41Sopenharmony_ci        if (firstTransition == nullptr) {
12091cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
12101cb0ef41Sopenharmony_ci            deleteTransitionRules();
12111cb0ef41Sopenharmony_ci            return;
12121cb0ef41Sopenharmony_ci        }
12131cb0ef41Sopenharmony_ci
12141cb0ef41Sopenharmony_ci    } else {
12151cb0ef41Sopenharmony_ci        // Create a TimeZoneRule for initial time
12161cb0ef41Sopenharmony_ci        initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
12171cb0ef41Sopenharmony_ci        // Check for null pointer.
12181cb0ef41Sopenharmony_ci        if (initialRule == nullptr) {
12191cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
12201cb0ef41Sopenharmony_ci            deleteTransitionRules();
12211cb0ef41Sopenharmony_ci            return;
12221cb0ef41Sopenharmony_ci        }
12231cb0ef41Sopenharmony_ci    }
12241cb0ef41Sopenharmony_ci
12251cb0ef41Sopenharmony_ci    transitionRulesInitialized = true;
12261cb0ef41Sopenharmony_ci}
12271cb0ef41Sopenharmony_ci
12281cb0ef41Sopenharmony_ciint32_t
12291cb0ef41Sopenharmony_ciSimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
12301cb0ef41Sopenharmony_ci    return (useDaylight) ? 2 : 0;
12311cb0ef41Sopenharmony_ci}
12321cb0ef41Sopenharmony_ci
12331cb0ef41Sopenharmony_civoid
12341cb0ef41Sopenharmony_ciSimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
12351cb0ef41Sopenharmony_ci                                 const TimeZoneRule* trsrules[],
12361cb0ef41Sopenharmony_ci                                 int32_t& trscount,
12371cb0ef41Sopenharmony_ci                                 UErrorCode& status) const {
12381cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
12391cb0ef41Sopenharmony_ci        return;
12401cb0ef41Sopenharmony_ci    }
12411cb0ef41Sopenharmony_ci    checkTransitionRules(status);
12421cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) {
12431cb0ef41Sopenharmony_ci        return;
12441cb0ef41Sopenharmony_ci    }
12451cb0ef41Sopenharmony_ci    initial = initialRule;
12461cb0ef41Sopenharmony_ci    int32_t cnt = 0;
12471cb0ef41Sopenharmony_ci    if (stdRule != nullptr) {
12481cb0ef41Sopenharmony_ci        if (cnt < trscount) {
12491cb0ef41Sopenharmony_ci            trsrules[cnt++] = stdRule;
12501cb0ef41Sopenharmony_ci        }
12511cb0ef41Sopenharmony_ci        if (cnt < trscount) {
12521cb0ef41Sopenharmony_ci            trsrules[cnt++] = dstRule;
12531cb0ef41Sopenharmony_ci        }
12541cb0ef41Sopenharmony_ci    }
12551cb0ef41Sopenharmony_ci    trscount = cnt;
12561cb0ef41Sopenharmony_ci}
12571cb0ef41Sopenharmony_ci
12581cb0ef41Sopenharmony_ci
12591cb0ef41Sopenharmony_ciU_NAMESPACE_END
12601cb0ef41Sopenharmony_ci
12611cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
12621cb0ef41Sopenharmony_ci
12631cb0ef41Sopenharmony_ci//eof
1264