Merge "Refactoy Locales for DateTimeFormatter." into devel_3.0_main
[platform/framework/native/appfw.git] / src / locales / FLcl_TimeZoneImpl.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 /**
18  * @file            FLcl_TimeZoneImpl.cpp
19  * @brief           This is the implementation file for _TimeZoneImpl class.
20  */
21
22 #include <unique_ptr.h>
23 #include <unicode/timezone.h>
24 #include <unicode/basictz.h>
25 #include <unicode/simpletz.h>
26
27 #include <FBaseInteger.h>
28 #include <FBaseSysLog.h>
29 #include <FLclTimeZone.h>
30
31 #include "FLcl_LocaleData.h"
32 #include "FLcl_TimeZoneImpl.h"
33
34 typedef U_ICU_NAMESPACE::TimeZone IcuTimeZone;
35 typedef U_ICU_NAMESPACE::BasicTimeZone IcuBasicTimeZone;
36 typedef U_ICU_NAMESPACE::SimpleTimeZone IcuSimpleTimeZone;
37 typedef U_ICU_NAMESPACE::InitialTimeZoneRule IcuInitialTimeZoneRule;
38 typedef U_ICU_NAMESPACE::AnnualTimeZoneRule IcuAnnualTimeZoneRule;
39 typedef U_ICU_NAMESPACE::DateTimeRule IcuDateTimeRule;
40
41 enum DstRuleMode
42 {
43         EXACT_DAY = 0,
44         DAY_OF_WEEK_IN_MONTH,
45         AFTER_THE_SPECIFIED_DAY,
46         BEFORE_THE_SPECIFIED_DAY,
47         BACKWARD_FROM_END_OF_MONTH
48 };
49
50 using namespace Tizen::Base;
51
52 namespace Tizen { namespace Locales
53 {
54
55 _TimeZoneImpl::_TimeZoneImpl(void)
56         : __icuTimeZone(0, "")
57         , __dstStartingYear(0)
58         , __startingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
59         , __endingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
60 {
61
62 }
63
64 _TimeZoneImpl::_TimeZoneImpl(int rawOffset, const String& id)
65         : __icuTimeZone(rawOffset * ONE_MIN_IN_MILLISEC, _LocaleData::GetIcuString(id))
66         , __dstStartingYear(0)
67         , __startingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
68         , __endingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
69 {
70
71 }
72
73 _TimeZoneImpl::_TimeZoneImpl(int rawOffset, const String& id, const TimeRule& startRule, const TimeRule& endRule, int dstOffset)
74         : __icuTimeZone(rawOffset * ONE_MIN_IN_MILLISEC, _LocaleData::GetIcuString(id))
75         , __dstStartingYear(0)
76         , __startingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
77         , __endingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
78 {
79         SetDstRules(startRule, endRule, dstOffset);
80 }
81
82 _TimeZoneImpl::_TimeZoneImpl(const _TimeZoneImpl& otherTimeZone)
83         : __icuTimeZone(otherTimeZone.__icuTimeZone)
84         , __dstStartingYear(otherTimeZone.__dstStartingYear)
85         , __startingRule(otherTimeZone.__startingRule)
86         , __endingRule(otherTimeZone.__endingRule)
87 {
88 }
89
90 _TimeZoneImpl::_TimeZoneImpl(U_ICU_NAMESPACE::TimeZone& icuTimeZone)
91         : __icuTimeZone(0, "")
92         , __dstStartingYear(0)
93         , __startingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
94         , __endingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
95 {
96         U_ICU_NAMESPACE::UnicodeString id;
97         __icuTimeZone.setID(icuTimeZone.getID(id));
98         __icuTimeZone.setRawOffset(icuTimeZone.getRawOffset());
99 }
100
101 _TimeZoneImpl::_TimeZoneImpl(U_ICU_NAMESPACE::TimeZone& icuTimeZone, UDate icuDate)
102         : __icuTimeZone(0, "")
103         , __dstStartingYear(0)
104         , __startingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
105         , __endingRule(MONTH_UNDEFINED, DAY_UNDEFINED)
106 {
107         U_ICU_NAMESPACE::UnicodeString id;
108         __icuTimeZone.setID(icuTimeZone.getID(id));
109         __icuTimeZone.setRawOffset(icuTimeZone.getRawOffset());
110
111         U_ICU_NAMESPACE::BasicTimeZone* pIcuTz = dynamic_cast<U_ICU_NAMESPACE::BasicTimeZone*>(&icuTimeZone);
112         if (pIcuTz)
113         {
114                 TimeRule startingRule(MONTH_UNDEFINED, DAY_UNDEFINED);
115                 TimeRule endingRule(MONTH_UNDEFINED, DAY_UNDEFINED);
116
117                 int dstSaving = 0;
118                 UErrorCode status = U_ZERO_ERROR;
119                 U_ICU_NAMESPACE::InitialTimeZoneRule* pInitial = null;
120                 U_ICU_NAMESPACE::AnnualTimeZoneRule* pStd = null;
121                 U_ICU_NAMESPACE::AnnualTimeZoneRule* pDst = null;
122                 pIcuTz->getSimpleRulesNear(icuDate, pInitial, pStd, pDst, status);
123                 if (pStd && pDst)
124                 {
125                         result r = GetTimeRuleFromIcuDateTimeRule(pDst->getRule(), startingRule);
126                         if (r == E_SUCCESS)
127                         {
128                                 dstSaving = pIcuTz->getDSTSavings() / ONE_MIN_IN_MILLISEC;
129                                 GetTimeRuleFromIcuDateTimeRule(pStd->getRule(), endingRule);
130                         }
131
132                         int dstStartingYear = pDst->getStartYear();
133                         SetDstStartingYear(dstStartingYear);
134                 }
135
136                 delete pInitial;
137                 delete pStd;
138                 delete pDst;
139                 SetDstRules(startingRule, endingRule, dstSaving);
140         }
141 }
142
143 _TimeZoneImpl*
144 _TimeZoneImpl::CloneN(void)
145 {
146         return new (std::nothrow) _TimeZoneImpl(*this);
147 }
148
149 _TimeZoneImpl&
150 _TimeZoneImpl::operator =(const _TimeZoneImpl& otherTimeZone)
151 {
152         if (*this != otherTimeZone)
153         {
154                 __icuTimeZone = otherTimeZone.__icuTimeZone;
155                 __dstStartingYear = otherTimeZone.__dstStartingYear;
156                 __startingRule = otherTimeZone.__startingRule;
157                 __endingRule = otherTimeZone.__endingRule;
158         }
159         return *this;
160 }
161
162 _TimeZoneImpl::~_TimeZoneImpl(void)
163 {
164
165 }
166
167 U_ICU_NAMESPACE::SimpleTimeZone
168 _TimeZoneImpl::GetIcuTimeZone(void) const
169 {
170         return __icuTimeZone;
171 }
172
173
174 bool
175 _TimeZoneImpl::operator ==(const _TimeZoneImpl& otherTimeZone) const
176 {
177         return __icuTimeZone == otherTimeZone.__icuTimeZone;
178 }
179
180 bool
181 _TimeZoneImpl::operator !=(const _TimeZoneImpl& otherTimeZone) const
182 {
183         return !(*this == otherTimeZone);
184 }
185
186 bool
187 _TimeZoneImpl::Equals(const Object& obj) const
188 {
189         const _TimeZoneImpl* pTimeZoneImpl = dynamic_cast<const _TimeZoneImpl*>(&obj);
190         if (pTimeZoneImpl)
191         {
192                 return (*this == *pTimeZoneImpl);
193         }
194         return false;
195 }
196
197 int
198 _TimeZoneImpl::GetHashCode(void) const
199 {
200         int hashCode = GetId().GetHashCode();
201         Integer intValues = GetRawOffset() + GetDstSavings() + GetDstStartingYear() + IsDstUsed();
202         hashCode = (hashCode << 5) - hashCode + intValues.GetHashCode();
203         hashCode = (hashCode << 5) - hashCode + __startingRule.GetHashCode();
204         hashCode = (hashCode << 5) - hashCode + __endingRule.GetHashCode();
205
206         return hashCode;
207 }
208
209 String
210 _TimeZoneImpl::GetId(void) const
211 {
212         U_ICU_NAMESPACE::UnicodeString icuStr;
213         return _LocaleData::GetOspString(__icuTimeZone.getID(icuStr));
214 }
215
216 void
217 _TimeZoneImpl::SetId(const String& id)
218 {
219         U_ICU_NAMESPACE::UnicodeString icuStr = _LocaleData::GetIcuString(id);
220         __icuTimeZone.setID(icuStr);
221 }
222
223 int
224 _TimeZoneImpl::GetRawOffset(void) const
225 {
226         return __icuTimeZone.getRawOffset() / ONE_MIN_IN_MILLISEC;
227 }
228
229 void
230 _TimeZoneImpl::SetRawOffset(int rawOffset)
231 {
232         __icuTimeZone.setRawOffset(rawOffset * ONE_MIN_IN_MILLISEC);
233 }
234
235 int
236 _TimeZoneImpl::GetDstStartingYear(void) const
237 {
238         return __dstStartingYear;
239 }
240
241 void
242 _TimeZoneImpl::SetDstStartingYear(int year)
243 {
244         __dstStartingYear = year;
245         __icuTimeZone.setStartYear(year);
246 }
247
248 int
249 _TimeZoneImpl::GetDstSavings(void) const
250 {
251         return __icuTimeZone.getDSTSavings() / ONE_MIN_IN_MILLISEC;
252 }
253
254 void
255 _TimeZoneImpl::SetDstSavings(int dstSavings)
256 {
257         UErrorCode ec = U_ZERO_ERROR;
258         __icuTimeZone.setDSTSavings(dstSavings * ONE_MIN_IN_MILLISEC, ec);
259 }
260
261 const TimeRule*
262 _TimeZoneImpl::GetDstStartingRule(void) const
263 {
264         return __startingRule.GetMonth() != MONTH_UNDEFINED ? &__startingRule : null;
265 }
266
267 void
268 _TimeZoneImpl::SetDstStartingRule(const TimeRule& startRule)
269 {
270         int month = 0;
271         int dayOfWeekInMonth = 0;
272         int dayOfWeek = 0;
273         int time = 0;
274         int mode = 0;
275
276         UErrorCode ec = U_ZERO_ERROR;
277         GetIcuTimeRuleValue(startRule, month, dayOfWeekInMonth, dayOfWeek, time, mode);
278
279         U_ICU_NAMESPACE::SimpleTimeZone::TimeMode timeMode = static_cast<U_ICU_NAMESPACE::SimpleTimeZone::TimeMode> (mode);
280         __icuTimeZone.setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, timeMode, ec);
281         __startingRule = startRule;
282 }
283
284 const TimeRule*
285 _TimeZoneImpl::GetDstEndingRule(void) const
286 {
287         return __endingRule.GetMonth() != MONTH_UNDEFINED ? &__endingRule : null;
288 }
289
290 void
291 _TimeZoneImpl::SetDstEndingRule(const TimeRule& endRule)
292 {
293         int month = 0;
294         int dayOfWeekInMonth = 0;
295         int dayOfWeek = 0;
296         int time = 0;
297         int mode = 0;
298
299         UErrorCode ec = U_ZERO_ERROR;
300         GetIcuTimeRuleValue(endRule, month, dayOfWeekInMonth, dayOfWeek, time, mode);
301
302         U_ICU_NAMESPACE::SimpleTimeZone::TimeMode timeMode = static_cast<U_ICU_NAMESPACE::SimpleTimeZone::TimeMode> (mode);
303         __icuTimeZone.setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, timeMode, ec);
304         __endingRule = endRule;
305 }
306
307 result
308 _TimeZoneImpl::SetDstRules(const TimeRule& startRule, const TimeRule& endRule, int dstSavings)
309 {
310         SysTryReturnResult(NID_LCL, dstSavings >= 0,
311                         E_OUT_OF_RANGE, "dstSavings [%d] should be greater or equal to than 0", dstSavings);
312         SysTryReturnResult(NID_LCL, dstSavings < ONE_DAY_IN_MINUTE,
313                         E_OUT_OF_RANGE, "dstSavings [%d] should be greater than %d", dstSavings, ONE_DAY_IN_MINUTE);
314         SetDstStartingRule(startRule);
315         SetDstEndingRule(endRule);
316         SetDstSavings(dstSavings);
317         return E_SUCCESS;
318 }
319
320 result
321 _TimeZoneImpl::GetOffset(const DateTime& date, bool local, int& rawOffset, int& dstOffset) const
322 {
323         UErrorCode ec = U_ZERO_ERROR;
324         __icuTimeZone.getOffset(_LocaleData::GetIcuDate(date), local, rawOffset, dstOffset, ec);
325         rawOffset /= ONE_MIN_IN_MILLISEC;
326         dstOffset /= ONE_MIN_IN_MILLISEC;
327         return U_SUCCESS(ec) ? E_SUCCESS : E_INVALID_ARG;
328 }
329
330 result
331 _TimeZoneImpl::GetOffset(long long ticks, int& offset) const
332 {
333         TimeSpan ts(ticks);
334         DateTime date;
335         date.SetValue(ts.GetTicks());
336
337         int rawOffset = 0;
338         int dstOffset = 0;
339         UErrorCode ec = U_ZERO_ERROR;
340         __icuTimeZone.getOffset(_LocaleData::GetIcuDate(date), false, rawOffset, dstOffset, ec);
341         offset = (rawOffset + dstOffset) / ONE_MIN_IN_MILLISEC;
342         return U_SUCCESS(ec) ? E_SUCCESS : E_INVALID_ARG;
343 }
344
345 bool
346 _TimeZoneImpl::IsDstUsed(void) const
347 {
348         return __icuTimeZone.useDaylightTime();
349 }
350
351 const _TimeZoneImpl*
352 _TimeZoneImpl::GetTimeZoneImpl(const TimeZone& ospTimeZone)
353 {
354         return ospTimeZone.__pTimeZoneImpl;
355 }
356
357 result
358 _TimeZoneImpl::GetTimeZone(const String& id, Tizen::Locales::TimeZone& timeZone)
359 {
360         U_ICU_NAMESPACE::UnicodeString icuStr = _LocaleData::GetIcuString(id);
361         std::unique_ptr<U_ICU_NAMESPACE::TimeZone> pIcuTimeZone(U_ICU_NAMESPACE::TimeZone::createTimeZone(icuStr));
362         SysTryReturnResult(NID_LCL, pIcuTimeZone != null, E_INVALID_ARG, "Unable to create ICU timezone");
363
364         U_ICU_NAMESPACE::UnicodeString retIcuStr;
365         SysTryReturnResult(NID_LCL, pIcuTimeZone->getID(retIcuStr) == icuStr,
366                                 E_INVALID_ARG, "Unsupported timezone id [%ls]", id.GetPointer());
367
368         U_ICU_NAMESPACE::SimpleTimeZone icuTimeZone(pIcuTimeZone->getRawOffset(), icuStr);
369         std::unique_ptr<_TimeZoneImpl> pTimeZoneImpl(new (std::nothrow) _TimeZoneImpl(icuTimeZone));
370         if (pTimeZoneImpl)
371         {
372                 delete timeZone.__pTimeZoneImpl;
373                 timeZone.__pTimeZoneImpl = pTimeZoneImpl.release();
374                 return E_SUCCESS;
375         }
376
377         return E_INVALID_ARG;
378 }
379
380 result
381 _TimeZoneImpl::GetTimeZone(const String& id, const DateTime& utcTime, Tizen::Locales::TimeZone& timeZone)
382 {
383         U_ICU_NAMESPACE::UnicodeString icuStr = _LocaleData::GetIcuString(id);
384         std::unique_ptr<U_ICU_NAMESPACE::TimeZone> pIcuTimeZone(U_ICU_NAMESPACE::TimeZone::createTimeZone(icuStr));
385         SysTryReturnResult(NID_LCL, pIcuTimeZone != null, E_INVALID_ARG, "Unable to create ICU timezone");
386
387         U_ICU_NAMESPACE::UnicodeString retIcuStr;
388         SysTryReturnResult(NID_LCL, pIcuTimeZone->getID(retIcuStr) == icuStr,
389                                 E_INVALID_ARG, "Unsupported timezone id [%ls]", id.GetPointer());
390
391         std::unique_ptr<_TimeZoneImpl> pTimeZoneImpl(new (std::nothrow) _TimeZoneImpl(*pIcuTimeZone, _LocaleData::GetIcuDate(utcTime)));
392         if (pTimeZoneImpl)
393         {
394                 delete timeZone.__pTimeZoneImpl;
395                 timeZone.__pTimeZoneImpl = pTimeZoneImpl.release();
396                 return E_SUCCESS;
397         }
398
399         return E_INVALID_ARG;
400 }
401
402 void
403 _TimeZoneImpl::GetIcuTimeRuleValue(const TimeRule& ospRule, int& month, int& dayOfWeekInMonth, int& dayOfWeek, int& time, int& mode)
404 {
405         if (ospRule.GetMonth() != MONTH_UNDEFINED)
406         {
407                 month = ospRule.GetMonth() - 1;
408
409                 int ospDay = ospRule.GetDay();
410                 dayOfWeekInMonth = (ospDay == TimeRule::DAY_UNDEFINED)? 0 : ospDay;
411
412                 int ospDayOfWeek =  ospRule.GetDayOfWeek();
413                 dayOfWeek = (ospDayOfWeek == WEEK_UNDEFINED)? 0 : ospDayOfWeek;
414
415                 time = ospRule.GetHour() * ONE_HOUR_IN_MILLISEC + ospRule.GetMinute() * ONE_MIN_IN_MILLISEC;
416
417                 int ospTimeMode = ospRule.GetTimeMode();
418                 mode = IcuDateTimeRule::WALL_TIME;
419                 if (ospTimeMode == Tizen::System::TIME_MODE_UTC)
420                 {
421                         mode = IcuDateTimeRule::UTC_TIME;
422                 }
423
424                 if (ospTimeMode == Tizen::System::TIME_MODE_STANDARD)
425                 {
426                         mode = IcuDateTimeRule::STANDARD_TIME;
427                 }
428
429                 switch (ospRule.GetRuleMode())
430                 {
431                 case EXACT_DAY:
432                 case BACKWARD_FROM_END_OF_MONTH:
433                         dayOfWeek = 0;
434                         break;
435                 case DAY_OF_WEEK_IN_MONTH:
436                         dayOfWeekInMonth = ospRule.GetWeek();
437                         if (dayOfWeekInMonth < 0)
438                         {
439                                 ++dayOfWeekInMonth;
440                         }
441                         break;
442                 case AFTER_THE_SPECIFIED_DAY:
443                 case BEFORE_THE_SPECIFIED_DAY:
444                         dayOfWeekInMonth *= ospRule.IsOnOrAfterDay()? 1 : -1;
445                         dayOfWeek = -dayOfWeek;
446                         break;
447                 }
448         }
449 }
450
451 result
452 _TimeZoneImpl::GetTimeRuleFromIcuDateTimeRule(const U_ICU_NAMESPACE::DateTimeRule* pIcuRule, TimeRule& ospRule)
453 {
454         if (pIcuRule)
455         {
456                 Month month = MONTH_UNDEFINED;
457                 int icuMonth = pIcuRule->getRuleMonth();
458                 if (icuMonth >= 0 && icuMonth <= 11)
459                 {
460                         month = static_cast< Month > (icuMonth + 1);
461                 }
462
463                 IcuDateTimeRule::DateRuleType dateRuleType = pIcuRule->getDateRuleType();
464                 int day = (dateRuleType == IcuDateTimeRule::DOW)? TimeRule::DAY_UNDEFINED : pIcuRule->getRuleDayOfMonth();
465
466                 Week week = WEEK_UNDEFINED;
467                 int icuWeek = pIcuRule->getRuleWeekInMonth();
468                 if (dateRuleType == IcuDateTimeRule::DOW)
469                 {
470                         week = (icuWeek == -1)? LAST_WEEK : static_cast< Week >(icuWeek);
471                 }
472
473                 DayOfWeek dayOfWeek = DAY_OF_WEEK_UNDEFINED;
474                 if (dateRuleType != IcuDateTimeRule::DOM)
475                 {
476                         dayOfWeek = static_cast< DayOfWeek >(pIcuRule->getRuleDayOfWeek());
477                 }
478
479                 bool onOrAfterDay = (dateRuleType == IcuDateTimeRule::DOW_LEQ_DOM)? false : true;
480
481                 int ruleMID = pIcuRule->getRuleMillisInDay();
482                 int hour = ruleMID / ONE_HOUR_IN_MILLISEC;
483                 int minute = (ruleMID % ONE_HOUR_IN_MILLISEC) / ONE_MIN_IN_MILLISEC;
484
485                 Tizen::System::TimeMode timeMode = Tizen::System::TIME_MODE_WALL;
486                 IcuDateTimeRule::TimeRuleType timeRuleType = pIcuRule->getTimeRuleType();
487                 if (timeRuleType == IcuDateTimeRule::UTC_TIME)
488                 {
489                         timeMode = Tizen::System::TIME_MODE_UTC;
490                 }
491
492                 if (timeRuleType == IcuDateTimeRule::STANDARD_TIME)
493                 {
494                         timeMode = Tizen::System::TIME_MODE_STANDARD;
495                 }
496
497                 ospRule.SetValue(month, day, week, dayOfWeek, onOrAfterDay, hour, minute, timeMode);
498
499
500                 return E_SUCCESS;
501         }
502
503         return E_FAILURE;
504 }
505
506 };
507 };      // Tizen::Locales
508
509
510