simpletz.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. *******************************************************************************
  5. * Copyright (C) 1997-2013, International Business Machines Corporation and
  6. * others. All Rights Reserved.
  7. *******************************************************************************
  8. *
  9. * File SIMPLETZ.H
  10. *
  11. * Modification History:
  12. *
  13. * Date Name Description
  14. * 12/05/96 clhuang Creation.
  15. * 04/21/97 aliu Fixed miscellaneous bugs found by inspection and
  16. * testing.
  17. * 07/29/97 aliu Ported source bodies back from Java version with
  18. * numerous feature enhancements and bug fixes.
  19. * 08/10/98 stephen JDK 1.2 sync.
  20. * 09/17/98 stephen Fixed getOffset() for last hour of year and DST
  21. * 12/02/99 aliu Added TimeMode and constructor and setStart/EndRule
  22. * methods that take TimeMode. Whitespace cleanup.
  23. ********************************************************************************
  24. */
  25. #include "utypeinfo.h" // for 'typeid' to work
  26. #include "unicode/utypes.h"
  27. #if !UCONFIG_NO_FORMATTING
  28. #include "unicode/simpletz.h"
  29. #include "unicode/gregocal.h"
  30. #include "unicode/smpdtfmt.h"
  31. #include "cmemory.h"
  32. #include "gregoimp.h"
  33. #include "umutex.h"
  34. U_NAMESPACE_BEGIN
  35. UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleTimeZone)
  36. // Use only for decodeStartRule() and decodeEndRule() where the year is not
  37. // available. Set February to 29 days to accommodate rules with that date
  38. // and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).
  39. // The compareToRule() method adjusts to February 28 in non-leap years.
  40. //
  41. // For actual getOffset() calculations, use Grego::monthLength() and
  42. // Grego::previousMonthLength() which take leap years into account.
  43. // We handle leap years assuming always
  44. // Gregorian, since we know they didn't have daylight time when
  45. // Gregorian calendar started.
  46. const int8_t SimpleTimeZone::STATICMONTHLENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
  47. static const char16_t DST_STR[] = {0x0028,0x0044,0x0053,0x0054,0x0029,0}; // "(DST)"
  48. static const char16_t STD_STR[] = {0x0028,0x0053,0x0054,0x0044,0x0029,0}; // "(STD)"
  49. // *****************************************************************************
  50. // class SimpleTimeZone
  51. // *****************************************************************************
  52. SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID)
  53. : BasicTimeZone(ID),
  54. startMonth(0),
  55. startDay(0),
  56. startDayOfWeek(0),
  57. startTime(0),
  58. startTimeMode(WALL_TIME),
  59. endTimeMode(WALL_TIME),
  60. endMonth(0),
  61. endDay(0),
  62. endDayOfWeek(0),
  63. endTime(0),
  64. startYear(0),
  65. rawOffset(rawOffsetGMT),
  66. useDaylight(false),
  67. startMode(DOM_MODE),
  68. endMode(DOM_MODE),
  69. dstSavings(U_MILLIS_PER_HOUR)
  70. {
  71. clearTransitionRules();
  72. }
  73. // -------------------------------------
  74. SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
  75. int8_t savingsStartMonth, int8_t savingsStartDay,
  76. int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
  77. int8_t savingsEndMonth, int8_t savingsEndDay,
  78. int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
  79. UErrorCode& status)
  80. : BasicTimeZone(ID)
  81. {
  82. clearTransitionRules();
  83. construct(rawOffsetGMT,
  84. savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
  85. savingsStartTime, WALL_TIME,
  86. savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
  87. savingsEndTime, WALL_TIME,
  88. U_MILLIS_PER_HOUR, status);
  89. }
  90. // -------------------------------------
  91. SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
  92. int8_t savingsStartMonth, int8_t savingsStartDay,
  93. int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
  94. int8_t savingsEndMonth, int8_t savingsEndDay,
  95. int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
  96. int32_t savingsDST, UErrorCode& status)
  97. : BasicTimeZone(ID)
  98. {
  99. clearTransitionRules();
  100. construct(rawOffsetGMT,
  101. savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
  102. savingsStartTime, WALL_TIME,
  103. savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
  104. savingsEndTime, WALL_TIME,
  105. savingsDST, status);
  106. }
  107. // -------------------------------------
  108. SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
  109. int8_t savingsStartMonth, int8_t savingsStartDay,
  110. int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
  111. TimeMode savingsStartTimeMode,
  112. int8_t savingsEndMonth, int8_t savingsEndDay,
  113. int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
  114. TimeMode savingsEndTimeMode,
  115. int32_t savingsDST, UErrorCode& status)
  116. : BasicTimeZone(ID)
  117. {
  118. clearTransitionRules();
  119. construct(rawOffsetGMT,
  120. savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
  121. savingsStartTime, savingsStartTimeMode,
  122. savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
  123. savingsEndTime, savingsEndTimeMode,
  124. savingsDST, status);
  125. }
  126. /**
  127. * Internal construction method.
  128. */
  129. void SimpleTimeZone::construct(int32_t rawOffsetGMT,
  130. int8_t savingsStartMonth,
  131. int8_t savingsStartDay,
  132. int8_t savingsStartDayOfWeek,
  133. int32_t savingsStartTime,
  134. TimeMode savingsStartTimeMode,
  135. int8_t savingsEndMonth,
  136. int8_t savingsEndDay,
  137. int8_t savingsEndDayOfWeek,
  138. int32_t savingsEndTime,
  139. TimeMode savingsEndTimeMode,
  140. int32_t savingsDST,
  141. UErrorCode& status)
  142. {
  143. this->rawOffset = rawOffsetGMT;
  144. this->startMonth = savingsStartMonth;
  145. this->startDay = savingsStartDay;
  146. this->startDayOfWeek = savingsStartDayOfWeek;
  147. this->startTime = savingsStartTime;
  148. this->startTimeMode = savingsStartTimeMode;
  149. this->endMonth = savingsEndMonth;
  150. this->endDay = savingsEndDay;
  151. this->endDayOfWeek = savingsEndDayOfWeek;
  152. this->endTime = savingsEndTime;
  153. this->endTimeMode = savingsEndTimeMode;
  154. this->dstSavings = savingsDST;
  155. this->startYear = 0;
  156. this->startMode = DOM_MODE;
  157. this->endMode = DOM_MODE;
  158. decodeRules(status);
  159. if (savingsDST == 0) {
  160. status = U_ILLEGAL_ARGUMENT_ERROR;
  161. }
  162. }
  163. // -------------------------------------
  164. SimpleTimeZone::~SimpleTimeZone()
  165. {
  166. deleteTransitionRules();
  167. }
  168. // -------------------------------------
  169. // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
  170. SimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source)
  171. : BasicTimeZone(source)
  172. {
  173. *this = source;
  174. }
  175. // -------------------------------------
  176. // Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
  177. SimpleTimeZone &
  178. SimpleTimeZone::operator=(const SimpleTimeZone &right)
  179. {
  180. if (this != &right)
  181. {
  182. TimeZone::operator=(right);
  183. rawOffset = right.rawOffset;
  184. startMonth = right.startMonth;
  185. startDay = right.startDay;
  186. startDayOfWeek = right.startDayOfWeek;
  187. startTime = right.startTime;
  188. startTimeMode = right.startTimeMode;
  189. startMode = right.startMode;
  190. endMonth = right.endMonth;
  191. endDay = right.endDay;
  192. endDayOfWeek = right.endDayOfWeek;
  193. endTime = right.endTime;
  194. endTimeMode = right.endTimeMode;
  195. endMode = right.endMode;
  196. startYear = right.startYear;
  197. dstSavings = right.dstSavings;
  198. useDaylight = right.useDaylight;
  199. clearTransitionRules();
  200. }
  201. return *this;
  202. }
  203. // -------------------------------------
  204. bool
  205. SimpleTimeZone::operator==(const TimeZone& that) const
  206. {
  207. return ((this == &that) ||
  208. (typeid(*this) == typeid(that) &&
  209. TimeZone::operator==(that) &&
  210. hasSameRules(that)));
  211. }
  212. // -------------------------------------
  213. // Called by TimeZone::createDefault() inside a Mutex - be careful.
  214. SimpleTimeZone*
  215. SimpleTimeZone::clone() const
  216. {
  217. return new SimpleTimeZone(*this);
  218. }
  219. // -------------------------------------
  220. /**
  221. * Sets the daylight savings starting year, that is, the year this time zone began
  222. * observing its specified daylight savings time rules. The time zone is considered
  223. * not to observe daylight savings time prior to that year; SimpleTimeZone doesn't
  224. * support historical daylight-savings-time rules.
  225. * @param year the daylight savings starting year.
  226. */
  227. void
  228. SimpleTimeZone::setStartYear(int32_t year)
  229. {
  230. startYear = year;
  231. transitionRulesInitialized = false;
  232. }
  233. // -------------------------------------
  234. /**
  235. * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
  236. * Time starts at the first Sunday in April, at 2 AM in standard time.
  237. * Therefore, you can set the start rule by calling:
  238. * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
  239. * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
  240. * the exact starting date. Their exact meaning depend on their respective signs,
  241. * allowing various types of rules to be constructed, as follows:<ul>
  242. * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
  243. * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
  244. * of the month).
  245. * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
  246. * the day of week in the month counting backward from the end of the month.
  247. * (e.g., (-1, MONDAY) is the last Monday in the month)
  248. * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
  249. * specifies the day of the month, regardless of what day of the week it is.
  250. * (e.g., (10, 0) is the tenth day of the month)
  251. * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
  252. * specifies the day of the month counting backward from the end of the
  253. * month, regardless of what day of the week it is (e.g., (-2, 0) is the
  254. * next-to-last day of the month).
  255. * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
  256. * first specified day of the week on or after the specified day of the month.
  257. * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
  258. * [or the 15th itself if the 15th is a Sunday].)
  259. * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
  260. * last specified day of the week on or before the specified day of the month.
  261. * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
  262. * [or the 20th itself if the 20th is a Tuesday].)</ul>
  263. * @param month the daylight savings starting month. Month is 0-based.
  264. * eg, 0 for January.
  265. * @param dayOfWeekInMonth the daylight savings starting
  266. * day-of-week-in-month. Please see the member description for an example.
  267. * @param dayOfWeek the daylight savings starting day-of-week. Please see
  268. * the member description for an example.
  269. * @param time the daylight savings starting time. Please see the member
  270. * description for an example.
  271. */
  272. void
  273. SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
  274. int32_t time, TimeMode mode, UErrorCode& status)
  275. {
  276. startMonth = (int8_t)month;
  277. startDay = (int8_t)dayOfWeekInMonth;
  278. startDayOfWeek = (int8_t)dayOfWeek;
  279. startTime = time;
  280. startTimeMode = mode;
  281. decodeStartRule(status);
  282. transitionRulesInitialized = false;
  283. }
  284. // -------------------------------------
  285. void
  286. SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
  287. int32_t time, TimeMode mode, UErrorCode& status)
  288. {
  289. setStartRule(month, dayOfMonth, 0, time, mode, status);
  290. }
  291. // -------------------------------------
  292. void
  293. SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
  294. int32_t time, TimeMode mode, UBool after, UErrorCode& status)
  295. {
  296. setStartRule(month, after ? dayOfMonth : -dayOfMonth,
  297. -dayOfWeek, time, mode, status);
  298. }
  299. // -------------------------------------
  300. /**
  301. * Sets the daylight savings ending rule. For example, in the U.S., Daylight
  302. * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
  303. * Therefore, you can set the end rule by calling:
  304. * setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
  305. * Various other types of rules can be specified by manipulating the dayOfWeek
  306. * and dayOfWeekInMonth parameters. For complete details, see the documentation
  307. * for setStartRule().
  308. * @param month the daylight savings ending month. Month is 0-based.
  309. * eg, 0 for January.
  310. * @param dayOfWeekInMonth the daylight savings ending
  311. * day-of-week-in-month. See setStartRule() for a complete explanation.
  312. * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
  313. * for a complete explanation.
  314. * @param time the daylight savings ending time. Please see the member
  315. * description for an example.
  316. */
  317. void
  318. SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
  319. int32_t time, TimeMode mode, UErrorCode& status)
  320. {
  321. endMonth = (int8_t)month;
  322. endDay = (int8_t)dayOfWeekInMonth;
  323. endDayOfWeek = (int8_t)dayOfWeek;
  324. endTime = time;
  325. endTimeMode = mode;
  326. decodeEndRule(status);
  327. transitionRulesInitialized = false;
  328. }
  329. // -------------------------------------
  330. void
  331. SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
  332. int32_t time, TimeMode mode, UErrorCode& status)
  333. {
  334. setEndRule(month, dayOfMonth, 0, time, mode, status);
  335. }
  336. // -------------------------------------
  337. void
  338. SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
  339. int32_t time, TimeMode mode, UBool after, UErrorCode& status)
  340. {
  341. setEndRule(month, after ? dayOfMonth : -dayOfMonth,
  342. -dayOfWeek, time, mode, status);
  343. }
  344. // -------------------------------------
  345. int32_t
  346. SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
  347. uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const
  348. {
  349. // Check the month before calling Grego::monthLength(). This
  350. // duplicates the test that occurs in the 7-argument getOffset(),
  351. // however, this is unavoidable. We don't mind because this method, in
  352. // fact, should not be called; internal code should always call the
  353. // 7-argument getOffset(), and outside code should use Calendar.get(int
  354. // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
  355. // this method because it's public API. - liu 8/10/98
  356. if(month < UCAL_JANUARY || month > UCAL_DECEMBER) {
  357. status = U_ILLEGAL_ARGUMENT_ERROR;
  358. return 0;
  359. }
  360. return getOffset(era, year, month, day, dayOfWeek, millis, Grego::monthLength(year, month), status);
  361. }
  362. int32_t
  363. SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
  364. uint8_t dayOfWeek, int32_t millis,
  365. int32_t /*monthLength*/, UErrorCode& status) const
  366. {
  367. // Check the month before calling Grego::monthLength(). This
  368. // duplicates a test that occurs in the 9-argument getOffset(),
  369. // however, this is unavoidable. We don't mind because this method, in
  370. // fact, should not be called; internal code should always call the
  371. // 9-argument getOffset(), and outside code should use Calendar.get(int
  372. // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
  373. // this method because it's public API. - liu 8/10/98
  374. if (month < UCAL_JANUARY
  375. || month > UCAL_DECEMBER) {
  376. status = U_ILLEGAL_ARGUMENT_ERROR;
  377. return -1;
  378. }
  379. // We ignore monthLength because it can be derived from year and month.
  380. // This is so that February in leap years is calculated correctly.
  381. // We keep this argument in this function for backwards compatibility.
  382. return getOffset(era, year, month, day, dayOfWeek, millis,
  383. Grego::monthLength(year, month),
  384. Grego::previousMonthLength(year, month),
  385. status);
  386. }
  387. int32_t
  388. SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
  389. uint8_t dayOfWeek, int32_t millis,
  390. int32_t monthLength, int32_t prevMonthLength,
  391. UErrorCode& status) const
  392. {
  393. if(U_FAILURE(status)) return 0;
  394. if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
  395. || month < UCAL_JANUARY
  396. || month > UCAL_DECEMBER
  397. || day < 1
  398. || day > monthLength
  399. || dayOfWeek < UCAL_SUNDAY
  400. || dayOfWeek > UCAL_SATURDAY
  401. || millis < 0
  402. || millis >= U_MILLIS_PER_DAY
  403. || monthLength < 28
  404. || monthLength > 31
  405. || prevMonthLength < 28
  406. || prevMonthLength > 31) {
  407. status = U_ILLEGAL_ARGUMENT_ERROR;
  408. return -1;
  409. }
  410. int32_t result = rawOffset;
  411. // Bail out if we are before the onset of daylight savings time
  412. if(!useDaylight || year < startYear || era != GregorianCalendar::AD)
  413. return result;
  414. // Check for southern hemisphere. We assume that the start and end
  415. // month are different.
  416. UBool southern = (startMonth > endMonth);
  417. // Compare the date to the starting and ending rules.+1 = date>rule, -1
  418. // = date<rule, 0 = date==rule.
  419. int32_t startCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
  420. (int8_t)day, (int8_t)dayOfWeek, millis,
  421. startTimeMode == UTC_TIME ? -rawOffset : 0,
  422. startMode, (int8_t)startMonth, (int8_t)startDayOfWeek,
  423. (int8_t)startDay, startTime);
  424. int32_t endCompare = 0;
  425. /* We don't always have to compute endCompare. For many instances,
  426. * startCompare is enough to determine if we are in DST or not. In the
  427. * northern hemisphere, if we are before the start rule, we can't have
  428. * DST. In the southern hemisphere, if we are after the start rule, we
  429. * must have DST. This is reflected in the way the next if statement
  430. * (not the one immediately following) short circuits. */
  431. if(southern != (startCompare >= 0)) {
  432. endCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
  433. (int8_t)day, (int8_t)dayOfWeek, millis,
  434. endTimeMode == WALL_TIME ? dstSavings :
  435. (endTimeMode == UTC_TIME ? -rawOffset : 0),
  436. endMode, (int8_t)endMonth, (int8_t)endDayOfWeek,
  437. (int8_t)endDay, endTime);
  438. }
  439. // Check for both the northern and southern hemisphere cases. We
  440. // assume that in the northern hemisphere, the start rule is before the
  441. // end rule within the calendar year, and vice versa for the southern
  442. // hemisphere.
  443. if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
  444. (southern && (startCompare >= 0 || endCompare < 0)))
  445. result += dstSavings;
  446. return result;
  447. }
  448. void
  449. SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingTimeOpt,
  450. UTimeZoneLocalOption duplicatedTimeOpt, int32_t& rawOffsetGMT,
  451. int32_t& savingsDST, UErrorCode& status) const
  452. {
  453. if (U_FAILURE(status)) {
  454. return;
  455. }
  456. rawOffsetGMT = getRawOffset();
  457. int32_t year, month, dom, dow, millis;
  458. int32_t day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
  459. Grego::dayToFields(day, year, month, dom, dow);
  460. savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
  461. (uint8_t) dow, millis,
  462. Grego::monthLength(year, month),
  463. status) - rawOffsetGMT;
  464. if (U_FAILURE(status)) {
  465. return;
  466. }
  467. UBool recalc = false;
  468. // Now we need some adjustment
  469. if (savingsDST > 0) {
  470. if ((nonExistingTimeOpt & kStdDstMask) == kStandard
  471. || ((nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter)) {
  472. date -= getDSTSavings();
  473. recalc = true;
  474. }
  475. } else {
  476. if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
  477. || ((duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer)) {
  478. date -= getDSTSavings();
  479. recalc = true;
  480. }
  481. }
  482. if (recalc) {
  483. day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
  484. Grego::dayToFields(day, year, month, dom, dow);
  485. savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
  486. (uint8_t) dow, millis,
  487. Grego::monthLength(year, month),
  488. status) - rawOffsetGMT;
  489. }
  490. }
  491. // -------------------------------------
  492. /**
  493. * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
  494. * on whether the date is after, equal to, or before the rule date. The
  495. * millis are compared directly against the ruleMillis, so any
  496. * standard-daylight adjustments must be handled by the caller.
  497. *
  498. * @return 1 if the date is after the rule date, -1 if the date is before
  499. * the rule date, or 0 if the date is equal to the rule date.
  500. */
  501. int32_t
  502. SimpleTimeZone::compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
  503. int8_t dayOfMonth,
  504. int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
  505. EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
  506. int8_t ruleDay, int32_t ruleMillis)
  507. {
  508. // Make adjustments for startTimeMode and endTimeMode
  509. millis += millisDelta;
  510. while (millis >= U_MILLIS_PER_DAY) {
  511. millis -= U_MILLIS_PER_DAY;
  512. ++dayOfMonth;
  513. dayOfWeek = (int8_t)(1 + (dayOfWeek % 7)); // dayOfWeek is one-based
  514. if (dayOfMonth > monthLen) {
  515. dayOfMonth = 1;
  516. /* When incrementing the month, it is desirable to overflow
  517. * from DECEMBER to DECEMBER+1, since we use the result to
  518. * compare against a real month. Wraparound of the value
  519. * leads to bug 4173604. */
  520. ++month;
  521. }
  522. }
  523. while (millis < 0) {
  524. millis += U_MILLIS_PER_DAY;
  525. --dayOfMonth;
  526. dayOfWeek = (int8_t)(1 + ((dayOfWeek+5) % 7)); // dayOfWeek is one-based
  527. if (dayOfMonth < 1) {
  528. dayOfMonth = prevMonthLen;
  529. --month;
  530. }
  531. }
  532. // first compare months. If they're different, we don't have to worry about days
  533. // and times
  534. if (month < ruleMonth) return -1;
  535. else if (month > ruleMonth) return 1;
  536. // calculate the actual day of month for the rule
  537. int32_t ruleDayOfMonth = 0;
  538. // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.
  539. if (ruleDay > monthLen) {
  540. ruleDay = monthLen;
  541. }
  542. switch (ruleMode)
  543. {
  544. // if the mode is day-of-month, the day of month is given
  545. case DOM_MODE:
  546. ruleDayOfMonth = ruleDay;
  547. break;
  548. // if the mode is day-of-week-in-month, calculate the day-of-month from it
  549. case DOW_IN_MONTH_MODE:
  550. // In this case ruleDay is the day-of-week-in-month (this code is using
  551. // the dayOfWeek and dayOfMonth parameters to figure out the day-of-week
  552. // of the first day of the month, so it's trusting that they're really
  553. // consistent with each other)
  554. if (ruleDay > 0)
  555. ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
  556. (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
  557. // if ruleDay is negative (we assume it's not zero here), we have to do
  558. // the same calculation figuring backward from the last day of the month.
  559. else
  560. {
  561. // (again, this code is trusting that dayOfWeek and dayOfMonth are
  562. // consistent with each other here, since we're using them to figure
  563. // the day of week of the first of the month)
  564. ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
  565. (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
  566. }
  567. break;
  568. case DOW_GE_DOM_MODE:
  569. ruleDayOfMonth = ruleDay +
  570. (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
  571. break;
  572. case DOW_LE_DOM_MODE:
  573. ruleDayOfMonth = ruleDay -
  574. (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
  575. // Note at this point ruleDayOfMonth may be <1, although it will
  576. // be >=1 for well-formed rules.
  577. break;
  578. }
  579. // now that we have a real day-in-month for the rule, we can compare days...
  580. if (dayOfMonth < ruleDayOfMonth) return -1;
  581. else if (dayOfMonth > ruleDayOfMonth) return 1;
  582. // ...and if they're equal, we compare times
  583. if (millis < ruleMillis) return -1;
  584. else if (millis > ruleMillis) return 1;
  585. else return 0;
  586. }
  587. // -------------------------------------
  588. int32_t
  589. SimpleTimeZone::getRawOffset() const
  590. {
  591. return rawOffset;
  592. }
  593. // -------------------------------------
  594. void
  595. SimpleTimeZone::setRawOffset(int32_t offsetMillis)
  596. {
  597. rawOffset = offsetMillis;
  598. transitionRulesInitialized = false;
  599. }
  600. // -------------------------------------
  601. void
  602. SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
  603. {
  604. if (millisSavedDuringDST == 0) {
  605. status = U_ILLEGAL_ARGUMENT_ERROR;
  606. }
  607. else {
  608. dstSavings = millisSavedDuringDST;
  609. }
  610. transitionRulesInitialized = false;
  611. }
  612. // -------------------------------------
  613. int32_t
  614. SimpleTimeZone::getDSTSavings() const
  615. {
  616. return dstSavings;
  617. }
  618. // -------------------------------------
  619. UBool
  620. SimpleTimeZone::useDaylightTime() const
  621. {
  622. return useDaylight;
  623. }
  624. // -------------------------------------
  625. /**
  626. * Overrides TimeZone
  627. * Queries if the given date is in Daylight Savings Time.
  628. */
  629. UBool SimpleTimeZone::inDaylightTime(UDate date, UErrorCode& status) const
  630. {
  631. // This method is wasteful since it creates a new GregorianCalendar and
  632. // deletes it each time it is called. However, this is a deprecated method
  633. // and provided only for Java compatibility as of 8/6/97 [LIU].
  634. if (U_FAILURE(status)) return false;
  635. GregorianCalendar *gc = new GregorianCalendar(*this, status);
  636. /* test for nullptr */
  637. if (gc == 0) {
  638. status = U_MEMORY_ALLOCATION_ERROR;
  639. return false;
  640. }
  641. gc->setTime(date, status);
  642. UBool result = gc->inDaylightTime(status);
  643. delete gc;
  644. return result;
  645. }
  646. // -------------------------------------
  647. /**
  648. * Return true if this zone has the same rules and offset as another zone.
  649. * @param other the TimeZone object to be compared with
  650. * @return true if the given zone has the same rules and offset as this one
  651. */
  652. UBool
  653. SimpleTimeZone::hasSameRules(const TimeZone& other) const
  654. {
  655. if (this == &other) return true;
  656. if (typeid(*this) != typeid(other)) return false;
  657. SimpleTimeZone *that = (SimpleTimeZone*)&other;
  658. return rawOffset == that->rawOffset &&
  659. useDaylight == that->useDaylight &&
  660. (!useDaylight
  661. // Only check rules if using DST
  662. || (dstSavings == that->dstSavings &&
  663. startMode == that->startMode &&
  664. startMonth == that->startMonth &&
  665. startDay == that->startDay &&
  666. startDayOfWeek == that->startDayOfWeek &&
  667. startTime == that->startTime &&
  668. startTimeMode == that->startTimeMode &&
  669. endMode == that->endMode &&
  670. endMonth == that->endMonth &&
  671. endDay == that->endDay &&
  672. endDayOfWeek == that->endDayOfWeek &&
  673. endTime == that->endTime &&
  674. endTimeMode == that->endTimeMode &&
  675. startYear == that->startYear));
  676. }
  677. // -------------------------------------
  678. //----------------------------------------------------------------------
  679. // Rule representation
  680. //
  681. // We represent the following flavors of rules:
  682. // 5 the fifth of the month
  683. // lastSun the last Sunday in the month
  684. // lastMon the last Monday in the month
  685. // Sun>=8 first Sunday on or after the eighth
  686. // Sun<=25 last Sunday on or before the 25th
  687. // This is further complicated by the fact that we need to remain
  688. // backward compatible with the 1.1 FCS. Finally, we need to minimize
  689. // API changes. In order to satisfy these requirements, we support
  690. // three representation systems, and we translate between them.
  691. //
  692. // INTERNAL REPRESENTATION
  693. // This is the format SimpleTimeZone objects take after construction or
  694. // streaming in is complete. Rules are represented directly, using an
  695. // unencoded format. We will discuss the start rule only below; the end
  696. // rule is analogous.
  697. // startMode Takes on enumerated values DAY_OF_MONTH,
  698. // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
  699. // startDay The day of the month, or for DOW_IN_MONTH mode, a
  700. // value indicating which DOW, such as +1 for first,
  701. // +2 for second, -1 for last, etc.
  702. // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
  703. //
  704. // ENCODED REPRESENTATION
  705. // This is the format accepted by the constructor and by setStartRule()
  706. // and setEndRule(). It uses various combinations of positive, negative,
  707. // and zero values to encode the different rules. This representation
  708. // allows us to specify all the different rule flavors without altering
  709. // the API.
  710. // MODE startMonth startDay startDayOfWeek
  711. // DOW_IN_MONTH_MODE >=0 !=0 >0
  712. // DOM_MODE >=0 >0 ==0
  713. // DOW_GE_DOM_MODE >=0 >0 <0
  714. // DOW_LE_DOM_MODE >=0 <0 <0
  715. // (no DST) don't care ==0 don't care
  716. //
  717. // STREAMED REPRESENTATION
  718. // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
  719. // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
  720. // flag useDaylight. When we stream an object out, we translate into an
  721. // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
  722. // and used by 1.1 code. Following that, we write out the full
  723. // representation separately so that contemporary code can recognize and
  724. // parse it. The full representation is written in a "packed" format,
  725. // consisting of a version number, a length, and an array of bytes. Future
  726. // versions of this class may specify different versions. If they wish to
  727. // include additional data, they should do so by storing them after the
  728. // packed representation below.
  729. //----------------------------------------------------------------------
  730. /**
  731. * Given a set of encoded rules in startDay and startDayOfMonth, decode
  732. * them and set the startMode appropriately. Do the same for endDay and
  733. * endDayOfMonth. Upon entry, the day of week variables may be zero or
  734. * negative, in order to indicate special modes. The day of month
  735. * variables may also be negative. Upon exit, the mode variables will be
  736. * set, and the day of week and day of month variables will be positive.
  737. * This method also recognizes a startDay or endDay of zero as indicating
  738. * no DST.
  739. */
  740. void
  741. SimpleTimeZone::decodeRules(UErrorCode& status)
  742. {
  743. decodeStartRule(status);
  744. decodeEndRule(status);
  745. }
  746. /**
  747. * Decode the start rule and validate the parameters. The parameters are
  748. * expected to be in encoded form, which represents the various rule modes
  749. * by negating or zeroing certain values. Representation formats are:
  750. * <p>
  751. * <pre>
  752. * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
  753. * ------------ ----- -------- -------- ----------
  754. * month 0..11 same same same don't care
  755. * day -5..5 1..31 1..31 -1..-31 0
  756. * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
  757. * time 0..ONEDAY same same same don't care
  758. * </pre>
  759. * The range for month does not include UNDECIMBER since this class is
  760. * really specific to GregorianCalendar, which does not use that month.
  761. * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
  762. * end rule is an exclusive limit point. That is, the range of times that
  763. * are in DST include those >= the start and < the end. For this reason,
  764. * it should be possible to specify an end of ONEDAY in order to include the
  765. * entire day. Although this is equivalent to time 0 of the following day,
  766. * it's not always possible to specify that, for example, on December 31.
  767. * While arguably the start range should still be 0..ONEDAY-1, we keep
  768. * the start and end ranges the same for consistency.
  769. */
  770. void
  771. SimpleTimeZone::decodeStartRule(UErrorCode& status)
  772. {
  773. if(U_FAILURE(status)) return;
  774. useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
  775. if (useDaylight && dstSavings == 0) {
  776. dstSavings = U_MILLIS_PER_HOUR;
  777. }
  778. if (startDay != 0) {
  779. if (startMonth < UCAL_JANUARY || startMonth > UCAL_DECEMBER) {
  780. status = U_ILLEGAL_ARGUMENT_ERROR;
  781. return;
  782. }
  783. if (startTime < 0 || startTime > U_MILLIS_PER_DAY ||
  784. startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {
  785. status = U_ILLEGAL_ARGUMENT_ERROR;
  786. return;
  787. }
  788. if (startDayOfWeek == 0) {
  789. startMode = DOM_MODE;
  790. } else {
  791. if (startDayOfWeek > 0) {
  792. startMode = DOW_IN_MONTH_MODE;
  793. } else {
  794. startDayOfWeek = (int8_t)-startDayOfWeek;
  795. if (startDay > 0) {
  796. startMode = DOW_GE_DOM_MODE;
  797. } else {
  798. startDay = (int8_t)-startDay;
  799. startMode = DOW_LE_DOM_MODE;
  800. }
  801. }
  802. if (startDayOfWeek > UCAL_SATURDAY) {
  803. status = U_ILLEGAL_ARGUMENT_ERROR;
  804. return;
  805. }
  806. }
  807. if (startMode == DOW_IN_MONTH_MODE) {
  808. if (startDay < -5 || startDay > 5) {
  809. status = U_ILLEGAL_ARGUMENT_ERROR;
  810. return;
  811. }
  812. } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) {
  813. status = U_ILLEGAL_ARGUMENT_ERROR;
  814. return;
  815. }
  816. }
  817. }
  818. /**
  819. * Decode the end rule and validate the parameters. This method is exactly
  820. * analogous to decodeStartRule().
  821. * @see decodeStartRule
  822. */
  823. void
  824. SimpleTimeZone::decodeEndRule(UErrorCode& status)
  825. {
  826. if(U_FAILURE(status)) return;
  827. useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? true : false);
  828. if (useDaylight && dstSavings == 0) {
  829. dstSavings = U_MILLIS_PER_HOUR;
  830. }
  831. if (endDay != 0) {
  832. if (endMonth < UCAL_JANUARY || endMonth > UCAL_DECEMBER) {
  833. status = U_ILLEGAL_ARGUMENT_ERROR;
  834. return;
  835. }
  836. if (endTime < 0 || endTime > U_MILLIS_PER_DAY ||
  837. endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {
  838. status = U_ILLEGAL_ARGUMENT_ERROR;
  839. return;
  840. }
  841. if (endDayOfWeek == 0) {
  842. endMode = DOM_MODE;
  843. } else {
  844. if (endDayOfWeek > 0) {
  845. endMode = DOW_IN_MONTH_MODE;
  846. } else {
  847. endDayOfWeek = (int8_t)-endDayOfWeek;
  848. if (endDay > 0) {
  849. endMode = DOW_GE_DOM_MODE;
  850. } else {
  851. endDay = (int8_t)-endDay;
  852. endMode = DOW_LE_DOM_MODE;
  853. }
  854. }
  855. if (endDayOfWeek > UCAL_SATURDAY) {
  856. status = U_ILLEGAL_ARGUMENT_ERROR;
  857. return;
  858. }
  859. }
  860. if (endMode == DOW_IN_MONTH_MODE) {
  861. if (endDay < -5 || endDay > 5) {
  862. status = U_ILLEGAL_ARGUMENT_ERROR;
  863. return;
  864. }
  865. } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) {
  866. status = U_ILLEGAL_ARGUMENT_ERROR;
  867. return;
  868. }
  869. }
  870. }
  871. UBool
  872. SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
  873. if (!useDaylight) {
  874. return false;
  875. }
  876. UErrorCode status = U_ZERO_ERROR;
  877. checkTransitionRules(status);
  878. if (U_FAILURE(status)) {
  879. return false;
  880. }
  881. UDate firstTransitionTime = firstTransition->getTime();
  882. if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
  883. result = *firstTransition;
  884. }
  885. UDate stdDate, dstDate;
  886. UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
  887. UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
  888. if (stdAvail && (!dstAvail || stdDate < dstDate)) {
  889. result.setTime(stdDate);
  890. result.setFrom(*dstRule);
  891. result.setTo(*stdRule);
  892. return true;
  893. }
  894. if (dstAvail && (!stdAvail || dstDate < stdDate)) {
  895. result.setTime(dstDate);
  896. result.setFrom(*stdRule);
  897. result.setTo(*dstRule);
  898. return true;
  899. }
  900. return false;
  901. }
  902. UBool
  903. SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
  904. if (!useDaylight) {
  905. return false;
  906. }
  907. UErrorCode status = U_ZERO_ERROR;
  908. checkTransitionRules(status);
  909. if (U_FAILURE(status)) {
  910. return false;
  911. }
  912. UDate firstTransitionTime = firstTransition->getTime();
  913. if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
  914. return false;
  915. }
  916. UDate stdDate, dstDate;
  917. UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
  918. UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
  919. if (stdAvail && (!dstAvail || stdDate > dstDate)) {
  920. result.setTime(stdDate);
  921. result.setFrom(*dstRule);
  922. result.setTo(*stdRule);
  923. return true;
  924. }
  925. if (dstAvail && (!stdAvail || dstDate > stdDate)) {
  926. result.setTime(dstDate);
  927. result.setFrom(*stdRule);
  928. result.setTo(*dstRule);
  929. return true;
  930. }
  931. return false;
  932. }
  933. void
  934. SimpleTimeZone::clearTransitionRules() {
  935. initialRule = nullptr;
  936. firstTransition = nullptr;
  937. stdRule = nullptr;
  938. dstRule = nullptr;
  939. transitionRulesInitialized = false;
  940. }
  941. void
  942. SimpleTimeZone::deleteTransitionRules() {
  943. if (initialRule != nullptr) {
  944. delete initialRule;
  945. }
  946. if (firstTransition != nullptr) {
  947. delete firstTransition;
  948. }
  949. if (stdRule != nullptr) {
  950. delete stdRule;
  951. }
  952. if (dstRule != nullptr) {
  953. delete dstRule;
  954. }
  955. clearTransitionRules();
  956. }
  957. /*
  958. * Lazy transition rules initializer
  959. *
  960. * Note On the removal of UMTX_CHECK from checkTransitionRules():
  961. *
  962. * It would be faster to have a UInitOnce as part of a SimpleTimeZone object,
  963. * which would avoid needing to lock a mutex to check the initialization state.
  964. * But we can't easily because simpletz.h is a public header, and including
  965. * a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers.
  966. *
  967. * Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object,
  968. * allocate it in the constructors. This would be a more intrusive change, but doable
  969. * if performance turns out to be an issue.
  970. */
  971. void
  972. SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
  973. if (U_FAILURE(status)) {
  974. return;
  975. }
  976. static UMutex gLock;
  977. umtx_lock(&gLock);
  978. if (!transitionRulesInitialized) {
  979. SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
  980. ncThis->initTransitionRules(status);
  981. }
  982. umtx_unlock(&gLock);
  983. }
  984. void
  985. SimpleTimeZone::initTransitionRules(UErrorCode& status) {
  986. if (U_FAILURE(status)) {
  987. return;
  988. }
  989. if (transitionRulesInitialized) {
  990. return;
  991. }
  992. deleteTransitionRules();
  993. UnicodeString tzid;
  994. getID(tzid);
  995. if (useDaylight) {
  996. DateTimeRule* dtRule;
  997. DateTimeRule::TimeRuleType timeRuleType;
  998. UDate firstStdStart, firstDstStart;
  999. // Create a TimeZoneRule for daylight saving time
  1000. timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
  1001. ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
  1002. switch (startMode) {
  1003. case DOM_MODE:
  1004. dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
  1005. break;
  1006. case DOW_IN_MONTH_MODE:
  1007. dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);
  1008. break;
  1009. case DOW_GE_DOM_MODE:
  1010. dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);
  1011. break;
  1012. case DOW_LE_DOM_MODE:
  1013. dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);
  1014. break;
  1015. default:
  1016. status = U_INVALID_STATE_ERROR;
  1017. return;
  1018. }
  1019. // Check for Null pointer
  1020. if (dtRule == nullptr) {
  1021. status = U_MEMORY_ALLOCATION_ERROR;
  1022. return;
  1023. }
  1024. // For now, use ID + "(DST)" as the name
  1025. dstRule = new AnnualTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
  1026. dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
  1027. // Check for Null pointer
  1028. if (dstRule == nullptr) {
  1029. status = U_MEMORY_ALLOCATION_ERROR;
  1030. deleteTransitionRules();
  1031. return;
  1032. }
  1033. // Calculate the first DST start time
  1034. dstRule->getFirstStart(getRawOffset(), 0, firstDstStart);
  1035. // Create a TimeZoneRule for standard time
  1036. timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
  1037. ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
  1038. switch (endMode) {
  1039. case DOM_MODE:
  1040. dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
  1041. break;
  1042. case DOW_IN_MONTH_MODE:
  1043. dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
  1044. break;
  1045. case DOW_GE_DOM_MODE:
  1046. dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);
  1047. break;
  1048. case DOW_LE_DOM_MODE:
  1049. dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);
  1050. break;
  1051. }
  1052. // Check for Null pointer
  1053. if (dtRule == nullptr) {
  1054. status = U_MEMORY_ALLOCATION_ERROR;
  1055. deleteTransitionRules();
  1056. return;
  1057. }
  1058. // For now, use ID + "(STD)" as the name
  1059. stdRule = new AnnualTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0,
  1060. dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
  1061. //Check for Null pointer
  1062. if (stdRule == nullptr) {
  1063. status = U_MEMORY_ALLOCATION_ERROR;
  1064. deleteTransitionRules();
  1065. return;
  1066. }
  1067. // Calculate the first STD start time
  1068. stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstStdStart);
  1069. // Create a TimeZoneRule for initial time
  1070. if (firstStdStart < firstDstStart) {
  1071. initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
  1072. if (initialRule == nullptr) {
  1073. status = U_MEMORY_ALLOCATION_ERROR;
  1074. deleteTransitionRules();
  1075. return;
  1076. }
  1077. firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
  1078. } else {
  1079. initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
  1080. if (initialRule == nullptr) {
  1081. status = U_MEMORY_ALLOCATION_ERROR;
  1082. deleteTransitionRules();
  1083. return;
  1084. }
  1085. firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
  1086. }
  1087. if (firstTransition == nullptr) {
  1088. status = U_MEMORY_ALLOCATION_ERROR;
  1089. deleteTransitionRules();
  1090. return;
  1091. }
  1092. } else {
  1093. // Create a TimeZoneRule for initial time
  1094. initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
  1095. // Check for null pointer.
  1096. if (initialRule == nullptr) {
  1097. status = U_MEMORY_ALLOCATION_ERROR;
  1098. deleteTransitionRules();
  1099. return;
  1100. }
  1101. }
  1102. transitionRulesInitialized = true;
  1103. }
  1104. int32_t
  1105. SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
  1106. return (useDaylight) ? 2 : 0;
  1107. }
  1108. void
  1109. SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
  1110. const TimeZoneRule* trsrules[],
  1111. int32_t& trscount,
  1112. UErrorCode& status) const {
  1113. if (U_FAILURE(status)) {
  1114. return;
  1115. }
  1116. checkTransitionRules(status);
  1117. if (U_FAILURE(status)) {
  1118. return;
  1119. }
  1120. initial = initialRule;
  1121. int32_t cnt = 0;
  1122. if (stdRule != nullptr) {
  1123. if (cnt < trscount) {
  1124. trsrules[cnt++] = stdRule;
  1125. }
  1126. if (cnt < trscount) {
  1127. trsrules[cnt++] = dstRule;
  1128. }
  1129. }
  1130. trscount = cnt;
  1131. }
  1132. U_NAMESPACE_END
  1133. #endif /* #if !UCONFIG_NO_FORMATTING */
  1134. //eof