1 /* 2 * Copyright (c) 2010, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Adrien Destugues <pulkomandy@pulkomandy.ath.cx> 7 * Oliver Tappe <zooey@hirschkaefer.de> 8 */ 9 10 11 #include <TimeZone.h> 12 13 #include <new> 14 15 #include <unicode/locid.h> 16 #include <unicode/timezone.h> 17 #include <ICUWrapper.h> 18 19 #include <Language.h> 20 21 22 const char* BTimeZone::kNameOfGmtZone = "GMT"; 23 24 25 static const BString skEmptyString; 26 27 28 static const uint32 skNameField = 1U << 0; 29 static const uint32 skDaylightSavingNameField = 1U << 1; 30 static const uint32 skShortNameField = 1U << 2; 31 static const uint32 skShortDaylightSavingNameField = 1U << 3; 32 static const uint32 skLongGenericNameField = 1U << 4; 33 static const uint32 skGenericLocationNameField = 1U << 5; 34 static const uint32 skShortCommonlyUsedNameField = 1U << 6; 35 static const uint32 skSupportsDaylightSavingField = 1U << 7; 36 static const uint32 skOffsetFromGMTField = 1U << 8; 37 38 39 BTimeZone::BTimeZone(const char* zoneID, const BLanguage* language) 40 : 41 fICUTimeZone(NULL), 42 fICULocale(NULL), 43 fInitStatus(B_NO_INIT), 44 fInitializedFields(0) 45 { 46 SetTo(zoneID, language); 47 } 48 49 50 BTimeZone::BTimeZone(const BTimeZone& other) 51 : 52 fICUTimeZone(other.fICUTimeZone == NULL 53 ? NULL 54 : other.fICUTimeZone->clone()), 55 fICULocale(other.fICULocale == NULL 56 ? NULL 57 : other.fICULocale->clone()), 58 fInitStatus(other.fInitStatus), 59 fInitializedFields(other.fInitializedFields), 60 fZoneID(other.fZoneID), 61 fName(other.fName), 62 fDaylightSavingName(other.fDaylightSavingName), 63 fShortName(other.fShortName), 64 fShortDaylightSavingName(other.fShortDaylightSavingName), 65 fOffsetFromGMT(other.fOffsetFromGMT), 66 fSupportsDaylightSaving(other.fSupportsDaylightSaving) 67 { 68 } 69 70 71 BTimeZone::~BTimeZone() 72 { 73 delete fICULocale; 74 delete fICUTimeZone; 75 } 76 77 78 BTimeZone& BTimeZone::operator=(const BTimeZone& source) 79 { 80 delete fICUTimeZone; 81 fICUTimeZone = source.fICUTimeZone == NULL 82 ? NULL 83 : source.fICUTimeZone->clone(); 84 fICULocale = source.fICULocale == NULL 85 ? NULL 86 : source.fICULocale->clone(); 87 fInitStatus = source.fInitStatus; 88 fInitializedFields = source.fInitializedFields; 89 fZoneID = source.fZoneID; 90 fName = source.fName; 91 fDaylightSavingName = source.fDaylightSavingName; 92 fShortName = source.fShortName; 93 fShortDaylightSavingName = source.fShortDaylightSavingName; 94 fOffsetFromGMT = source.fOffsetFromGMT; 95 fSupportsDaylightSaving = source.fSupportsDaylightSaving; 96 97 return *this; 98 } 99 100 101 const BString& 102 BTimeZone::ID() const 103 { 104 return fZoneID; 105 } 106 107 108 const BString& 109 BTimeZone::Name() const 110 { 111 if ((fInitializedFields & skNameField) == 0) { 112 UnicodeString unicodeString; 113 if (fICULocale != NULL) { 114 fICUTimeZone->getDisplayName(false, TimeZone::GENERIC_LOCATION, 115 *fICULocale, unicodeString); 116 } else { 117 fICUTimeZone->getDisplayName(false, TimeZone::GENERIC_LOCATION, 118 unicodeString); 119 } 120 BStringByteSink sink(&fName); 121 unicodeString.toUTF8(sink); 122 fInitializedFields |= skNameField; 123 } 124 125 return fName; 126 } 127 128 129 const BString& 130 BTimeZone::DaylightSavingName() const 131 { 132 if ((fInitializedFields & skDaylightSavingNameField) == 0) { 133 UnicodeString unicodeString; 134 if (fICULocale != NULL) { 135 fICUTimeZone->getDisplayName(true, TimeZone::GENERIC_LOCATION, 136 *fICULocale, unicodeString); 137 } else { 138 fICUTimeZone->getDisplayName(true, TimeZone::GENERIC_LOCATION, 139 unicodeString); 140 } 141 BStringByteSink sink(&fDaylightSavingName); 142 unicodeString.toUTF8(sink); 143 fInitializedFields |= skDaylightSavingNameField; 144 } 145 146 return fDaylightSavingName; 147 } 148 149 150 const BString& 151 BTimeZone::ShortName() const 152 { 153 if ((fInitializedFields & skShortNameField) == 0) { 154 UnicodeString unicodeString; 155 if (fICULocale != NULL) { 156 fICUTimeZone->getDisplayName(false, TimeZone::SHORT_COMMONLY_USED, 157 *fICULocale, unicodeString); 158 } else { 159 fICUTimeZone->getDisplayName(false, TimeZone::SHORT_COMMONLY_USED, 160 unicodeString); 161 } 162 BStringByteSink sink(&fShortName); 163 unicodeString.toUTF8(sink); 164 fInitializedFields |= skShortNameField; 165 } 166 167 return fShortName; 168 } 169 170 171 const BString& 172 BTimeZone::ShortDaylightSavingName() const 173 { 174 if ((fInitializedFields & skShortDaylightSavingNameField) == 0) { 175 UnicodeString unicodeString; 176 if (fICULocale != NULL) { 177 fICUTimeZone->getDisplayName(true, TimeZone::SHORT_COMMONLY_USED, 178 *fICULocale, unicodeString); 179 } else { 180 fICUTimeZone->getDisplayName(true, TimeZone::SHORT_COMMONLY_USED, 181 unicodeString); 182 } 183 BStringByteSink sink(&fShortDaylightSavingName); 184 unicodeString.toUTF8(sink); 185 fInitializedFields |= skShortDaylightSavingNameField; 186 } 187 188 return fShortDaylightSavingName; 189 } 190 191 192 int 193 BTimeZone::OffsetFromGMT() const 194 { 195 if ((fInitializedFields & skOffsetFromGMTField) == 0) { 196 int32_t rawOffset; 197 int32_t dstOffset; 198 UDate nowMillis = 1000 * (double)time(NULL); 199 200 UErrorCode error = U_ZERO_ERROR; 201 fICUTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error); 202 if (!U_SUCCESS(error)) 203 fOffsetFromGMT = 0; 204 else { 205 fOffsetFromGMT = (rawOffset + dstOffset) / 1000; 206 // we want seconds, not ms (which ICU gives us) 207 } 208 fInitializedFields |= skOffsetFromGMTField; 209 } 210 211 return fOffsetFromGMT; 212 } 213 214 215 bool 216 BTimeZone::SupportsDaylightSaving() const 217 { 218 if ((fInitializedFields & skSupportsDaylightSavingField) == 0) { 219 fSupportsDaylightSaving = fICUTimeZone->useDaylightTime(); 220 fInitializedFields |= skSupportsDaylightSavingField; 221 } 222 223 return fSupportsDaylightSaving; 224 } 225 226 227 status_t 228 BTimeZone::InitCheck() const 229 { 230 return fInitStatus; 231 } 232 233 234 status_t 235 BTimeZone::SetLanguage(const BLanguage* language) 236 { 237 return SetTo(fZoneID, language); 238 } 239 240 241 status_t 242 BTimeZone::SetTo(const char* zoneID, const BLanguage* language) 243 { 244 delete fICULocale; 245 fICULocale = NULL; 246 delete fICUTimeZone; 247 fInitializedFields = 0; 248 249 if (zoneID == NULL || zoneID[0] == '\0') 250 fICUTimeZone = TimeZone::createDefault(); 251 else 252 fICUTimeZone = TimeZone::createTimeZone(zoneID); 253 254 if (fICUTimeZone == NULL) { 255 fInitStatus = B_NAME_NOT_FOUND; 256 return fInitStatus; 257 } 258 259 if (language != NULL) { 260 fICULocale = new Locale(language->Code()); 261 if (fICULocale == NULL) { 262 fInitStatus = B_NO_MEMORY; 263 return fInitStatus; 264 } 265 } 266 267 UnicodeString unicodeString; 268 fICUTimeZone->getID(unicodeString); 269 BStringByteSink sink(&fZoneID); 270 unicodeString.toUTF8(sink); 271 272 fInitStatus = B_OK; 273 274 return fInitStatus; 275 } 276