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