basictz.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright (C) 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. *******************************************************************************
  5. * Copyright (C) 2007-2013, International Business Machines Corporation and
  6. * others. All Rights Reserved.
  7. *******************************************************************************
  8. */
  9. #include "unicode/utypes.h"
  10. #if !UCONFIG_NO_FORMATTING
  11. #include "unicode/basictz.h"
  12. #include "gregoimp.h"
  13. #include "uvector.h"
  14. #include "cmemory.h"
  15. U_NAMESPACE_BEGIN
  16. #define MILLIS_PER_YEAR (365*24*60*60*1000.0)
  17. BasicTimeZone::BasicTimeZone()
  18. : TimeZone() {
  19. }
  20. BasicTimeZone::BasicTimeZone(const UnicodeString &id)
  21. : TimeZone(id) {
  22. }
  23. BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
  24. : TimeZone(source) {
  25. }
  26. BasicTimeZone::~BasicTimeZone() {
  27. }
  28. UBool
  29. BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end,
  30. UBool ignoreDstAmount, UErrorCode& status) const {
  31. if (U_FAILURE(status)) {
  32. return FALSE;
  33. }
  34. if (hasSameRules(tz)) {
  35. return TRUE;
  36. }
  37. // Check the offsets at the start time
  38. int32_t raw1, raw2, dst1, dst2;
  39. getOffset(start, FALSE, raw1, dst1, status);
  40. if (U_FAILURE(status)) {
  41. return FALSE;
  42. }
  43. tz.getOffset(start, FALSE, raw2, dst2, status);
  44. if (U_FAILURE(status)) {
  45. return FALSE;
  46. }
  47. if (ignoreDstAmount) {
  48. if ((raw1 + dst1 != raw2 + dst2)
  49. || (dst1 != 0 && dst2 == 0)
  50. || (dst1 == 0 && dst2 != 0)) {
  51. return FALSE;
  52. }
  53. } else {
  54. if (raw1 != raw2 || dst1 != dst2) {
  55. return FALSE;
  56. }
  57. }
  58. // Check transitions in the range
  59. UDate time = start;
  60. TimeZoneTransition tr1, tr2;
  61. while (TRUE) {
  62. UBool avail1 = getNextTransition(time, FALSE, tr1);
  63. UBool avail2 = tz.getNextTransition(time, FALSE, tr2);
  64. if (ignoreDstAmount) {
  65. // Skip a transition which only differ the amount of DST savings
  66. while (TRUE) {
  67. if (avail1
  68. && tr1.getTime() <= end
  69. && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
  70. == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
  71. && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
  72. getNextTransition(tr1.getTime(), FALSE, tr1);
  73. } else {
  74. break;
  75. }
  76. }
  77. while (TRUE) {
  78. if (avail2
  79. && tr2.getTime() <= end
  80. && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
  81. == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
  82. && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
  83. tz.getNextTransition(tr2.getTime(), FALSE, tr2);
  84. } else {
  85. break;
  86. }
  87. }
  88. }
  89. UBool inRange1 = (avail1 && tr1.getTime() <= end);
  90. UBool inRange2 = (avail2 && tr2.getTime() <= end);
  91. if (!inRange1 && !inRange2) {
  92. // No more transition in the range
  93. break;
  94. }
  95. if (!inRange1 || !inRange2) {
  96. return FALSE;
  97. }
  98. if (tr1.getTime() != tr2.getTime()) {
  99. return FALSE;
  100. }
  101. if (ignoreDstAmount) {
  102. if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
  103. != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
  104. || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0)
  105. || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) {
  106. return FALSE;
  107. }
  108. } else {
  109. if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
  110. tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
  111. return FALSE;
  112. }
  113. }
  114. time = tr1.getTime();
  115. }
  116. return TRUE;
  117. }
  118. void
  119. BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
  120. AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const {
  121. initial = NULL;
  122. std = NULL;
  123. dst = NULL;
  124. if (U_FAILURE(status)) {
  125. return;
  126. }
  127. int32_t initialRaw, initialDst;
  128. UnicodeString initialName;
  129. AnnualTimeZoneRule *ar1 = NULL;
  130. AnnualTimeZoneRule *ar2 = NULL;
  131. UnicodeString name;
  132. UBool avail;
  133. TimeZoneTransition tr;
  134. // Get the next transition
  135. avail = getNextTransition(date, FALSE, tr);
  136. if (avail) {
  137. tr.getFrom()->getName(initialName);
  138. initialRaw = tr.getFrom()->getRawOffset();
  139. initialDst = tr.getFrom()->getDSTSavings();
  140. // Check if the next transition is either DST->STD or STD->DST and
  141. // within roughly 1 year from the specified date
  142. UDate nextTransitionTime = tr.getTime();
  143. if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
  144. || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
  145. && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
  146. int32_t year, month, dom, dow, doy, mid;
  147. UDate d;
  148. // Get local wall time for the next transition time
  149. Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
  150. year, month, dom, dow, doy, mid);
  151. int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
  152. // Create DOW rule
  153. DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
  154. tr.getTo()->getName(name);
  155. // Note: SimpleTimeZone does not support raw offset change.
  156. // So we always use raw offset of the given time for the rule,
  157. // even raw offset is changed. This will result that the result
  158. // zone to return wrong offset after the transition.
  159. // When we encounter such case, we do not inspect next next
  160. // transition for another rule.
  161. ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
  162. dtr, year, AnnualTimeZoneRule::MAX_YEAR);
  163. if (tr.getTo()->getRawOffset() == initialRaw) {
  164. // Get the next next transition
  165. avail = getNextTransition(nextTransitionTime, FALSE, tr);
  166. if (avail) {
  167. // Check if the next next transition is either DST->STD or STD->DST
  168. // and within roughly 1 year from the next transition
  169. if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
  170. || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
  171. && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
  172. // Get local wall time for the next transition time
  173. Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
  174. year, month, dom, dow, doy, mid);
  175. weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
  176. // Generate another DOW rule
  177. dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
  178. tr.getTo()->getName(name);
  179. ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
  180. dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
  181. // Make sure this rule can be applied to the specified date
  182. avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d);
  183. if (!avail || d > date
  184. || initialRaw != tr.getTo()->getRawOffset()
  185. || initialDst != tr.getTo()->getDSTSavings()) {
  186. // We cannot use this rule as the second transition rule
  187. delete ar2;
  188. ar2 = NULL;
  189. }
  190. }
  191. }
  192. }
  193. if (ar2 == NULL) {
  194. // Try previous transition
  195. avail = getPreviousTransition(date, TRUE, tr);
  196. if (avail) {
  197. // Check if the previous transition is either DST->STD or STD->DST.
  198. // The actual transition time does not matter here.
  199. if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
  200. || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
  201. // Generate another DOW rule
  202. Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
  203. year, month, dom, dow, doy, mid);
  204. weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
  205. dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
  206. tr.getTo()->getName(name);
  207. // second rule raw/dst offsets should match raw/dst offsets
  208. // at the given time
  209. ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
  210. dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
  211. // Check if this rule start after the first rule after the specified date
  212. avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d);
  213. if (!avail || d <= nextTransitionTime) {
  214. // We cannot use this rule as the second transition rule
  215. delete ar2;
  216. ar2 = NULL;
  217. }
  218. }
  219. }
  220. }
  221. if (ar2 == NULL) {
  222. // Cannot find a good pair of AnnualTimeZoneRule
  223. delete ar1;
  224. ar1 = NULL;
  225. } else {
  226. // The initial rule should represent the rule before the previous transition
  227. ar1->getName(initialName);
  228. initialRaw = ar1->getRawOffset();
  229. initialDst = ar1->getDSTSavings();
  230. }
  231. }
  232. }
  233. else {
  234. // Try the previous one
  235. avail = getPreviousTransition(date, TRUE, tr);
  236. if (avail) {
  237. tr.getTo()->getName(initialName);
  238. initialRaw = tr.getTo()->getRawOffset();
  239. initialDst = tr.getTo()->getDSTSavings();
  240. } else {
  241. // No transitions in the past. Just use the current offsets
  242. getOffset(date, FALSE, initialRaw, initialDst, status);
  243. if (U_FAILURE(status)) {
  244. return;
  245. }
  246. }
  247. }
  248. // Set the initial rule
  249. initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
  250. // Set the standard and daylight saving rules
  251. if (ar1 != NULL && ar2 != NULL) {
  252. if (ar1->getDSTSavings() != 0) {
  253. dst = ar1;
  254. std = ar2;
  255. } else {
  256. std = ar1;
  257. dst = ar2;
  258. }
  259. }
  260. }
  261. void
  262. BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
  263. UVector*& transitionRules, UErrorCode& status) const {
  264. if (U_FAILURE(status)) {
  265. return;
  266. }
  267. const InitialTimeZoneRule *orgini;
  268. const TimeZoneRule **orgtrs = NULL;
  269. TimeZoneTransition tzt;
  270. UBool avail;
  271. UVector *orgRules = NULL;
  272. int32_t ruleCount;
  273. TimeZoneRule *r = NULL;
  274. UBool *done = NULL;
  275. InitialTimeZoneRule *res_initial = NULL;
  276. UVector *filteredRules = NULL;
  277. UnicodeString name;
  278. int32_t i;
  279. UDate time, t;
  280. UDate *newTimes = NULL;
  281. UDate firstStart;
  282. UBool bFinalStd = FALSE, bFinalDst = FALSE;
  283. // Original transition rules
  284. ruleCount = countTransitionRules(status);
  285. if (U_FAILURE(status)) {
  286. return;
  287. }
  288. orgRules = new UVector(ruleCount, status);
  289. if (U_FAILURE(status)) {
  290. return;
  291. }
  292. orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount);
  293. if (orgtrs == NULL) {
  294. status = U_MEMORY_ALLOCATION_ERROR;
  295. goto error;
  296. }
  297. getTimeZoneRules(orgini, orgtrs, ruleCount, status);
  298. if (U_FAILURE(status)) {
  299. goto error;
  300. }
  301. for (i = 0; i < ruleCount; i++) {
  302. orgRules->addElement(orgtrs[i]->clone(), status);
  303. if (U_FAILURE(status)) {
  304. goto error;
  305. }
  306. }
  307. uprv_free(orgtrs);
  308. orgtrs = NULL;
  309. avail = getPreviousTransition(start, TRUE, tzt);
  310. if (!avail) {
  311. // No need to filter out rules only applicable to time before the start
  312. initial = orgini->clone();
  313. transitionRules = orgRules;
  314. return;
  315. }
  316. done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount);
  317. if (done == NULL) {
  318. status = U_MEMORY_ALLOCATION_ERROR;
  319. goto error;
  320. }
  321. filteredRules = new UVector(status);
  322. if (U_FAILURE(status)) {
  323. goto error;
  324. }
  325. // Create initial rule
  326. tzt.getTo()->getName(name);
  327. res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(),
  328. tzt.getTo()->getDSTSavings());
  329. // Mark rules which does not need to be processed
  330. for (i = 0; i < ruleCount; i++) {
  331. r = (TimeZoneRule*)orgRules->elementAt(i);
  332. avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time);
  333. done[i] = !avail;
  334. }
  335. time = start;
  336. while (!bFinalStd || !bFinalDst) {
  337. avail = getNextTransition(time, FALSE, tzt);
  338. if (!avail) {
  339. break;
  340. }
  341. UDate updatedTime = tzt.getTime();
  342. if (updatedTime == time) {
  343. // Can get here if rules for start & end of daylight time have exactly
  344. // the same time.
  345. // TODO: fix getNextTransition() to prevent it?
  346. status = U_INVALID_STATE_ERROR;
  347. goto error;
  348. }
  349. time = updatedTime;
  350. const TimeZoneRule *toRule = tzt.getTo();
  351. for (i = 0; i < ruleCount; i++) {
  352. r = (TimeZoneRule*)orgRules->elementAt(i);
  353. if (*r == *toRule) {
  354. break;
  355. }
  356. }
  357. if (i >= ruleCount) {
  358. // This case should never happen
  359. status = U_INVALID_STATE_ERROR;
  360. goto error;
  361. }
  362. if (done[i]) {
  363. continue;
  364. }
  365. const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
  366. const AnnualTimeZoneRule *ar;
  367. if (tar != NULL) {
  368. // Get the previous raw offset and DST savings before the very first start time
  369. TimeZoneTransition tzt0;
  370. t = start;
  371. while (TRUE) {
  372. avail = getNextTransition(t, FALSE, tzt0);
  373. if (!avail) {
  374. break;
  375. }
  376. if (*(tzt0.getTo()) == *tar) {
  377. break;
  378. }
  379. t = tzt0.getTime();
  380. }
  381. if (avail) {
  382. // Check if the entire start times to be added
  383. tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
  384. if (firstStart > start) {
  385. // Just add the rule as is
  386. filteredRules->addElement(tar->clone(), status);
  387. if (U_FAILURE(status)) {
  388. goto error;
  389. }
  390. } else {
  391. // Colllect transitions after the start time
  392. int32_t startTimes;
  393. DateTimeRule::TimeRuleType timeType;
  394. int32_t idx;
  395. startTimes = tar->countStartTimes();
  396. timeType = tar->getTimeType();
  397. for (idx = 0; idx < startTimes; idx++) {
  398. tar->getStartTimeAt(idx, t);
  399. if (timeType == DateTimeRule::STANDARD_TIME) {
  400. t -= tzt.getFrom()->getRawOffset();
  401. }
  402. if (timeType == DateTimeRule::WALL_TIME) {
  403. t -= tzt.getFrom()->getDSTSavings();
  404. }
  405. if (t > start) {
  406. break;
  407. }
  408. }
  409. int32_t asize = startTimes - idx;
  410. if (asize > 0) {
  411. newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize);
  412. if (newTimes == NULL) {
  413. status = U_MEMORY_ALLOCATION_ERROR;
  414. goto error;
  415. }
  416. for (int32_t newidx = 0; newidx < asize; newidx++) {
  417. tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
  418. if (U_FAILURE(status)) {
  419. uprv_free(newTimes);
  420. newTimes = NULL;
  421. goto error;
  422. }
  423. }
  424. tar->getName(name);
  425. TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name,
  426. tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType);
  427. uprv_free(newTimes);
  428. filteredRules->addElement(newTar, status);
  429. if (U_FAILURE(status)) {
  430. goto error;
  431. }
  432. }
  433. }
  434. }
  435. } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) {
  436. ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
  437. if (firstStart == tzt.getTime()) {
  438. // Just add the rule as is
  439. filteredRules->addElement(ar->clone(), status);
  440. if (U_FAILURE(status)) {
  441. goto error;
  442. }
  443. } else {
  444. // Calculate the transition year
  445. int32_t year, month, dom, dow, doy, mid;
  446. Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
  447. // Re-create the rule
  448. ar->getName(name);
  449. AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
  450. *(ar->getRule()), year, ar->getEndYear());
  451. filteredRules->addElement(newAr, status);
  452. if (U_FAILURE(status)) {
  453. goto error;
  454. }
  455. }
  456. // check if this is a final rule
  457. if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
  458. // After bot final standard and dst rules are processed,
  459. // exit this while loop.
  460. if (ar->getDSTSavings() == 0) {
  461. bFinalStd = TRUE;
  462. } else {
  463. bFinalDst = TRUE;
  464. }
  465. }
  466. }
  467. done[i] = TRUE;
  468. }
  469. // Set the results
  470. if (orgRules != NULL) {
  471. while (!orgRules->isEmpty()) {
  472. r = (TimeZoneRule*)orgRules->orphanElementAt(0);
  473. delete r;
  474. }
  475. delete orgRules;
  476. }
  477. if (done != NULL) {
  478. uprv_free(done);
  479. }
  480. initial = res_initial;
  481. transitionRules = filteredRules;
  482. return;
  483. error:
  484. if (orgtrs != NULL) {
  485. uprv_free(orgtrs);
  486. }
  487. if (orgRules != NULL) {
  488. while (!orgRules->isEmpty()) {
  489. r = (TimeZoneRule*)orgRules->orphanElementAt(0);
  490. delete r;
  491. }
  492. delete orgRules;
  493. }
  494. if (done != NULL) {
  495. if (filteredRules != NULL) {
  496. while (!filteredRules->isEmpty()) {
  497. r = (TimeZoneRule*)filteredRules->orphanElementAt(0);
  498. delete r;
  499. }
  500. delete filteredRules;
  501. }
  502. delete res_initial;
  503. uprv_free(done);
  504. }
  505. initial = NULL;
  506. transitionRules = NULL;
  507. }
  508. void
  509. BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/,
  510. int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const {
  511. if (U_FAILURE(status)) {
  512. return;
  513. }
  514. status = U_UNSUPPORTED_ERROR;
  515. }
  516. U_NAMESPACE_END
  517. #endif /* #if !UCONFIG_NO_FORMATTING */
  518. //eof