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