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, *fICULocale, 157 unicodeString); 158 } else { 159 fICUTimeZone->getDisplayName(false, TimeZone::SHORT, unicodeString); 160 } 161 BStringByteSink sink(&fShortName); 162 unicodeString.toUTF8(sink); 163 fInitializedFields |= skShortNameField; 164 } 165 166 return fShortName; 167 } 168 169 170 const BString& 171 BTimeZone::ShortDaylightSavingName() const 172 { 173 if ((fInitializedFields & skShortDaylightSavingNameField) == 0) { 174 UnicodeString unicodeString; 175 if (fICULocale != NULL) { 176 fICUTimeZone->getDisplayName(true, TimeZone::SHORT, *fICULocale, 177 unicodeString); 178 } else { 179 fICUTimeZone->getDisplayName(true, TimeZone::SHORT, unicodeString); 180 } 181 BStringByteSink sink(&fShortDaylightSavingName); 182 unicodeString.toUTF8(sink); 183 fInitializedFields |= skShortDaylightSavingNameField; 184 } 185 186 return fShortDaylightSavingName; 187 } 188 189 190 int 191 BTimeZone::OffsetFromGMT() const 192 { 193 if ((fInitializedFields & skOffsetFromGMTField) == 0) { 194 int32_t rawOffset; 195 int32_t dstOffset; 196 UDate nowMillis = 1000 * (double)time(NULL); 197 198 UErrorCode error = U_ZERO_ERROR; 199 fICUTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, error); 200 if (!U_SUCCESS(error)) 201 fOffsetFromGMT = 0; 202 else { 203 fOffsetFromGMT = (rawOffset + dstOffset) / 1000; 204 // we want seconds, not ms (which ICU gives us) 205 } 206 fInitializedFields |= skOffsetFromGMTField; 207 } 208 209 return fOffsetFromGMT; 210 } 211 212 213 bool 214 BTimeZone::SupportsDaylightSaving() const 215 { 216 if ((fInitializedFields & skSupportsDaylightSavingField) == 0) { 217 fSupportsDaylightSaving = fICUTimeZone->useDaylightTime(); 218 fInitializedFields |= skSupportsDaylightSavingField; 219 } 220 221 return fSupportsDaylightSaving; 222 } 223 224 225 status_t 226 BTimeZone::InitCheck() const 227 { 228 return fInitStatus; 229 } 230 231 232 status_t 233 BTimeZone::SetLanguage(const BLanguage* language) 234 { 235 return SetTo(fZoneID, language); 236 } 237 238 239 status_t 240 BTimeZone::SetTo(const char* zoneID, const BLanguage* language) 241 { 242 delete fICULocale; 243 fICULocale = NULL; 244 delete fICUTimeZone; 245 fInitializedFields = 0; 246 247 if (zoneID == NULL || zoneID[0] == '\0') 248 fICUTimeZone = TimeZone::createDefault(); 249 else 250 fICUTimeZone = TimeZone::createTimeZone(zoneID); 251 252 if (fICUTimeZone == NULL) { 253 fInitStatus = B_NAME_NOT_FOUND; 254 return fInitStatus; 255 } 256 257 if (language != NULL) { 258 fICULocale = new Locale(language->Code()); 259 if (fICULocale == NULL) { 260 fInitStatus = B_NO_MEMORY; 261 return fInitStatus; 262 } 263 } 264 265 UnicodeString unicodeString; 266 fICUTimeZone->getID(unicodeString); 267 BStringByteSink sink(&fZoneID); 268 unicodeString.toUTF8(sink); 269 270 fInitStatus = B_OK; 271 272 return fInitStatus; 273 } 274