1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Copyright (C) 2007-2014, International Business Machines Corporation and
459d709d503bab6e2b61931737e662dd293b40578ccornelius* others. All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "zonemeta.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/timezone.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ustring.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/putil.h"
17103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#include "unicode/simpletz.h"
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "umutex.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uvector.h"
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "gregoimp.h"
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cstring.h"
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "ucln_in.h"
2550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uassert.h"
26b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uresimp.h"
27b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "uhash.h"
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "olsontz.h"
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
3054dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic UMutex gZoneMetaLock = U_MUTEX_INITIALIZER;
3150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
32b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// CLDR Canonical ID mapping table
33b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UHashtable *gCanonicalIDCache = NULL;
3459d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic icu::UInitOnce gCanonicalIDCacheInitOnce = U_INITONCE_INITIALIZER;
35b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
3650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho// Metazone mapping table
37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UHashtable *gOlsonToMeta = NULL;
3859d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic icu::UInitOnce gOlsonToMetaInitOnce = U_INITONCE_INITIALIZER;
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
40b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho// Available metazone IDs vector and table
41103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic icu::UVector *gMetaZoneIDs = NULL;
42b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UHashtable *gMetaZoneIDTable = NULL;
4359d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic icu::UInitOnce gMetaZoneIDsInitOnce = U_INITONCE_INITIALIZER;
44b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
4550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho// Country info vectors
46103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic icu::UVector *gSingleZoneCountries = NULL;
47103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic icu::UVector *gMultiZonesCountries = NULL;
4859d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic icu::UInitOnce gCountryInfoVectorsInitOnce = U_INITONCE_INITIALIZER;
49b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
5050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_CDECL_BEGIN
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Cleanup callback func
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic UBool U_CALLCONV zoneMeta_cleanup(void)
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
57b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (gCanonicalIDCache != NULL) {
58b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uhash_close(gCanonicalIDCache);
59b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        gCanonicalIDCache = NULL;
60b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
6159d709d503bab6e2b61931737e662dd293b40578ccornelius    gCanonicalIDCacheInitOnce.reset();
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (gOlsonToMeta != NULL) {
64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uhash_close(gOlsonToMeta);
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        gOlsonToMeta = NULL;
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
6759d709d503bab6e2b61931737e662dd293b40578ccornelius    gOlsonToMetaInitOnce.reset();
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
69b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (gMetaZoneIDTable != NULL) {
70b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        uhash_close(gMetaZoneIDTable);
7159d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDTable = NULL;
72b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
73b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // delete after closing gMetaZoneIDTable, because it holds
74b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // value objects held by the hashtable
75b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    delete gMetaZoneIDs;
7659d709d503bab6e2b61931737e662dd293b40578ccornelius    gMetaZoneIDs = NULL;
7759d709d503bab6e2b61931737e662dd293b40578ccornelius    gMetaZoneIDsInitOnce.reset();
78b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
7950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    delete gSingleZoneCountries;
8059d709d503bab6e2b61931737e662dd293b40578ccornelius    gSingleZoneCountries = NULL;
8150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    delete gMultiZonesCountries;
8259d709d503bab6e2b61931737e662dd293b40578ccornelius    gMultiZonesCountries = NULL;
8359d709d503bab6e2b61931737e662dd293b40578ccornelius    gCountryInfoVectorsInitOnce.reset();
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
89b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Deleter for UChar* string
90b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
91b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void U_CALLCONV
92b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QuerudeleteUCharString(void *obj) {
93b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UChar *entry = (UChar*)obj;
94b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(entry);
95b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
96b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
97b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/**
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Deleter for UVector
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QuerudeleteUVector(void *obj) {
102103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius   delete (icu::UVector*) obj;
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Deleter for OlsonToMetaMappingEntry
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QuerudeleteOlsonToMetaMappingEntry(void *obj) {
110103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    icu::OlsonToMetaMappingEntry *entry = (icu::OlsonToMetaMappingEntry*)obj;
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(entry);
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ZID_KEY_MAX 128
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
12050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gMetaZones[]          = "metaZones";
12150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gMetazoneInfo[]       = "metazoneInfo";
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char gMapTimezonesTag[]    = "mapTimezones";
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gKeyTypeData[]        = "keyTypeData";
12550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gTypeAliasTag[]       = "typeAlias";
12627f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char gTypeMapTag[]         = "typeMap";
12750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gTimezoneTag[]        = "timezone";
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char gPrimaryZonesTag[]    = "primaryZones";
1308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
13150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gWorldTag[]           = "001";
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
13550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
13650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                     0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00}; // "1970-01-01 00:00"
13750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const UChar gDefaultTo[]   = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31,
13850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                     0x20, 0x32, 0x33, 0x3A, 0x35, 0x39, 0x00}; // "9999-12-31 23:59"
13950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
140103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic const UChar gCustomTzPrefix[]    = {0x47, 0x4D, 0x54, 0};    // "GMT"
141103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1)
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Convert a date string used by metazone mappings to UDate.
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm".
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
148c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic UDate
149c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruparseDate (const UChar *text, UErrorCode &status) {
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t len = u_strlen(text);
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (len != 16 && len != 10) {
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // It must be yyyy-MM-dd HH:mm (length 16) or yyyy-MM-dd (length 10)
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n;
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t idx;
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "yyyy" (0 - 3)
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) {
165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            year = 10*year + n;
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "MM" (5 - 6)
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) {
174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            month = 10*month + n;
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "dd" (8 - 9)
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) {
183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            day = 10*day + n;
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (len == 16) {
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // "HH" (11 - 12)
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) {
193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            n = ASCII_DIGIT((int32_t)text[idx]);
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (n >= 0) {
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                hour = 10*hour + n;
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_INVALID_FORMAT_ERROR;
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // "mm" (14 - 15)
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) {
202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            n = ASCII_DIGIT((int32_t)text[idx]);
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (n >= 0) {
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                min = 10*min + n;
205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_INVALID_FORMAT_ERROR;
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_SUCCESS(status)) {
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            + hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE;
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return date;
215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return 0;
217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
21959d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV initCanonicalIDCache(UErrorCode &status) {
22059d709d503bab6e2b61931737e662dd293b40578ccornelius    gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
22159d709d503bab6e2b61931737e662dd293b40578ccornelius    if (gCanonicalIDCache == NULL) {
22259d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
22359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
22459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
22559d709d503bab6e2b61931737e662dd293b40578ccornelius        gCanonicalIDCache = NULL;
22659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
22759d709d503bab6e2b61931737e662dd293b40578ccornelius    // No key/value deleters - keys/values are from a resource bundle
22859d709d503bab6e2b61931737e662dd293b40578ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
22959d709d503bab6e2b61931737e662dd293b40578ccornelius}
23059d709d503bab6e2b61931737e662dd293b40578ccornelius
23159d709d503bab6e2b61931737e662dd293b40578ccornelius
232b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar* U_EXPORT2
233b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
234b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
235b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
236b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
237b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (tzid.isBogus() || tzid.length() > ZID_KEY_MAX) {
23927f654740f2a26ad62a5c155af9199af9e69b889claireho        status = U_ILLEGAL_ARGUMENT_ERROR;
240b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return NULL;
241b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
242b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
243b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Checking the cached results
24459d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gCanonicalIDCacheInitOnce, &initCanonicalIDCache, status);
24559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
24659d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
247b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
248b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
249b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *canonicalID = NULL;
250b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
251b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode tmpStatus = U_ZERO_ERROR;
252b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UChar utzid[ZID_KEY_MAX + 1];
253b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus);
254b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    U_ASSERT(tmpStatus == U_ZERO_ERROR);    // we checked the length of tzid already
255b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
256b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // Check if it was already cached
257b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_lock(&gZoneMetaLock);
258b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    {
259b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
26027f654740f2a26ad62a5c155af9199af9e69b889claireho    }
261b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    umtx_unlock(&gZoneMetaLock);
262c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
263b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (canonicalID != NULL) {
264b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return canonicalID;
265b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
266b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
267b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    // If not, resolve CLDR canonical ID with resource data
268b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool isInputCanonical = FALSE;
269b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    char id[ZID_KEY_MAX + 1];
270f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    tzid.extract(0, 0x7fffffff, id, UPRV_LENGTHOF(id), US_INV);
27127f654740f2a26ad62a5c155af9199af9e69b889claireho
27227f654740f2a26ad62a5c155af9199af9e69b889claireho    // replace '/' with ':'
27327f654740f2a26ad62a5c155af9199af9e69b889claireho    char *p = id;
27427f654740f2a26ad62a5c155af9199af9e69b889claireho    while (*p++) {
27527f654740f2a26ad62a5c155af9199af9e69b889claireho        if (*p == '/') {
27627f654740f2a26ad62a5c155af9199af9e69b889claireho            *p = ':';
27750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
27927f654740f2a26ad62a5c155af9199af9e69b889claireho
2808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UResourceBundle *top = ures_openDirect(NULL, gKeyTypeData, &tmpStatus);
28127f654740f2a26ad62a5c155af9199af9e69b889claireho    UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus);
28227f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
28327f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(rb, id, rb, &tmpStatus);
28427f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(tmpStatus)) {
285b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // type entry (canonical) found
286b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // the input is the canonical ID. resolve to const UChar*
287b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        canonicalID = TimeZone::findID(tzid);
288b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        isInputCanonical = TRUE;
28927f654740f2a26ad62a5c155af9199af9e69b889claireho    }
29027f654740f2a26ad62a5c155af9199af9e69b889claireho
291b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (canonicalID == NULL) {
292b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // If a map element not found, then look for an alias
293b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tmpStatus = U_ZERO_ERROR;
294b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus);
295b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
296b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const UChar *canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
297b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(tmpStatus)) {
298b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // canonical map found
299b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            canonicalID = canonical;
300b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
30127f654740f2a26ad62a5c155af9199af9e69b889claireho
302b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (canonicalID == NULL) {
303b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            // Dereference the input ID using the tz data
304b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
305b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (derefer == NULL) {
306b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                status = U_ILLEGAL_ARGUMENT_ERROR;
307b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else {
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                int32_t len = u_strlen(derefer);
309b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                u_UCharsToChars(derefer,id,len);
310b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                id[len] = (char) 0; // Make sure it is null terminated.
311b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
312b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // replace '/' with ':'
313b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                char *p = id;
314b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                while (*p++) {
315b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (*p == '/') {
316b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *p = ':';
317b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
318b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
31927f654740f2a26ad62a5c155af9199af9e69b889claireho
320b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // If a dereference turned something up then look for an alias.
321b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // rb still points to the alias table, so we don't have to go looking
322b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // for it.
323b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                tmpStatus = U_ZERO_ERROR;
324b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus);
325b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (U_SUCCESS(tmpStatus)) {
326b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    // canonical map for the dereferenced ID found
327b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    canonicalID = canonical;
328b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
329b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    canonicalID = derefer;
330b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    isInputCanonical = TRUE;
331b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
33227f654740f2a26ad62a5c155af9199af9e69b889claireho            }
33327f654740f2a26ad62a5c155af9199af9e69b889claireho        }
334b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
335b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    ures_close(rb);
336b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    ures_close(top);
33727f654740f2a26ad62a5c155af9199af9e69b889claireho
338b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_SUCCESS(status)) {
339b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        U_ASSERT(canonicalID != NULL);  // canocanilD must be non-NULL here
340b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
341b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // Put the resolved canonical ID to the cache
342b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        umtx_lock(&gZoneMetaLock);
343b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        {
344b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
345b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (idInCache == NULL) {
346b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                const UChar* key = ZoneMeta::findTimeZoneID(tzid);
347b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                U_ASSERT(key != NULL);
348b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (key != NULL) {
349b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    idInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)key, (void *)canonicalID, &status);
350b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    U_ASSERT(idInCache == NULL);
351b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
352b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
353b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (U_SUCCESS(status) && isInputCanonical) {
354b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                // Also put canonical ID itself into the cache if not exist
355b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                const UChar *canonicalInCache = (const UChar*)uhash_get(gCanonicalIDCache, canonicalID);
356b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (canonicalInCache == NULL) {
357b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    canonicalInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)canonicalID, (void *)canonicalID, &status);
358b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    U_ASSERT(canonicalInCache == NULL);
359b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
360b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
36127f654740f2a26ad62a5c155af9199af9e69b889claireho        }
362b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        umtx_unlock(&gZoneMetaLock);
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
365b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return canonicalID;
36650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
36850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
369b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
370b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar *canonicalID = getCanonicalCLDRID(tzid, status);
371b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status) || canonicalID == NULL) {
372b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        systemID.setToBogus();
373b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return systemID;
374b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
375b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    systemID.setTo(TRUE, canonicalID, -1);
376b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return systemID;
377b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
378b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
379b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar* U_EXPORT2
380b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::getCanonicalCLDRID(const TimeZone& tz) {
381b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL) {
382b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // short cut for OlsonTimeZone
383b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
384b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return otz->getCanonicalID();
385b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
386b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode status = U_ZERO_ERROR;
387b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UnicodeString tzID;
388b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return getCanonicalCLDRID(tz.getID(tzID), status);
389b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
390b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
39159d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV countryInfoVectorsInit(UErrorCode &status) {
39259d709d503bab6e2b61931737e662dd293b40578ccornelius    // Create empty vectors
39359d709d503bab6e2b61931737e662dd293b40578ccornelius    // No deleters for these UVectors, it's a reference to a resource bundle string.
39459d709d503bab6e2b61931737e662dd293b40578ccornelius    gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
39559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (gSingleZoneCountries == NULL) {
39659d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
39759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
39859d709d503bab6e2b61931737e662dd293b40578ccornelius    gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
39959d709d503bab6e2b61931737e662dd293b40578ccornelius    if (gMultiZonesCountries == NULL) {
40059d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
40159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
40259d709d503bab6e2b61931737e662dd293b40578ccornelius
40359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
40459d709d503bab6e2b61931737e662dd293b40578ccornelius        delete gSingleZoneCountries;
40559d709d503bab6e2b61931737e662dd293b40578ccornelius        delete gMultiZonesCountries;
40659d709d503bab6e2b61931737e662dd293b40578ccornelius        gSingleZoneCountries = NULL;
40759d709d503bab6e2b61931737e662dd293b40578ccornelius        gMultiZonesCountries  = NULL;
40859d709d503bab6e2b61931737e662dd293b40578ccornelius    }
40959d709d503bab6e2b61931737e662dd293b40578ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
41059d709d503bab6e2b61931737e662dd293b40578ccornelius}
41159d709d503bab6e2b61931737e662dd293b40578ccornelius
41259d709d503bab6e2b61931737e662dd293b40578ccornelius
413b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoUnicodeString& U_EXPORT2
4148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country, UBool *isPrimary /* = NULL */) {
4158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (isPrimary != NULL) {
4168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        *isPrimary = FALSE;
41750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
41950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *region = TimeZone::getRegion(tzid);
4208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (region != NULL && u_strcmp(gWorld, region) != 0) {
4218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        country.setTo(region, -1);
4228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    } else {
423b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        country.setToBogus();
42450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return country;
42550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
4278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (isPrimary != NULL) {
4288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        char regionBuf[] = {0, 0, 0};
4298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        // Checking the cached results
4318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        UErrorCode status = U_ZERO_ERROR;
43259d709d503bab6e2b61931737e662dd293b40578ccornelius        umtx_initOnce(gCountryInfoVectorsInitOnce, &countryInfoVectorsInit, status);
43359d709d503bab6e2b61931737e662dd293b40578ccornelius        if (U_FAILURE(status)) {
43459d709d503bab6e2b61931737e662dd293b40578ccornelius            return country;
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
4378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        // Check if it was already cached
4388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        UBool cached = FALSE;
4398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        UBool singleZone = FALSE;
4408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        umtx_lock(&gZoneMetaLock);
4418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        {
4428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            singleZone = cached = gSingleZoneCountries->contains((void*)region);
4438393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            if (!cached) {
4448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                cached = gMultiZonesCountries->contains((void*)region);
4458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            }
446c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
4478393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        umtx_unlock(&gZoneMetaLock);
448c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
4498393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (!cached) {
4508393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // We need to go through all zones associated with the region.
4518393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // This is relatively heavy operation.
45250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            U_ASSERT(u_strlen(region) == 2);
45450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4558393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            u_UCharsToChars(region, regionBuf, 2);
45650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4578393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            StringEnumeration *ids = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL_LOCATION, regionBuf, NULL, status);
4588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            int32_t idsLen = ids->count(status);
4598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            if (U_SUCCESS(status) && idsLen == 1) {
4608393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                // only the single zone is available for the region
4618393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                singleZone = TRUE;
4628393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            }
4638393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            delete ids;
4648393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // Cache the result
4668393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            umtx_lock(&gZoneMetaLock);
4678393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            {
4688393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                UErrorCode ec = U_ZERO_ERROR;
4698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                if (singleZone) {
4708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    if (!gSingleZoneCountries->contains((void*)region)) {
4718393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                        gSingleZoneCountries->addElement((void*)region, ec);
4728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    }
4738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                } else {
4748393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    if (!gMultiZonesCountries->contains((void*)region)) {
4758393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                        gMultiZonesCountries->addElement((void*)region, ec);
4768393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    }
4778393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                }
4788393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            }
4798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            umtx_unlock(&gZoneMetaLock);
48050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
48150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
4828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (singleZone) {
4838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            *isPrimary = TRUE;
4848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        } else {
4858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // Note: We may cache the primary zone map in future.
4868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // Even a country has multiple zones, one of them might be
4888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            // dominant and treated as a primary zone
4898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            int32_t idLen = 0;
4908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            if (regionBuf[0] == 0) {
4918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                u_UCharsToChars(region, regionBuf, 2);
4928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            }
4938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
4948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
4958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            ures_getByKey(rb, gPrimaryZonesTag, rb, &status);
4968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            const UChar *primaryZone = ures_getStringByKey(rb, regionBuf, &idLen, &status);
4978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            if (U_SUCCESS(status)) {
4988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                if (tzid.compare(primaryZone, idLen) == 0) {
4998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    *isPrimary = TRUE;
5008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                } else {
5018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    // The given ID might not be a canonical ID
5028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    UnicodeString canonicalID;
5038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    TimeZone::getCanonicalID(tzid, canonicalID, status);
5048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    if (U_SUCCESS(status) && canonicalID.compare(primaryZone, idLen) == 0) {
5058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                        *isPrimary = TRUE;
5068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                    }
50750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
5098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            ures_close(rb);
510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
51350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return country;
514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
51650294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
51750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) {
51850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool isSet = FALSE;
51950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UVector *mappings = getMetazoneMappings(tzid);
52050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (mappings != NULL) {
52150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        for (int32_t i = 0; i < mappings->size(); i++) {
52250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i);
52350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (mzm->from <= date && mzm->to > date) {
52450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                result.setTo(mzm->mzid, -1);
52550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                isSet = TRUE;
526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
53050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (!isSet) {
531b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        result.setToBogus();
532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
53350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return result;
534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
53659d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV olsonToMetaInit(UErrorCode &status) {
53759d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(gOlsonToMeta == NULL);
53859d709d503bab6e2b61931737e662dd293b40578ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
53959d709d503bab6e2b61931737e662dd293b40578ccornelius    gOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
54059d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
54159d709d503bab6e2b61931737e662dd293b40578ccornelius        gOlsonToMeta = NULL;
54259d709d503bab6e2b61931737e662dd293b40578ccornelius    } else {
54359d709d503bab6e2b61931737e662dd293b40578ccornelius        uhash_setKeyDeleter(gOlsonToMeta, deleteUCharString);
54459d709d503bab6e2b61931737e662dd293b40578ccornelius        uhash_setValueDeleter(gOlsonToMeta, deleteUVector);
54559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
54659d709d503bab6e2b61931737e662dd293b40578ccornelius}
54759d709d503bab6e2b61931737e662dd293b40578ccornelius
54859d709d503bab6e2b61931737e662dd293b40578ccornelius
54950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoconst UVector* U_EXPORT2
55050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
552b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UChar tzidUChars[ZID_KEY_MAX + 1];
553b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    tzid.extract(tzidUChars, ZID_KEY_MAX + 1, status);
55450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
55859d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gOlsonToMetaInitOnce, &olsonToMetaInit, status);
55959d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
56059d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
56350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // get the mapping from cache
56450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UVector *result = NULL;
565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_lock(&gZoneMetaLock);
56750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    {
56850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_unlock(&gZoneMetaLock);
571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
57250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (result != NULL) {
57350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return result;
574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
575c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
57650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // miss the cache - create new one
57750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UVector *tmpResult = createMetazoneMappings(tzid);
57850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (tmpResult == NULL) {
57950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // not available
58050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return NULL;
581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
582c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
58350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // put the new one into the cache
584c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    umtx_lock(&gZoneMetaLock);
58550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    {
58650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // make sure it's already created
58750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
58850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (result == NULL) {
58950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // add the one just created
59050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            int32_t tzidLen = tzid.length() + 1;
59150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UChar *key = (UChar*)uprv_malloc(tzidLen * sizeof(UChar));
59250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (key == NULL) {
59350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // memory allocation error..  just return NULL
59450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                result = NULL;
59550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                delete tmpResult;
59650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
59750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                tzid.extract(key, tzidLen, status);
59850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                uhash_put(gOlsonToMeta, key, tmpResult, &status);
59950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
60050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // delete the mapping
60150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    result = NULL;
60250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete tmpResult;
60350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                } else {
60450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    result = tmpResult;
60550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
60650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
60750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else {
60850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // another thread already put the one
60950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            delete tmpResult;
61050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_unlock(&gZoneMetaLock);
613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
61450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return result;
615c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
616c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
61750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUVector*
61850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
61950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UVector *mzMappings = NULL;
62050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UErrorCode status = U_ZERO_ERROR;
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
62250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UnicodeString canonicalID;
62350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
62450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, gMetazoneInfo, rb, &status);
625b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    getCanonicalCLDRID(tzid, canonicalID, status);
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
62750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_SUCCESS(status)) {
628b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        char tzKey[ZID_KEY_MAX + 1];
629b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t tzKeyLen = canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
630b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        tzKey[tzKeyLen] = 0;
63150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
63250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // tzid keys are using ':' as separators
63350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        char *p = tzKey;
63450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        while (*p) {
63550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (*p == '/') {
63650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *p = ':';
63750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
63850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            p++;
639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
64150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(rb, tzKey, rb, &status);
642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
64350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(status)) {
64450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UResourceBundle *mz = NULL;
64550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            while (ures_hasNext(rb)) {
64650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                mz = ures_getNextResource(rb, mz, &status);
647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
64850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
64950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_from = gDefaultFrom;
65050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_to = gDefaultTo;
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
65250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (ures_getSize(mz) == 3) {
65350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
65450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mz_to   = ures_getStringByIndex(mz, 2, NULL, &status);
65550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
65650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
65750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if(U_FAILURE(status)){
65850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_ZERO_ERROR;
65950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    continue;
66050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
66150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // We do not want to use SimpleDateformat to parse boundary dates,
66250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // because this code could be triggered by the initialization code
66350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // used by SimpleDateFormat.
66450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                UDate from = parseDate(mz_from, status);
66550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                UDate to = parseDate(mz_to, status);
66650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
66750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_ZERO_ERROR;
66850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    continue;
66950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
67050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
67150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
67250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (entry == NULL) {
67350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_MEMORY_ALLOCATION_ERROR;
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
67650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->mzid = mz_name;
67750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->from = from;
67850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->to = to;
67950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
68050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (mzMappings == NULL) {
68150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
68250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (U_FAILURE(status)) {
68350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        delete mzMappings;
68450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        deleteOlsonToMetaMappingEntry(entry);
68550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        uprv_free(entry);
68650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        break;
68750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
68850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
68950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
69050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                mzMappings->addElement(entry, status);
69150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
69250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    break;
69350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
69450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
69550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ures_close(mz);
69650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_FAILURE(status)) {
69750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (mzMappings != NULL) {
69850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete mzMappings;
69950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mzMappings = NULL;
70050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
70450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(rb);
70550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return mzMappings;
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
708c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString& U_EXPORT2
70950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result) {
71050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UErrorCode status = U_ZERO_ERROR;
71150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *tzid = NULL;
71250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t tzidLen = 0;
71350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    char keyBuf[ZID_KEY_MAX + 1];
71450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t keyLen = 0;
71550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
716fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (mzid.isBogus() || mzid.length() > ZID_KEY_MAX) {
717b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        result.setToBogus();
71850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return result;
719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
721b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
722b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    keyBuf[keyLen] = 0;
723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
72450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
72550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, gMapTimezonesTag, rb, &status);
72650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, keyBuf, rb, &status);
72750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
72850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_SUCCESS(status)) {
72950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // check region mapping
73050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (region.length() == 2 || region.length() == 3) {
731b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            keyLen = region.extract(0, region.length(), keyBuf, ZID_KEY_MAX + 1, US_INV);
732b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            keyBuf[keyLen] = 0;
73350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            tzid = ures_getStringByKey(rb, keyBuf, &tzidLen, &status);
73450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (status == U_MISSING_RESOURCE_ERROR) {
73550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                status = U_ZERO_ERROR;
736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
73850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(status) && tzid == NULL) {
73950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // try "001"
74050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            tzid = ures_getStringByKey(rb, gWorldTag, &tzidLen, &status);
74150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
74350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(rb);
74450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
74550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (tzid == NULL) {
746b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        result.setToBogus();
74750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
74850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result.setTo(tzid, tzidLen);
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
75050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
75459d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV initAvailableMetaZoneIDs () {
75559d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(gMetaZoneIDs == NULL);
75659d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(gMetaZoneIDTable == NULL);
75759d709d503bab6e2b61931737e662dd293b40578ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
75859d709d503bab6e2b61931737e662dd293b40578ccornelius
75959d709d503bab6e2b61931737e662dd293b40578ccornelius    UErrorCode status = U_ZERO_ERROR;
76059d709d503bab6e2b61931737e662dd293b40578ccornelius    gMetaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
76159d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status) || gMetaZoneIDTable == NULL) {
76259d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDTable = NULL;
76359d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
76459d709d503bab6e2b61931737e662dd293b40578ccornelius    }
76559d709d503bab6e2b61931737e662dd293b40578ccornelius    uhash_setKeyDeleter(gMetaZoneIDTable, uprv_deleteUObject);
76659d709d503bab6e2b61931737e662dd293b40578ccornelius    // No valueDeleter, because the vector maintain the value objects
76759d709d503bab6e2b61931737e662dd293b40578ccornelius    gMetaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
76859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status) || gMetaZoneIDs == NULL) {
76959d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDs = NULL;
77059d709d503bab6e2b61931737e662dd293b40578ccornelius        uhash_close(gMetaZoneIDTable);
77159d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDTable = NULL;
77259d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
77359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
77459d709d503bab6e2b61931737e662dd293b40578ccornelius    gMetaZoneIDs->setDeleter(uprv_free);
77559d709d503bab6e2b61931737e662dd293b40578ccornelius
77659d709d503bab6e2b61931737e662dd293b40578ccornelius    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
77759d709d503bab6e2b61931737e662dd293b40578ccornelius    UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
77859d709d503bab6e2b61931737e662dd293b40578ccornelius    UResourceBundle res;
77959d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_initStackObject(&res);
78059d709d503bab6e2b61931737e662dd293b40578ccornelius    while (U_SUCCESS(status) && ures_hasNext(bundle)) {
78159d709d503bab6e2b61931737e662dd293b40578ccornelius        ures_getNextResource(bundle, &res, &status);
78259d709d503bab6e2b61931737e662dd293b40578ccornelius        if (U_FAILURE(status)) {
78359d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
784b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
78559d709d503bab6e2b61931737e662dd293b40578ccornelius        const char *mzID = ures_getKey(&res);
78659d709d503bab6e2b61931737e662dd293b40578ccornelius        int32_t len = uprv_strlen(mzID);
78759d709d503bab6e2b61931737e662dd293b40578ccornelius        UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
78859d709d503bab6e2b61931737e662dd293b40578ccornelius        if (uMzID == NULL) {
78959d709d503bab6e2b61931737e662dd293b40578ccornelius            status = U_MEMORY_ALLOCATION_ERROR;
79059d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
79159d709d503bab6e2b61931737e662dd293b40578ccornelius        }
79259d709d503bab6e2b61931737e662dd293b40578ccornelius        u_charsToUChars(mzID, uMzID, len);
79359d709d503bab6e2b61931737e662dd293b40578ccornelius        uMzID[len] = 0;
79459d709d503bab6e2b61931737e662dd293b40578ccornelius        UnicodeString *usMzID = new UnicodeString(uMzID);
79559d709d503bab6e2b61931737e662dd293b40578ccornelius        if (uhash_get(gMetaZoneIDTable, usMzID) == NULL) {
79659d709d503bab6e2b61931737e662dd293b40578ccornelius            gMetaZoneIDs->addElement((void *)uMzID, status);
79759d709d503bab6e2b61931737e662dd293b40578ccornelius            uhash_put(gMetaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
79859d709d503bab6e2b61931737e662dd293b40578ccornelius        } else {
79959d709d503bab6e2b61931737e662dd293b40578ccornelius            uprv_free(uMzID);
80059d709d503bab6e2b61931737e662dd293b40578ccornelius            delete usMzID;
80159d709d503bab6e2b61931737e662dd293b40578ccornelius        }
80259d709d503bab6e2b61931737e662dd293b40578ccornelius    }
80359d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_close(&res);
80459d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_close(bundle);
80559d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_close(rb);
80659d709d503bab6e2b61931737e662dd293b40578ccornelius
80759d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
80859d709d503bab6e2b61931737e662dd293b40578ccornelius        uhash_close(gMetaZoneIDTable);
80959d709d503bab6e2b61931737e662dd293b40578ccornelius        delete gMetaZoneIDs;
81059d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDTable = NULL;
81159d709d503bab6e2b61931737e662dd293b40578ccornelius        gMetaZoneIDs = NULL;
812b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
813b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
814b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
815b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UVector*
816b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::getAvailableMetazoneIDs() {
81759d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs);
818b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return gMetaZoneIDs;
819b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
820b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
821b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar*
822b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::findMetaZoneID(const UnicodeString& mzid) {
82359d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs);
82459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (gMetaZoneIDTable == NULL) {
82559d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
82659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
827b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return (const UChar*)uhash_get(gMetaZoneIDTable, &mzid);
828b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
829b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
830b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoconst UChar*
831b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoZoneMeta::findTimeZoneID(const UnicodeString& tzid) {
832b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return TimeZone::findID(tzid);
833b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
834b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
835103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
836103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusTimeZone*
837103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusZoneMeta::createCustomTimeZone(int32_t offset) {
838103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UBool negative = FALSE;
839103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t tmp = offset;
840103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (offset < 0) {
841103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        negative = TRUE;
842103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        tmp = -offset;
843103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
844103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    int32_t hour, min, sec;
845103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
846103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    tmp /= 1000;
847103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    sec = tmp % 60;
848103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    tmp /= 60;
849103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    min = tmp % 60;
850103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    hour = tmp / 60;
851103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
852103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UnicodeString zid;
853103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    formatCustomID(hour, min, sec, negative, zid);
854103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return new SimpleTimeZone(offset, zid);
855103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
856103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
857103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusUnicodeString&
858103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusZoneMeta::formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id) {
859103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    // Create normalized time zone ID - GMT[+|-]HH:mm[:ss]
860103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    id.setTo(gCustomTzPrefix, -1);
861103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (hour != 0 || min != 0) {
862103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (negative) {
86354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius          id.append((UChar)0x2D);    // '-'
864103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else {
86554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius          id.append((UChar)0x2B);    // '+'
866103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
867103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        // Always use US-ASCII digits
86854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        id.append((UChar)(0x30 + (hour%100)/10));
86954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        id.append((UChar)(0x30 + (hour%10)));
87054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        id.append((UChar)0x3A);    // ':'
87154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        id.append((UChar)(0x30 + (min%100)/10));
87254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        id.append((UChar)(0x30 + (min%10)));
873103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (sec != 0) {
87454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius          id.append((UChar)0x3A);    // ':'
87554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius          id.append((UChar)(0x30 + (sec%100)/10));
87654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius          id.append((UChar)(0x30 + (sec%10)));
877103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        }
878103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
879103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return id;
880103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
881103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
8828393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusconst UChar*
8838393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusZoneMeta::getShortID(const TimeZone& tz) {
8848393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UChar* canonicalID = NULL;
8858393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL) {
8868393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        // short cut for OlsonTimeZone
8878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        const OlsonTimeZone *otz = (const OlsonTimeZone*)&tz;
8888393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        canonicalID = otz->getCanonicalID();
8898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
8908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (canonicalID == NULL) {
8918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return NULL;
8928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
8938393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return getShortIDFromCanonical(canonicalID);
8948393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
8958393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
8968393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusconst UChar*
8978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusZoneMeta::getShortID(const UnicodeString& id) {
8988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode status = U_ZERO_ERROR;
8998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(id, status);
9008393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    if (U_FAILURE(status) || canonicalID == NULL) {
9018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        return NULL;
9028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return ZoneMeta::getShortIDFromCanonical(canonicalID);
9048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
9058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9068393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusconst UChar*
9078393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusZoneMeta::getShortIDFromCanonical(const UChar* canonicalID) {
9088393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    const UChar* shortID = NULL;
9098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    int32_t len = u_strlen(canonicalID);
9108393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    char tzidKey[ZID_KEY_MAX + 1];
9118393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9128393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    u_UCharsToChars(canonicalID, tzidKey, len);
9138393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    tzidKey[len] = (char) 0; // Make sure it is null terminated.
9148393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    // replace '/' with ':'
9168393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    char *p = tzidKey;
9178393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    while (*p++) {
9188393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        if (*p == '/') {
9198393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius            *p = ':';
9208393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        }
9218393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    }
9228393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9238393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UErrorCode status = U_ZERO_ERROR;
9248393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UResourceBundle *rb = ures_openDirect(NULL, gKeyTypeData, &status);
9258393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ures_getByKey(rb, gTypeMapTag, rb, &status);
9268393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ures_getByKey(rb, gTimezoneTag, rb, &status);
9278393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    shortID = ures_getStringByKey(rb, tzidKey, NULL, &status);
9288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    ures_close(rb);
9298393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
9308393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    return shortID;
9318393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
932103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
936