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