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