xref: /haiku/src/kits/locale/TimeZone.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
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