timezone.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  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-2016, International Business Machines Corporation and
  6. * others. All Rights Reserved.
  7. *******************************************************************************
  8. *
  9. * File TIMEZONE.CPP
  10. *
  11. * Modification History:
  12. *
  13. * Date Name Description
  14. * 12/05/96 clhuang Creation.
  15. * 04/21/97 aliu General clean-up and bug fixing.
  16. * 05/08/97 aliu Fixed Hashtable code per code review.
  17. * 07/09/97 helena Changed createInstance to createDefault.
  18. * 07/29/97 aliu Updated with all-new list of 96 UNIX-derived
  19. * TimeZones. Changed mechanism to load from static
  20. * array rather than resource bundle.
  21. * 07/07/1998 srl Bugfixes from the Java side: UTC GMT CAT NST
  22. * Added getDisplayName API
  23. * going to add custom parsing.
  24. *
  25. * ISSUES:
  26. * - should getDisplayName cache something?
  27. * - should custom time zones be cached? [probably]
  28. * 08/10/98 stephen Brought getDisplayName() API in-line w/ conventions
  29. * 08/19/98 stephen Changed createTimeZone() to never return 0
  30. * 09/02/98 stephen Added getOffset(monthLen) and hasSameRules()
  31. * 09/15/98 stephen Added getStaticClassID()
  32. * 02/22/99 stephen Removed character literals for EBCDIC safety
  33. * 05/04/99 stephen Changed initDefault() for Mutex issues
  34. * 07/12/99 helena HPUX 11 CC Port.
  35. * 12/03/99 aliu Moved data out of static table into icudata.dll.
  36. * Substantial rewrite of zone lookup, default zone, and
  37. * available IDs code. Misc. cleanup.
  38. *********************************************************************************/
  39. #include "utypeinfo.h" // for 'typeid' to work
  40. #include "unicode/utypes.h"
  41. #include "unicode/ustring.h"
  42. #include "uassert.h"
  43. #include "ustr_imp.h"
  44. #ifdef U_DEBUG_TZ
  45. # include <stdio.h>
  46. # include "uresimp.h" // for debugging
  47. static void debug_tz_loc(const char *f, int32_t l)
  48. {
  49. fprintf(stderr, "%s:%d: ", f, l);
  50. }
  51. static void debug_tz_msg(const char *pat, ...)
  52. {
  53. va_list ap;
  54. va_start(ap, pat);
  55. vfprintf(stderr, pat, ap);
  56. fflush(stderr);
  57. }
  58. static char gStrBuf[256];
  59. #define U_DEBUG_TZ_STR(x) u_austrncpy(gStrBuf,x,sizeof(gStrBuf)-1)
  60. // must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4));
  61. #define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
  62. #else
  63. #define U_DEBUG_TZ_MSG(x)
  64. #endif
  65. #if !UCONFIG_NO_FORMATTING
  66. #include "unicode/simpletz.h"
  67. #include "unicode/calendar.h"
  68. #include "unicode/gregocal.h"
  69. #include "unicode/ures.h"
  70. #include "unicode/tzfmt.h"
  71. #include "unicode/numfmt.h"
  72. #include "gregoimp.h"
  73. #include "uresimp.h" // struct UResourceBundle
  74. #include "olsontz.h"
  75. #include "mutex.h"
  76. #include "unicode/udata.h"
  77. #include "ucln_in.h"
  78. #include "cstring.h"
  79. #include "cmemory.h"
  80. #include "unicode/strenum.h"
  81. #include "uassert.h"
  82. #include "zonemeta.h"
  83. #define kZONEINFO "zoneinfo64"
  84. #define kREGIONS "Regions"
  85. #define kZONES "Zones"
  86. #define kRULES "Rules"
  87. #define kNAMES "Names"
  88. #define kTZVERSION "TZVersion"
  89. #define kLINKS "links"
  90. #define kMAX_CUSTOM_HOUR 23
  91. #define kMAX_CUSTOM_MIN 59
  92. #define kMAX_CUSTOM_SEC 59
  93. #define MINUS 0x002D
  94. #define PLUS 0x002B
  95. #define ZERO_DIGIT 0x0030
  96. #define COLON 0x003A
  97. // Static data and constants
  98. static const char16_t WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */
  99. static const char16_t GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
  100. static const char16_t UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00}; /* "Etc/Unknown" */
  101. static const int32_t GMT_ID_LENGTH = 3;
  102. static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11;
  103. static icu::TimeZone* DEFAULT_ZONE = nullptr;
  104. static icu::UInitOnce gDefaultZoneInitOnce {};
  105. alignas(icu::SimpleTimeZone)
  106. static char gRawGMT[sizeof(icu::SimpleTimeZone)];
  107. alignas(icu::SimpleTimeZone)
  108. static char gRawUNKNOWN[sizeof(icu::SimpleTimeZone)];
  109. static icu::UInitOnce gStaticZonesInitOnce {};
  110. static UBool gStaticZonesInitialized = false; // Whether the static zones are initialized and ready to use.
  111. static char TZDATA_VERSION[16];
  112. static icu::UInitOnce gTZDataVersionInitOnce {};
  113. static int32_t* MAP_SYSTEM_ZONES = nullptr;
  114. static int32_t* MAP_CANONICAL_SYSTEM_ZONES = nullptr;
  115. static int32_t* MAP_CANONICAL_SYSTEM_LOCATION_ZONES = nullptr;
  116. static int32_t LEN_SYSTEM_ZONES = 0;
  117. static int32_t LEN_CANONICAL_SYSTEM_ZONES = 0;
  118. static int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
  119. static icu::UInitOnce gSystemZonesInitOnce {};
  120. static icu::UInitOnce gCanonicalZonesInitOnce {};
  121. static icu::UInitOnce gCanonicalLocationZonesInitOnce {};
  122. U_CDECL_BEGIN
  123. static UBool U_CALLCONV timeZone_cleanup()
  124. {
  125. U_NAMESPACE_USE
  126. delete DEFAULT_ZONE;
  127. DEFAULT_ZONE = nullptr;
  128. gDefaultZoneInitOnce.reset();
  129. if (gStaticZonesInitialized) {
  130. reinterpret_cast<SimpleTimeZone*>(gRawGMT)->~SimpleTimeZone();
  131. reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN)->~SimpleTimeZone();
  132. gStaticZonesInitialized = false;
  133. gStaticZonesInitOnce.reset();
  134. }
  135. uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
  136. gTZDataVersionInitOnce.reset();
  137. LEN_SYSTEM_ZONES = 0;
  138. uprv_free(MAP_SYSTEM_ZONES);
  139. MAP_SYSTEM_ZONES = 0;
  140. gSystemZonesInitOnce.reset();
  141. LEN_CANONICAL_SYSTEM_ZONES = 0;
  142. uprv_free(MAP_CANONICAL_SYSTEM_ZONES);
  143. MAP_CANONICAL_SYSTEM_ZONES = 0;
  144. gCanonicalZonesInitOnce.reset();
  145. LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
  146. uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES);
  147. MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
  148. gCanonicalLocationZonesInitOnce.reset();
  149. return true;
  150. }
  151. U_CDECL_END
  152. U_NAMESPACE_BEGIN
  153. static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status)
  154. {
  155. UnicodeString copy;
  156. const char16_t *u;
  157. int32_t len;
  158. int32_t start = 0;
  159. int32_t limit = ures_getSize(array);
  160. int32_t mid;
  161. int32_t lastMid = INT32_MAX;
  162. if(U_FAILURE(status) || (limit < 1)) {
  163. return -1;
  164. }
  165. U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit));
  166. for (;;) {
  167. mid = (int32_t)((start + limit) / 2);
  168. if (lastMid == mid) { /* Have we moved? */
  169. break; /* We haven't moved, and it wasn't found. */
  170. }
  171. lastMid = mid;
  172. u = ures_getStringByIndex(array, mid, &len, &status);
  173. if (U_FAILURE(status)) {
  174. break;
  175. }
  176. U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit));
  177. copy.setTo(true, u, len);
  178. int r = id.compare(copy);
  179. if(r==0) {
  180. U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid));
  181. return mid;
  182. } else if(r<0) {
  183. limit = mid;
  184. } else {
  185. start = mid;
  186. }
  187. }
  188. U_DEBUG_TZ_MSG(("fisa: not found\n"));
  189. return -1;
  190. }
  191. /**
  192. * Fetch a specific zone by name. Replaces the getByKey call.
  193. * @param top Top timezone resource
  194. * @param id Time zone ID
  195. * @param oldbundle Bundle for reuse (or nullptr). see 'ures_open()'
  196. * @return the zone's bundle if found, or undefined if error. Reuses oldbundle.
  197. */
  198. static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) {
  199. // load the Rules object
  200. UResourceBundle *tmp = ures_getByKey(top, kNAMES, nullptr, &status);
  201. // search for the string
  202. int32_t idx = findInStringArray(tmp, id, status);
  203. if((idx == -1) && U_SUCCESS(status)) {
  204. // not found
  205. status = U_MISSING_RESOURCE_ERROR;
  206. //ures_close(oldbundle);
  207. //oldbundle = nullptr;
  208. } else {
  209. U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status)));
  210. tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top
  211. U_DEBUG_TZ_MSG(("gzbn: loaded ZONES, size %d, type %d, path %s %s\n", ures_getSize(tmp), ures_getType(tmp), ures_getPath(tmp), u_errorName(status)));
  212. oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object
  213. U_DEBUG_TZ_MSG(("gzbn: loaded z#%d, size %d, type %d, path %s, %s\n", idx, ures_getSize(oldbundle), ures_getType(oldbundle), ures_getPath(oldbundle), u_errorName(status)));
  214. }
  215. ures_close(tmp);
  216. if(U_FAILURE(status)) {
  217. //ures_close(oldbundle);
  218. return nullptr;
  219. } else {
  220. return oldbundle;
  221. }
  222. }
  223. UResourceBundle* TimeZone::loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode& status) {
  224. char key[64];
  225. ruleid.extract(0, sizeof(key)-1, key, (int32_t)sizeof(key)-1, US_INV);
  226. U_DEBUG_TZ_MSG(("loadRule(%s)\n", key));
  227. UResourceBundle *r = ures_getByKey(top, kRULES, oldbundle, &status);
  228. U_DEBUG_TZ_MSG(("loadRule(%s) -> kRULES [%s]\n", key, u_errorName(status)));
  229. r = ures_getByKey(r, key, r, &status);
  230. U_DEBUG_TZ_MSG(("loadRule(%s) -> item [%s]\n", key, u_errorName(status)));
  231. return r;
  232. }
  233. /**
  234. * Given an ID, open the appropriate resource for the given time zone.
  235. * Dereference aliases if necessary.
  236. * @param id zone id
  237. * @param res resource, which must be ready for use (initialized but not open)
  238. * @param ec input-output error code
  239. * @return top-level resource bundle
  240. */
  241. static UResourceBundle* openOlsonResource(const UnicodeString& id,
  242. UResourceBundle& res,
  243. UErrorCode& ec)
  244. {
  245. #ifdef U_DEBUG_TZ
  246. char buf[128];
  247. id.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
  248. #endif
  249. UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
  250. U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res)));
  251. /* &res = */ getZoneByName(top, id, &res, ec);
  252. // Dereference if this is an alias. Docs say result should be 1
  253. // but it is 0 in 2.8 (?).
  254. U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec)));
  255. if (ures_getType(&res) == URES_INT) {
  256. int32_t deref = ures_getInt(&res, &ec) + 0;
  257. U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res)));
  258. UResourceBundle *ares = ures_getByKey(top, kZONES, nullptr, &ec); // dereference Zones section
  259. ures_getByIndex(ares, deref, &res, &ec);
  260. ures_close(ares);
  261. U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec)));
  262. } else {
  263. U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res)));
  264. }
  265. U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec)));
  266. return top;
  267. }
  268. // -------------------------------------
  269. namespace {
  270. void U_CALLCONV initStaticTimeZones() {
  271. // Initialize _GMT independently of other static data; it should
  272. // be valid even if we can't load the time zone UDataMemory.
  273. ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
  274. // new can't fail below, as we use placement new into statically allocated space.
  275. new(gRawGMT) SimpleTimeZone(0, UnicodeString(true, GMT_ID, GMT_ID_LENGTH));
  276. new(gRawUNKNOWN) SimpleTimeZone(0, UnicodeString(true, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
  277. gStaticZonesInitialized = true;
  278. }
  279. } // anonymous namespace
  280. const TimeZone& U_EXPORT2
  281. TimeZone::getUnknown()
  282. {
  283. umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
  284. return *reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN);
  285. }
  286. const TimeZone* U_EXPORT2
  287. TimeZone::getGMT()
  288. {
  289. umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
  290. return reinterpret_cast<SimpleTimeZone*>(gRawGMT);
  291. }
  292. // *****************************************************************************
  293. // class TimeZone
  294. // *****************************************************************************
  295. UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(TimeZone)
  296. TimeZone::TimeZone()
  297. : UObject(), fID()
  298. {
  299. }
  300. // -------------------------------------
  301. TimeZone::TimeZone(const UnicodeString &id)
  302. : UObject(), fID(id)
  303. {
  304. }
  305. // -------------------------------------
  306. TimeZone::~TimeZone()
  307. {
  308. }
  309. // -------------------------------------
  310. TimeZone::TimeZone(const TimeZone &source)
  311. : UObject(source), fID(source.fID)
  312. {
  313. }
  314. // -------------------------------------
  315. TimeZone &
  316. TimeZone::operator=(const TimeZone &right)
  317. {
  318. if (this != &right) fID = right.fID;
  319. return *this;
  320. }
  321. // -------------------------------------
  322. bool
  323. TimeZone::operator==(const TimeZone& that) const
  324. {
  325. return typeid(*this) == typeid(that) &&
  326. fID == that.fID;
  327. }
  328. // -------------------------------------
  329. namespace {
  330. TimeZone*
  331. createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
  332. if (U_FAILURE(ec)) {
  333. return nullptr;
  334. }
  335. TimeZone* z = 0;
  336. StackUResourceBundle res;
  337. U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
  338. UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
  339. U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
  340. if (U_SUCCESS(ec)) {
  341. z = new OlsonTimeZone(top, res.getAlias(), id, ec);
  342. if (z == nullptr) {
  343. ec = U_MEMORY_ALLOCATION_ERROR;
  344. U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
  345. }
  346. }
  347. ures_close(top);
  348. if (U_FAILURE(ec)) {
  349. U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec)));
  350. delete z;
  351. z = nullptr;
  352. }
  353. return z;
  354. }
  355. /**
  356. * Lookup the given name in our system zone table. If found,
  357. * instantiate a new zone of that name and return it. If not
  358. * found, return 0.
  359. */
  360. TimeZone*
  361. createSystemTimeZone(const UnicodeString& id) {
  362. UErrorCode ec = U_ZERO_ERROR;
  363. return createSystemTimeZone(id, ec);
  364. }
  365. }
  366. TimeZone* U_EXPORT2
  367. TimeZone::createTimeZone(const UnicodeString& ID)
  368. {
  369. /* We first try to lookup the zone ID in our system list. If this
  370. * fails, we try to parse it as a custom string GMT[+-]hh:mm. If
  371. * all else fails, we return GMT, which is probably not what the
  372. * user wants, but at least is a functioning TimeZone object.
  373. *
  374. * We cannot return nullptr, because that would break compatibility
  375. * with the JDK.
  376. */
  377. TimeZone* result = createSystemTimeZone(ID);
  378. if (result == nullptr) {
  379. U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
  380. result = createCustomTimeZone(ID);
  381. }
  382. if (result == nullptr) {
  383. U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)"));
  384. const TimeZone& unknown = getUnknown();
  385. // Unknown zone uses statically allocated memory, so creation of it can never fail due to OOM.
  386. result = unknown.clone();
  387. }
  388. return result;
  389. }
  390. // -------------------------------------
  391. TimeZone* U_EXPORT2
  392. TimeZone::detectHostTimeZone()
  393. {
  394. // We access system timezone data through uprv_tzset(), uprv_tzname(), and others,
  395. // which have platform specific implementations in putil.cpp
  396. int32_t rawOffset = 0;
  397. const char *hostID;
  398. UBool hostDetectionSucceeded = true;
  399. // First, try to create a system timezone, based
  400. // on the string ID in tzname[0].
  401. uprv_tzset(); // Initialize tz... system data
  402. uprv_tzname_clear_cache();
  403. // Get the timezone ID from the host. This function should do
  404. // any required host-specific remapping; e.g., on Windows this
  405. // function maps the Windows Time Zone name to an ICU timezone ID.
  406. hostID = uprv_tzname(0);
  407. // Invert sign because UNIX semantics are backwards
  408. rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
  409. TimeZone* hostZone = nullptr;
  410. UnicodeString hostStrID(hostID, -1, US_INV);
  411. if (hostStrID.length() == 0) {
  412. // The host time zone detection (or remapping) above has failed and
  413. // we have no name at all. Fallback to using the Unknown zone.
  414. hostStrID = UnicodeString(true, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH);
  415. hostDetectionSucceeded = false;
  416. }
  417. hostZone = createSystemTimeZone(hostStrID);
  418. #if U_PLATFORM_USES_ONLY_WIN32_API
  419. // hostID points to a heap-allocated location on Windows.
  420. uprv_free(const_cast<char *>(hostID));
  421. #endif
  422. int32_t hostIDLen = hostStrID.length();
  423. if (hostZone != nullptr && rawOffset != hostZone->getRawOffset()
  424. && (3 <= hostIDLen && hostIDLen <= 4))
  425. {
  426. // Uh oh. This probably wasn't a good id.
  427. // It was probably an ambiguous abbreviation
  428. delete hostZone;
  429. hostZone = nullptr;
  430. }
  431. // Construct a fixed standard zone with the host's ID
  432. // and raw offset.
  433. if (hostZone == nullptr && hostDetectionSucceeded) {
  434. hostZone = new SimpleTimeZone(rawOffset, hostStrID);
  435. }
  436. // If we _still_ don't have a time zone, use the Unknown zone.
  437. //
  438. // Note: This is extremely unlikely situation. If
  439. // new SimpleTimeZone(...) above fails, the following
  440. // code may also fail.
  441. if (hostZone == nullptr) {
  442. // Unknown zone uses static allocated memory, so it must always exist.
  443. // However, clone() allocates memory and can fail.
  444. hostZone = TimeZone::getUnknown().clone();
  445. }
  446. return hostZone;
  447. }
  448. // -------------------------------------
  449. static UMutex gDefaultZoneMutex;
  450. /**
  451. * Initialize DEFAULT_ZONE from the system default time zone.
  452. * Upon return, DEFAULT_ZONE will not be nullptr, unless operator new()
  453. * returns nullptr.
  454. */
  455. static void U_CALLCONV initDefault()
  456. {
  457. ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
  458. Mutex lock(&gDefaultZoneMutex);
  459. // If setDefault() has already been called we can skip getting the
  460. // default zone information from the system.
  461. if (DEFAULT_ZONE != nullptr) {
  462. return;
  463. }
  464. // NOTE: this code is safely single threaded, being only
  465. // run via umtx_initOnce().
  466. //
  467. // Some of the locale/timezone OS functions may not be thread safe,
  468. //
  469. // The operating system might actually use ICU to implement timezones.
  470. // So we may have ICU calling ICU here, like on AIX.
  471. // There shouldn't be a problem with this; initOnce does not hold a mutex
  472. // while the init function is being run.
  473. // The code detecting the host time zone was separated from this
  474. // and implemented as TimeZone::detectHostTimeZone()
  475. TimeZone *default_zone = TimeZone::detectHostTimeZone();
  476. U_ASSERT(DEFAULT_ZONE == nullptr);
  477. DEFAULT_ZONE = default_zone;
  478. }
  479. // -------------------------------------
  480. TimeZone* U_EXPORT2
  481. TimeZone::createDefault()
  482. {
  483. umtx_initOnce(gDefaultZoneInitOnce, initDefault);
  484. {
  485. Mutex lock(&gDefaultZoneMutex);
  486. return (DEFAULT_ZONE != nullptr) ? DEFAULT_ZONE->clone() : nullptr;
  487. }
  488. }
  489. // -------------------------------------
  490. TimeZone* U_EXPORT2
  491. TimeZone::forLocaleOrDefault(const Locale& locale)
  492. {
  493. char buffer[ULOC_KEYWORDS_CAPACITY] = "";
  494. UErrorCode localStatus = U_ZERO_ERROR;
  495. int32_t count = locale.getKeywordValue("timezone", buffer, sizeof(buffer), localStatus);
  496. if (U_FAILURE(localStatus) || localStatus == U_STRING_NOT_TERMINATED_WARNING) {
  497. // the "timezone" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
  498. count = 0;
  499. }
  500. if (count > 0) {
  501. return TimeZone::createTimeZone(UnicodeString(buffer, count, US_INV));
  502. }
  503. return TimeZone::createDefault();
  504. }
  505. // -------------------------------------
  506. void U_EXPORT2
  507. TimeZone::adoptDefault(TimeZone* zone)
  508. {
  509. if (zone != nullptr)
  510. {
  511. {
  512. Mutex lock(&gDefaultZoneMutex);
  513. TimeZone *old = DEFAULT_ZONE;
  514. DEFAULT_ZONE = zone;
  515. delete old;
  516. }
  517. ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
  518. }
  519. }
  520. // -------------------------------------
  521. void U_EXPORT2
  522. TimeZone::setDefault(const TimeZone& zone)
  523. {
  524. adoptDefault(zone.clone());
  525. }
  526. //----------------------------------------------------------------------
  527. static void U_CALLCONV initMap(USystemTimeZoneType type, UErrorCode& ec) {
  528. ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
  529. UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
  530. res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
  531. if (U_SUCCESS(ec)) {
  532. int32_t size = ures_getSize(res);
  533. int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t));
  534. if (m == nullptr) {
  535. ec = U_MEMORY_ALLOCATION_ERROR;
  536. } else {
  537. int32_t numEntries = 0;
  538. for (int32_t i = 0; i < size; i++) {
  539. UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec);
  540. if (U_FAILURE(ec)) {
  541. break;
  542. }
  543. if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) {
  544. // exclude Etc/Unknown
  545. continue;
  546. }
  547. if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
  548. UnicodeString canonicalID;
  549. ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec);
  550. if (U_FAILURE(ec)) {
  551. break;
  552. }
  553. if (canonicalID != id) {
  554. // exclude aliases
  555. continue;
  556. }
  557. }
  558. if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
  559. const char16_t *region = TimeZone::getRegion(id, ec);
  560. if (U_FAILURE(ec)) {
  561. break;
  562. }
  563. if (u_strcmp(region, WORLD) == 0) {
  564. // exclude non-location ("001")
  565. continue;
  566. }
  567. }
  568. m[numEntries++] = i;
  569. }
  570. if (U_SUCCESS(ec)) {
  571. int32_t *tmp = m;
  572. m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t));
  573. if (m == nullptr) {
  574. // realloc failed.. use the original one even it has unused
  575. // area at the end
  576. m = tmp;
  577. }
  578. switch(type) {
  579. case UCAL_ZONE_TYPE_ANY:
  580. U_ASSERT(MAP_SYSTEM_ZONES == nullptr);
  581. MAP_SYSTEM_ZONES = m;
  582. LEN_SYSTEM_ZONES = numEntries;
  583. break;
  584. case UCAL_ZONE_TYPE_CANONICAL:
  585. U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == nullptr);
  586. MAP_CANONICAL_SYSTEM_ZONES = m;
  587. LEN_CANONICAL_SYSTEM_ZONES = numEntries;
  588. break;
  589. case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
  590. U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == nullptr);
  591. MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
  592. LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries;
  593. break;
  594. }
  595. }
  596. }
  597. }
  598. ures_close(res);
  599. }
  600. /**
  601. * This is the default implementation for subclasses that do not
  602. * override this method. This implementation calls through to the
  603. * 8-argument getOffset() method after suitable computations, and
  604. * correctly adjusts GMT millis to local millis when necessary.
  605. */
  606. void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
  607. int32_t& dstOffset, UErrorCode& ec) const {
  608. if (U_FAILURE(ec)) {
  609. return;
  610. }
  611. rawOffset = getRawOffset();
  612. if (!local) {
  613. date += rawOffset; // now in local standard millis
  614. }
  615. // When local == true, date might not be in local standard
  616. // millis. getOffset taking 7 parameters used here assume
  617. // the given time in day is local standard time.
  618. // At STD->DST transition, there is a range of time which
  619. // does not exist. When 'date' is in this time range
  620. // (and local == true), this method interprets the specified
  621. // local time as DST. At DST->STD transition, there is a
  622. // range of time which occurs twice. In this case, this
  623. // method interprets the specified local time as STD.
  624. // To support the behavior above, we need to call getOffset
  625. // (with 7 args) twice when local == true and DST is
  626. // detected in the initial call.
  627. for (int32_t pass=0; ; ++pass) {
  628. int32_t year, month, dom, dow, millis;
  629. double day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
  630. Grego::dayToFields(day, year, month, dom, dow);
  631. dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
  632. (uint8_t) dow, millis,
  633. Grego::monthLength(year, month),
  634. ec) - rawOffset;
  635. // Recompute if local==true, dstOffset!=0.
  636. if (pass!=0 || !local || dstOffset == 0) {
  637. break;
  638. }
  639. // adjust to local standard millis
  640. date -= dstOffset;
  641. }
  642. }
  643. // -------------------------------------
  644. // New available IDs API as of ICU 2.4. Uses StringEnumeration API.
  645. class TZEnumeration : public StringEnumeration {
  646. private:
  647. // Map into to zones. Our results are zone[map[i]] for
  648. // i=0..len-1, where zone[i] is the i-th Olson zone. If map==nullptr
  649. // then our results are zone[i] for i=0..len-1. Len will be zero
  650. // if the zone data could not be loaded.
  651. int32_t* map;
  652. int32_t* localMap;
  653. int32_t len;
  654. int32_t pos;
  655. TZEnumeration(int32_t* mapData, int32_t mapLen, UBool adoptMapData) : pos(0) {
  656. map = mapData;
  657. localMap = adoptMapData ? mapData : nullptr;
  658. len = mapLen;
  659. }
  660. UBool getID(int32_t i, UErrorCode& ec) {
  661. int32_t idLen = 0;
  662. const char16_t* id = nullptr;
  663. UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
  664. top = ures_getByKey(top, kNAMES, top, &ec); // dereference Zones section
  665. id = ures_getStringByIndex(top, i, &idLen, &ec);
  666. if(U_FAILURE(ec)) {
  667. unistr.truncate(0);
  668. }
  669. else {
  670. unistr.fastCopyFrom(UnicodeString(true, id, idLen));
  671. }
  672. ures_close(top);
  673. return U_SUCCESS(ec);
  674. }
  675. static int32_t* getMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) {
  676. len = 0;
  677. if (U_FAILURE(ec)) {
  678. return nullptr;
  679. }
  680. int32_t* m = nullptr;
  681. switch (type) {
  682. case UCAL_ZONE_TYPE_ANY:
  683. umtx_initOnce(gSystemZonesInitOnce, &initMap, type, ec);
  684. m = MAP_SYSTEM_ZONES;
  685. len = LEN_SYSTEM_ZONES;
  686. break;
  687. case UCAL_ZONE_TYPE_CANONICAL:
  688. umtx_initOnce(gCanonicalZonesInitOnce, &initMap, type, ec);
  689. m = MAP_CANONICAL_SYSTEM_ZONES;
  690. len = LEN_CANONICAL_SYSTEM_ZONES;
  691. break;
  692. case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
  693. umtx_initOnce(gCanonicalLocationZonesInitOnce, &initMap, type, ec);
  694. m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
  695. len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
  696. break;
  697. default:
  698. ec = U_ILLEGAL_ARGUMENT_ERROR;
  699. m = nullptr;
  700. len = 0;
  701. break;
  702. }
  703. return m;
  704. }
  705. public:
  706. #define DEFAULT_FILTERED_MAP_SIZE 8
  707. #define MAP_INCREMENT_SIZE 8
  708. static TZEnumeration* create(USystemTimeZoneType type, const char* region, const int32_t* rawOffset, UErrorCode& ec) {
  709. if (U_FAILURE(ec)) {
  710. return nullptr;
  711. }
  712. int32_t baseLen;
  713. int32_t *baseMap = getMap(type, baseLen, ec);
  714. if (U_FAILURE(ec)) {
  715. return nullptr;
  716. }
  717. // If any additional conditions are available,
  718. // create instance local map filtered by the conditions.
  719. int32_t *filteredMap = nullptr;
  720. int32_t numEntries = 0;
  721. if (region != nullptr || rawOffset != nullptr) {
  722. int32_t filteredMapSize = DEFAULT_FILTERED_MAP_SIZE;
  723. filteredMap = (int32_t *)uprv_malloc(filteredMapSize * sizeof(int32_t));
  724. if (filteredMap == nullptr) {
  725. ec = U_MEMORY_ALLOCATION_ERROR;
  726. return nullptr;
  727. }
  728. // Walk through the base map
  729. UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
  730. res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
  731. for (int32_t i = 0; i < baseLen; i++) {
  732. int32_t zidx = baseMap[i];
  733. UnicodeString id = ures_getUnicodeStringByIndex(res, zidx, &ec);
  734. if (U_FAILURE(ec)) {
  735. break;
  736. }
  737. if (region != nullptr) {
  738. // Filter by region
  739. char tzregion[4]; // max 3 letters + null term
  740. TimeZone::getRegion(id, tzregion, sizeof(tzregion), ec);
  741. if (U_FAILURE(ec)) {
  742. break;
  743. }
  744. if (uprv_stricmp(tzregion, region) != 0) {
  745. // region does not match
  746. continue;
  747. }
  748. }
  749. if (rawOffset != nullptr) {
  750. // Filter by raw offset
  751. // Note: This is VERY inefficient
  752. TimeZone *z = createSystemTimeZone(id, ec);
  753. if (U_FAILURE(ec)) {
  754. break;
  755. }
  756. int32_t tzoffset = z->getRawOffset();
  757. delete z;
  758. if (tzoffset != *rawOffset) {
  759. continue;
  760. }
  761. }
  762. if (filteredMapSize <= numEntries) {
  763. filteredMapSize += MAP_INCREMENT_SIZE;
  764. int32_t *tmp = (int32_t *)uprv_realloc(filteredMap, filteredMapSize * sizeof(int32_t));
  765. if (tmp == nullptr) {
  766. ec = U_MEMORY_ALLOCATION_ERROR;
  767. break;
  768. } else {
  769. filteredMap = tmp;
  770. }
  771. }
  772. filteredMap[numEntries++] = zidx;
  773. }
  774. if (U_FAILURE(ec)) {
  775. uprv_free(filteredMap);
  776. filteredMap = nullptr;
  777. }
  778. ures_close(res);
  779. }
  780. TZEnumeration *result = nullptr;
  781. if (U_SUCCESS(ec)) {
  782. // Finally, create a new enumeration instance
  783. if (filteredMap == nullptr) {
  784. result = new TZEnumeration(baseMap, baseLen, false);
  785. } else {
  786. result = new TZEnumeration(filteredMap, numEntries, true);
  787. filteredMap = nullptr;
  788. }
  789. if (result == nullptr) {
  790. ec = U_MEMORY_ALLOCATION_ERROR;
  791. }
  792. }
  793. if (filteredMap != nullptr) {
  794. uprv_free(filteredMap);
  795. }
  796. return result;
  797. }
  798. TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(nullptr), localMap(nullptr), len(0), pos(0) {
  799. if (other.localMap != nullptr) {
  800. localMap = (int32_t *)uprv_malloc(other.len * sizeof(int32_t));
  801. if (localMap != nullptr) {
  802. len = other.len;
  803. uprv_memcpy(localMap, other.localMap, len * sizeof(int32_t));
  804. pos = other.pos;
  805. map = localMap;
  806. } else {
  807. len = 0;
  808. pos = 0;
  809. map = nullptr;
  810. }
  811. } else {
  812. map = other.map;
  813. localMap = nullptr;
  814. len = other.len;
  815. pos = other.pos;
  816. }
  817. }
  818. virtual ~TZEnumeration();
  819. virtual StringEnumeration *clone() const override {
  820. return new TZEnumeration(*this);
  821. }
  822. virtual int32_t count(UErrorCode& status) const override {
  823. return U_FAILURE(status) ? 0 : len;
  824. }
  825. virtual const UnicodeString* snext(UErrorCode& status) override {
  826. if (U_SUCCESS(status) && map != nullptr && pos < len) {
  827. getID(map[pos], status);
  828. ++pos;
  829. return &unistr;
  830. }
  831. return 0;
  832. }
  833. virtual void reset(UErrorCode& /*status*/) override {
  834. pos = 0;
  835. }
  836. public:
  837. static UClassID U_EXPORT2 getStaticClassID();
  838. virtual UClassID getDynamicClassID() const override;
  839. };
  840. TZEnumeration::~TZEnumeration() {
  841. if (localMap != nullptr) {
  842. uprv_free(localMap);
  843. }
  844. }
  845. UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TZEnumeration)
  846. StringEnumeration* U_EXPORT2
  847. TimeZone::createTimeZoneIDEnumeration(
  848. USystemTimeZoneType zoneType,
  849. const char* region,
  850. const int32_t* rawOffset,
  851. UErrorCode& ec) {
  852. return TZEnumeration::create(zoneType, region, rawOffset, ec);
  853. }
  854. StringEnumeration* U_EXPORT2
  855. TimeZone::createEnumeration(UErrorCode& status) {
  856. return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, nullptr, nullptr, status);
  857. }
  858. StringEnumeration* U_EXPORT2
  859. TimeZone::createEnumerationForRawOffset(int32_t rawOffset, UErrorCode& status) {
  860. return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, nullptr, &rawOffset, status);
  861. }
  862. StringEnumeration* U_EXPORT2
  863. TimeZone::createEnumerationForRegion(const char* region, UErrorCode& status) {
  864. return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, region, nullptr, status);
  865. }
  866. //
  867. // Next 3 methods are equivalent to above, but ignores UErrorCode.
  868. // These methods were deprecated in ICU 70.
  869. StringEnumeration* U_EXPORT2
  870. TimeZone::createEnumeration() {
  871. UErrorCode ec = U_ZERO_ERROR;
  872. return createEnumeration(ec);
  873. }
  874. StringEnumeration* U_EXPORT2
  875. TimeZone::createEnumeration(int32_t rawOffset) {
  876. UErrorCode ec = U_ZERO_ERROR;
  877. return createEnumerationForRawOffset(rawOffset, ec);
  878. }
  879. StringEnumeration* U_EXPORT2
  880. TimeZone::createEnumeration(const char* region) {
  881. UErrorCode ec = U_ZERO_ERROR;
  882. return createEnumerationForRegion(region, ec);
  883. }
  884. // ---------------------------------------
  885. int32_t U_EXPORT2
  886. TimeZone::countEquivalentIDs(const UnicodeString& id) {
  887. int32_t result = 0;
  888. UErrorCode ec = U_ZERO_ERROR;
  889. StackUResourceBundle res;
  890. U_DEBUG_TZ_MSG(("countEquivalentIDs..\n"));
  891. UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
  892. if (U_SUCCESS(ec)) {
  893. StackUResourceBundle r;
  894. ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
  895. ures_getIntVector(r.getAlias(), &result, &ec);
  896. }
  897. ures_close(top);
  898. return result;
  899. }
  900. // ---------------------------------------
  901. const UnicodeString U_EXPORT2
  902. TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
  903. U_DEBUG_TZ_MSG(("gEI(%d)\n", index));
  904. UnicodeString result;
  905. UErrorCode ec = U_ZERO_ERROR;
  906. StackUResourceBundle res;
  907. UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
  908. int32_t zone = -1;
  909. if (U_SUCCESS(ec)) {
  910. StackUResourceBundle r;
  911. int32_t size;
  912. ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
  913. const int32_t *v = ures_getIntVector(r.getAlias(), &size, &ec);
  914. if (U_SUCCESS(ec)) {
  915. if (index >= 0 && index < size) {
  916. zone = v[index];
  917. }
  918. }
  919. }
  920. if (zone >= 0) {
  921. UResourceBundle *ares = ures_getByKey(top, kNAMES, nullptr, &ec); // dereference Zones section
  922. if (U_SUCCESS(ec)) {
  923. int32_t idLen = 0;
  924. const char16_t* id2 = ures_getStringByIndex(ares, zone, &idLen, &ec);
  925. result.fastCopyFrom(UnicodeString(true, id2, idLen));
  926. U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
  927. }
  928. ures_close(ares);
  929. }
  930. ures_close(top);
  931. #if defined(U_DEBUG_TZ)
  932. if(result.length() ==0) {
  933. U_DEBUG_TZ_MSG(("equiv [__, #%d] -> 0 (%s)\n", index, u_errorName(ec)));
  934. }
  935. #endif
  936. return result;
  937. }
  938. // ---------------------------------------
  939. // These methods are used by ZoneMeta class only.
  940. const char16_t*
  941. TimeZone::findID(const UnicodeString& id) {
  942. const char16_t *result = nullptr;
  943. UErrorCode ec = U_ZERO_ERROR;
  944. UResourceBundle *rb = ures_openDirect(nullptr, kZONEINFO, &ec);
  945. // resolve zone index by name
  946. UResourceBundle *names = ures_getByKey(rb, kNAMES, nullptr, &ec);
  947. int32_t idx = findInStringArray(names, id, ec);
  948. result = ures_getStringByIndex(names, idx, nullptr, &ec);
  949. if (U_FAILURE(ec)) {
  950. result = nullptr;
  951. }
  952. ures_close(names);
  953. ures_close(rb);
  954. return result;
  955. }
  956. const char16_t*
  957. TimeZone::dereferOlsonLink(const UnicodeString& id) {
  958. const char16_t *result = nullptr;
  959. UErrorCode ec = U_ZERO_ERROR;
  960. UResourceBundle *rb = ures_openDirect(nullptr, kZONEINFO, &ec);
  961. // resolve zone index by name
  962. UResourceBundle *names = ures_getByKey(rb, kNAMES, nullptr, &ec);
  963. int32_t idx = findInStringArray(names, id, ec);
  964. result = ures_getStringByIndex(names, idx, nullptr, &ec);
  965. // open the zone bundle by index
  966. ures_getByKey(rb, kZONES, rb, &ec);
  967. ures_getByIndex(rb, idx, rb, &ec);
  968. if (U_SUCCESS(ec)) {
  969. if (ures_getType(rb) == URES_INT) {
  970. // this is a link - dereference the link
  971. int32_t deref = ures_getInt(rb, &ec);
  972. const char16_t* tmp = ures_getStringByIndex(names, deref, nullptr, &ec);
  973. if (U_SUCCESS(ec)) {
  974. result = tmp;
  975. }
  976. }
  977. }
  978. ures_close(names);
  979. ures_close(rb);
  980. return result;
  981. }
  982. const char16_t*
  983. TimeZone::getRegion(const UnicodeString& id) {
  984. UErrorCode status = U_ZERO_ERROR;
  985. return getRegion(id, status);
  986. }
  987. const char16_t*
  988. TimeZone::getRegion(const UnicodeString& id, UErrorCode& status) {
  989. if (U_FAILURE(status)) {
  990. return nullptr;
  991. }
  992. const char16_t *result = nullptr;
  993. UResourceBundle *rb = ures_openDirect(nullptr, kZONEINFO, &status);
  994. // resolve zone index by name
  995. UResourceBundle *res = ures_getByKey(rb, kNAMES, nullptr, &status);
  996. int32_t idx = findInStringArray(res, id, status);
  997. // get region mapping
  998. ures_getByKey(rb, kREGIONS, res, &status);
  999. const char16_t *tmp = ures_getStringByIndex(res, idx, nullptr, &status);
  1000. if (U_SUCCESS(status)) {
  1001. result = tmp;
  1002. }
  1003. ures_close(res);
  1004. ures_close(rb);
  1005. return result;
  1006. }
  1007. // ---------------------------------------
  1008. int32_t
  1009. TimeZone::getRegion(const UnicodeString& id, char *region, int32_t capacity, UErrorCode& status)
  1010. {
  1011. int32_t resultLen = 0;
  1012. *region = 0;
  1013. if (U_FAILURE(status)) {
  1014. return 0;
  1015. }
  1016. const char16_t *uregion = nullptr;
  1017. // "Etc/Unknown" is not a system zone ID,
  1018. // but in the zone data
  1019. if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) {
  1020. uregion = getRegion(id);
  1021. }
  1022. if (uregion == nullptr) {
  1023. status = U_ILLEGAL_ARGUMENT_ERROR;
  1024. return 0;
  1025. }
  1026. resultLen = u_strlen(uregion);
  1027. // A region code is represented by invariant characters
  1028. u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity));
  1029. if (capacity < resultLen) {
  1030. status = U_BUFFER_OVERFLOW_ERROR;
  1031. return resultLen;
  1032. }
  1033. return u_terminateChars(region, capacity, resultLen, &status);
  1034. }
  1035. // ---------------------------------------
  1036. UnicodeString&
  1037. TimeZone::getDisplayName(UnicodeString& result) const
  1038. {
  1039. return getDisplayName(false,LONG,Locale::getDefault(), result);
  1040. }
  1041. UnicodeString&
  1042. TimeZone::getDisplayName(const Locale& locale, UnicodeString& result) const
  1043. {
  1044. return getDisplayName(false, LONG, locale, result);
  1045. }
  1046. UnicodeString&
  1047. TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, UnicodeString& result) const
  1048. {
  1049. return getDisplayName(inDaylight,style, Locale::getDefault(), result);
  1050. }
  1051. //--------------------------------------
  1052. int32_t
  1053. TimeZone::getDSTSavings()const {
  1054. if (useDaylightTime()) {
  1055. return 3600000;
  1056. }
  1057. return 0;
  1058. }
  1059. //---------------------------------------
  1060. UnicodeString&
  1061. TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
  1062. {
  1063. UErrorCode status = U_ZERO_ERROR;
  1064. UDate date = Calendar::getNow();
  1065. UTimeZoneFormatTimeType timeType = UTZFMT_TIME_TYPE_UNKNOWN;
  1066. int32_t offset;
  1067. if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) {
  1068. LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
  1069. if (U_FAILURE(status)) {
  1070. result.remove();
  1071. return result;
  1072. }
  1073. // Generic format
  1074. switch (style) {
  1075. case GENERIC_LOCATION:
  1076. tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, *this, date, result, &timeType);
  1077. break;
  1078. case LONG_GENERIC:
  1079. tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, *this, date, result, &timeType);
  1080. break;
  1081. case SHORT_GENERIC:
  1082. tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, *this, date, result, &timeType);
  1083. break;
  1084. default:
  1085. UPRV_UNREACHABLE_EXIT;
  1086. }
  1087. // Generic format many use Localized GMT as the final fallback.
  1088. // When Localized GMT format is used, the result might not be
  1089. // appropriate for the requested daylight value.
  1090. if ((inDaylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!inDaylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
  1091. offset = inDaylight ? getRawOffset() + getDSTSavings() : getRawOffset();
  1092. if (style == SHORT_GENERIC) {
  1093. tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
  1094. } else {
  1095. tzfmt->formatOffsetLocalizedGMT(offset, result, status);
  1096. }
  1097. }
  1098. } else if (style == LONG_GMT || style == SHORT_GMT) {
  1099. LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
  1100. if (U_FAILURE(status)) {
  1101. result.remove();
  1102. return result;
  1103. }
  1104. offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
  1105. switch (style) {
  1106. case LONG_GMT:
  1107. tzfmt->formatOffsetLocalizedGMT(offset, result, status);
  1108. break;
  1109. case SHORT_GMT:
  1110. tzfmt->formatOffsetISO8601Basic(offset, false, false, false, result, status);
  1111. break;
  1112. default:
  1113. UPRV_UNREACHABLE_EXIT;
  1114. }
  1115. } else {
  1116. U_ASSERT(style == LONG || style == SHORT || style == SHORT_COMMONLY_USED);
  1117. UTimeZoneNameType nameType = UTZNM_UNKNOWN;
  1118. switch (style) {
  1119. case LONG:
  1120. nameType = inDaylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD;
  1121. break;
  1122. case SHORT:
  1123. case SHORT_COMMONLY_USED:
  1124. nameType = inDaylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD;
  1125. break;
  1126. default:
  1127. UPRV_UNREACHABLE_EXIT;
  1128. }
  1129. LocalPointer<TimeZoneNames> tznames(TimeZoneNames::createInstance(locale, status));
  1130. if (U_FAILURE(status)) {
  1131. result.remove();
  1132. return result;
  1133. }
  1134. UnicodeString canonicalID(ZoneMeta::getCanonicalCLDRID(*this));
  1135. tznames->getDisplayName(canonicalID, nameType, date, result);
  1136. if (result.isEmpty()) {
  1137. // Fallback to localized GMT
  1138. LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
  1139. offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
  1140. if (style == LONG) {
  1141. tzfmt->formatOffsetLocalizedGMT(offset, result, status);
  1142. } else {
  1143. tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
  1144. }
  1145. }
  1146. }
  1147. if (U_FAILURE(status)) {
  1148. result.remove();
  1149. }
  1150. return result;
  1151. }
  1152. /**
  1153. * Parse a custom time zone identifier and return a corresponding zone.
  1154. * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
  1155. * GMT[+-]hh.
  1156. * @return a newly created SimpleTimeZone with the given offset and
  1157. * no Daylight Savings Time, or null if the id cannot be parsed.
  1158. */
  1159. TimeZone*
  1160. TimeZone::createCustomTimeZone(const UnicodeString& id)
  1161. {
  1162. int32_t sign, hour, min, sec;
  1163. if (parseCustomID(id, sign, hour, min, sec)) {
  1164. UnicodeString customID;
  1165. formatCustomID(hour, min, sec, (sign < 0), customID);
  1166. int32_t offset = sign * ((hour * 60 + min) * 60 + sec) * 1000;
  1167. return new SimpleTimeZone(offset, customID);
  1168. }
  1169. return nullptr;
  1170. }
  1171. UnicodeString&
  1172. TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UErrorCode& status) {
  1173. normalized.remove();
  1174. if (U_FAILURE(status)) {
  1175. return normalized;
  1176. }
  1177. int32_t sign, hour, min, sec;
  1178. if (parseCustomID(id, sign, hour, min, sec)) {
  1179. formatCustomID(hour, min, sec, (sign < 0), normalized);
  1180. } else {
  1181. status = U_ILLEGAL_ARGUMENT_ERROR;
  1182. }
  1183. return normalized;
  1184. }
  1185. UBool
  1186. TimeZone::parseCustomID(const UnicodeString& id, int32_t& sign,
  1187. int32_t& hour, int32_t& min, int32_t& sec) {
  1188. static const int32_t kParseFailed = -99999;
  1189. NumberFormat* numberFormat = 0;
  1190. UnicodeString idUppercase = id;
  1191. idUppercase.toUpper("");
  1192. if (id.length() > GMT_ID_LENGTH &&
  1193. idUppercase.startsWith(GMT_ID, GMT_ID_LENGTH))
  1194. {
  1195. ParsePosition pos(GMT_ID_LENGTH);
  1196. sign = 1;
  1197. hour = 0;
  1198. min = 0;
  1199. sec = 0;
  1200. if (id[pos.getIndex()] == MINUS /*'-'*/) {
  1201. sign = -1;
  1202. } else if (id[pos.getIndex()] != PLUS /*'+'*/) {
  1203. return false;
  1204. }
  1205. pos.setIndex(pos.getIndex() + 1);
  1206. UErrorCode success = U_ZERO_ERROR;
  1207. numberFormat = NumberFormat::createInstance(success);
  1208. if(U_FAILURE(success)){
  1209. return false;
  1210. }
  1211. numberFormat->setParseIntegerOnly(true);
  1212. //numberFormat->setLenient(true); // TODO: May need to set this, depends on latest timezone parsing
  1213. // Look for either hh:mm, hhmm, or hh
  1214. int32_t start = pos.getIndex();
  1215. Formattable n(kParseFailed);
  1216. numberFormat->parse(id, n, pos);
  1217. if (pos.getIndex() == start) {
  1218. delete numberFormat;
  1219. return false;
  1220. }
  1221. hour = n.getLong();
  1222. if (pos.getIndex() < id.length()) {
  1223. if (pos.getIndex() - start > 2
  1224. || id[pos.getIndex()] != COLON) {
  1225. delete numberFormat;
  1226. return false;
  1227. }
  1228. // hh:mm
  1229. pos.setIndex(pos.getIndex() + 1);
  1230. int32_t oldPos = pos.getIndex();
  1231. n.setLong(kParseFailed);
  1232. numberFormat->parse(id, n, pos);
  1233. if ((pos.getIndex() - oldPos) != 2) {
  1234. // must be 2 digits
  1235. delete numberFormat;
  1236. return false;
  1237. }
  1238. min = n.getLong();
  1239. if (pos.getIndex() < id.length()) {
  1240. if (id[pos.getIndex()] != COLON) {
  1241. delete numberFormat;
  1242. return false;
  1243. }
  1244. // [:ss]
  1245. pos.setIndex(pos.getIndex() + 1);
  1246. oldPos = pos.getIndex();
  1247. n.setLong(kParseFailed);
  1248. numberFormat->parse(id, n, pos);
  1249. if (pos.getIndex() != id.length()
  1250. || (pos.getIndex() - oldPos) != 2) {
  1251. delete numberFormat;
  1252. return false;
  1253. }
  1254. sec = n.getLong();
  1255. }
  1256. } else {
  1257. // Supported formats are below -
  1258. //
  1259. // HHmmss
  1260. // Hmmss
  1261. // HHmm
  1262. // Hmm
  1263. // HH
  1264. // H
  1265. int32_t length = pos.getIndex() - start;
  1266. if (length <= 0 || 6 < length) {
  1267. // invalid length
  1268. delete numberFormat;
  1269. return false;
  1270. }
  1271. switch (length) {
  1272. case 1:
  1273. case 2:
  1274. // already set to hour
  1275. break;
  1276. case 3:
  1277. case 4:
  1278. min = hour % 100;
  1279. hour /= 100;
  1280. break;
  1281. case 5:
  1282. case 6:
  1283. sec = hour % 100;
  1284. min = (hour/100) % 100;
  1285. hour /= 10000;
  1286. break;
  1287. }
  1288. }
  1289. delete numberFormat;
  1290. if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) {
  1291. return false;
  1292. }
  1293. return true;
  1294. }
  1295. return false;
  1296. }
  1297. UnicodeString&
  1298. TimeZone::formatCustomID(int32_t hour, int32_t min, int32_t sec,
  1299. UBool negative, UnicodeString& id) {
  1300. // Create time zone ID - GMT[+|-]hhmm[ss]
  1301. id.setTo(GMT_ID, GMT_ID_LENGTH);
  1302. if (hour | min | sec) {
  1303. if (negative) {
  1304. id += (char16_t)MINUS;
  1305. } else {
  1306. id += (char16_t)PLUS;
  1307. }
  1308. if (hour < 10) {
  1309. id += (char16_t)ZERO_DIGIT;
  1310. } else {
  1311. id += (char16_t)(ZERO_DIGIT + hour/10);
  1312. }
  1313. id += (char16_t)(ZERO_DIGIT + hour%10);
  1314. id += (char16_t)COLON;
  1315. if (min < 10) {
  1316. id += (char16_t)ZERO_DIGIT;
  1317. } else {
  1318. id += (char16_t)(ZERO_DIGIT + min/10);
  1319. }
  1320. id += (char16_t)(ZERO_DIGIT + min%10);
  1321. if (sec) {
  1322. id += (char16_t)COLON;
  1323. if (sec < 10) {
  1324. id += (char16_t)ZERO_DIGIT;
  1325. } else {
  1326. id += (char16_t)(ZERO_DIGIT + sec/10);
  1327. }
  1328. id += (char16_t)(ZERO_DIGIT + sec%10);
  1329. }
  1330. }
  1331. return id;
  1332. }
  1333. UBool
  1334. TimeZone::hasSameRules(const TimeZone& other) const
  1335. {
  1336. return (getRawOffset() == other.getRawOffset() &&
  1337. useDaylightTime() == other.useDaylightTime());
  1338. }
  1339. static void U_CALLCONV initTZDataVersion(UErrorCode &status) {
  1340. ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
  1341. int32_t len = 0;
  1342. StackUResourceBundle bundle;
  1343. ures_openDirectFillIn(bundle.getAlias(), nullptr, kZONEINFO, &status);
  1344. const char16_t *tzver = ures_getStringByKey(bundle.getAlias(), kTZVERSION, &len, &status);
  1345. if (U_SUCCESS(status)) {
  1346. if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
  1347. // Ensure that there is always space for a trailing nul in TZDATA_VERSION
  1348. len = sizeof(TZDATA_VERSION) - 1;
  1349. }
  1350. u_UCharsToChars(tzver, TZDATA_VERSION, len);
  1351. }
  1352. }
  1353. const char*
  1354. TimeZone::getTZDataVersion(UErrorCode& status)
  1355. {
  1356. umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status);
  1357. return (const char*)TZDATA_VERSION;
  1358. }
  1359. UnicodeString&
  1360. TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UErrorCode& status)
  1361. {
  1362. UBool isSystemID = false;
  1363. return getCanonicalID(id, canonicalID, isSystemID, status);
  1364. }
  1365. UnicodeString&
  1366. TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UBool& isSystemID,
  1367. UErrorCode& status)
  1368. {
  1369. canonicalID.remove();
  1370. isSystemID = false;
  1371. if (U_FAILURE(status)) {
  1372. return canonicalID;
  1373. }
  1374. if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) == 0) {
  1375. // special case - Etc/Unknown is a canonical ID, but not system ID
  1376. canonicalID.fastCopyFrom(id);
  1377. isSystemID = false;
  1378. } else {
  1379. ZoneMeta::getCanonicalCLDRID(id, canonicalID, status);
  1380. if (U_SUCCESS(status)) {
  1381. isSystemID = true;
  1382. } else {
  1383. // Not a system ID
  1384. status = U_ZERO_ERROR;
  1385. getCustomID(id, canonicalID, status);
  1386. }
  1387. }
  1388. return canonicalID;
  1389. }
  1390. UnicodeString&
  1391. TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode& status) {
  1392. winid.remove();
  1393. if (U_FAILURE(status)) {
  1394. return winid;
  1395. }
  1396. // canonicalize the input ID
  1397. UnicodeString canonicalID;
  1398. UBool isSystemID = false;
  1399. getCanonicalID(id, canonicalID, isSystemID, status);
  1400. if (U_FAILURE(status) || !isSystemID) {
  1401. // mapping data is only applicable to tz database IDs
  1402. if (status == U_ILLEGAL_ARGUMENT_ERROR) {
  1403. // getWindowsID() sets an empty string where
  1404. // getCanonicalID() sets a U_ILLEGAL_ARGUMENT_ERROR.
  1405. status = U_ZERO_ERROR;
  1406. }
  1407. return winid;
  1408. }
  1409. UResourceBundle *mapTimezones = ures_openDirect(nullptr, "windowsZones", &status);
  1410. ures_getByKey(mapTimezones, "mapTimezones", mapTimezones, &status);
  1411. if (U_FAILURE(status)) {
  1412. return winid;
  1413. }
  1414. UResourceBundle *winzone = nullptr;
  1415. UBool found = false;
  1416. while (ures_hasNext(mapTimezones) && !found) {
  1417. winzone = ures_getNextResource(mapTimezones, winzone, &status);
  1418. if (U_FAILURE(status)) {
  1419. break;
  1420. }
  1421. if (ures_getType(winzone) != URES_TABLE) {
  1422. continue;
  1423. }
  1424. UResourceBundle *regionalData = nullptr;
  1425. while (ures_hasNext(winzone) && !found) {
  1426. regionalData = ures_getNextResource(winzone, regionalData, &status);
  1427. if (U_FAILURE(status)) {
  1428. break;
  1429. }
  1430. if (ures_getType(regionalData) != URES_STRING) {
  1431. continue;
  1432. }
  1433. int32_t len;
  1434. const char16_t *tzids = ures_getString(regionalData, &len, &status);
  1435. if (U_FAILURE(status)) {
  1436. break;
  1437. }
  1438. const char16_t *start = tzids;
  1439. UBool hasNext = true;
  1440. while (hasNext) {
  1441. const char16_t *end = u_strchr(start, (char16_t)0x20);
  1442. if (end == nullptr) {
  1443. end = tzids + len;
  1444. hasNext = false;
  1445. }
  1446. if (canonicalID.compare(start, static_cast<int32_t>(end - start)) == 0) {
  1447. winid = UnicodeString(ures_getKey(winzone), -1 , US_INV);
  1448. found = true;
  1449. break;
  1450. }
  1451. start = end + 1;
  1452. }
  1453. }
  1454. ures_close(regionalData);
  1455. }
  1456. ures_close(winzone);
  1457. ures_close(mapTimezones);
  1458. return winid;
  1459. }
  1460. #define MAX_WINDOWS_ID_SIZE 128
  1461. UnicodeString&
  1462. TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, UnicodeString& id, UErrorCode& status) {
  1463. id.remove();
  1464. if (U_FAILURE(status)) {
  1465. return id;
  1466. }
  1467. UResourceBundle *zones = ures_openDirect(nullptr, "windowsZones", &status);
  1468. ures_getByKey(zones, "mapTimezones", zones, &status);
  1469. if (U_FAILURE(status)) {
  1470. ures_close(zones);
  1471. return id;
  1472. }
  1473. UErrorCode tmperr = U_ZERO_ERROR;
  1474. char winidKey[MAX_WINDOWS_ID_SIZE];
  1475. int32_t winKeyLen = winid.extract(0, winid.length(), winidKey, sizeof(winidKey) - 1, US_INV);
  1476. if (winKeyLen == 0 || winKeyLen >= (int32_t)sizeof(winidKey)) {
  1477. ures_close(zones);
  1478. return id;
  1479. }
  1480. winidKey[winKeyLen] = 0;
  1481. ures_getByKey(zones, winidKey, zones, &tmperr); // use tmperr, because windows mapping might not
  1482. // be available by design
  1483. if (U_FAILURE(tmperr)) {
  1484. ures_close(zones);
  1485. return id;
  1486. }
  1487. const char16_t *tzid = nullptr;
  1488. int32_t len = 0;
  1489. UBool gotID = false;
  1490. if (region) {
  1491. const char16_t *tzids = ures_getStringByKey(zones, region, &len, &tmperr); // use tmperr, because
  1492. // regional mapping is optional
  1493. if (U_SUCCESS(tmperr)) {
  1494. // first ID delimited by space is the default one
  1495. const char16_t *end = u_strchr(tzids, (char16_t)0x20);
  1496. if (end == nullptr) {
  1497. id.setTo(tzids, -1);
  1498. } else {
  1499. id.setTo(tzids, static_cast<int32_t>(end - tzids));
  1500. }
  1501. gotID = true;
  1502. }
  1503. }
  1504. if (!gotID) {
  1505. tzid = ures_getStringByKey(zones, "001", &len, &status); // using status, because "001" must be
  1506. // available at this point
  1507. if (U_SUCCESS(status)) {
  1508. id.setTo(tzid, len);
  1509. }
  1510. }
  1511. ures_close(zones);
  1512. return id;
  1513. }
  1514. U_NAMESPACE_END
  1515. #endif /* #if !UCONFIG_NO_FORMATTING */
  1516. //eof