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
22const char* BTimeZone::kNameOfGmtZone = "GMT";
23
24
25static const BString skEmptyString;
26
27
28static const uint32 skNameField 					= 1U << 0;
29static const uint32 skDaylightSavingNameField 		= 1U << 1;
30static const uint32 skShortNameField 				= 1U << 2;
31static const uint32 skShortDaylightSavingNameField 	= 1U << 3;
32static const uint32 skLongGenericNameField 			= 1U << 4;
33static const uint32 skGenericLocationNameField 		= 1U << 5;
34static const uint32 skShortCommonlyUsedNameField	= 1U << 6;
35static const uint32 skSupportsDaylightSavingField   = 1U << 7;
36static const uint32 skOffsetFromGMTField			= 1U << 8;
37
38
39BTimeZone::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
50BTimeZone::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
71BTimeZone::~BTimeZone()
72{
73	delete fICULocale;
74	delete fICUTimeZone;
75}
76
77
78BTimeZone& 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
101const BString&
102BTimeZone::ID() const
103{
104	return fZoneID;
105}
106
107
108const BString&
109BTimeZone::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
129const BString&
130BTimeZone::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
150const BString&
151BTimeZone::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
170const BString&
171BTimeZone::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
190int
191BTimeZone::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
213bool
214BTimeZone::SupportsDaylightSaving() const
215{
216	if ((fInitializedFields & skSupportsDaylightSavingField) == 0) {
217		fSupportsDaylightSaving = fICUTimeZone->useDaylightTime();
218		fInitializedFields |= skSupportsDaylightSavingField;
219	}
220
221	return fSupportsDaylightSaving;
222}
223
224
225status_t
226BTimeZone::InitCheck() const
227{
228	return fInitStatus;
229}
230
231
232status_t
233BTimeZone::SetLanguage(const BLanguage* language)
234{
235	return SetTo(fZoneID, language);
236}
237
238
239status_t
240BTimeZone::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