wrt-plugins-tizen_0.4.23
[framework/web/wrt-plugins-tizen.git] / src / TimeUtil / TZDate.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <Commons/Exception.h>
19 #include <unicode/timezone.h>
20 #include <unicode/vtzone.h>
21 #include <unicode/smpdtfmt.h>
22 #include "TZDate.h"
23 #include "TimeUtilTools.h"
24 #include <Logger.h>
25
26 using namespace WrtDeviceApis;
27
28 namespace DeviceAPI {
29 namespace Time {
30
31 TZDate::TZDate(const bool isNotNull)
32 {
33         LoggerD("entered");
34
35         if (isNotNull == FALSE) {
36                 myCalendar = NULL;
37         } else {
38                 UErrorCode ec = U_ZERO_ERROR;
39                 TimeUtilTools util;
40                 myCalendar = Calendar::createInstance(ec);
41
42                 if (U_SUCCESS(ec)) {
43                         util.printDate(myCalendar);
44                 }
45                 else {
46                         myCalendar = NULL;
47                         ThrowMsg(Commons::PlatformException, "Can't make to ICU Calendar");
48                 }
49         }
50 }
51
52 TZDate::TZDate(const std::string &timezone)
53 {
54         LoggerD("entered");
55
56         UErrorCode ec = U_ZERO_ERROR;
57         TimeUtilTools util;
58         myCalendar = Calendar::createInstance(util.makeTimeZone(timezone) ,ec);
59
60         if (U_SUCCESS(ec)) {
61                 TimeUtilTools util;
62                 util.printDate(myCalendar);
63                 if (!util.compareTimeZoneName(myCalendar, timezone)) {
64                         myCalendar = NULL;
65                         ThrowMsg(Commons::InvalidArgumentException, "Unsupported Timezone.");
66                 }
67         } else {
68                 myCalendar = NULL;
69                 ThrowMsg(Commons::PlatformException, "Can't make to ICU Calendar");
70         }
71
72 }
73
74 TZDate::TZDate(const TZDateProperties &properties)
75 {
76         LoggerD("entered");
77
78         TimeUtilTools util;
79         myCalendar = _makeCalendar(properties);
80         if (myCalendar != NULL) {
81                 if (!util.compareTimeZoneName(myCalendar, properties.timezone)) {
82                         delete myCalendar;
83                         myCalendar = NULL;
84                         ThrowMsg(Commons::InvalidArgumentException, "Unsupported Timezone.");
85                 }
86         } else
87                 ThrowMsg(Commons::PlatformException, "Can't make to ICU Calendar");
88 }
89
90 TZDate::~TZDate()
91 {
92         LoggerD("entered");
93
94         if (myCalendar != NULL)
95                 delete myCalendar;
96
97         myCalendar = NULL;
98 }
99
100 bool  TZDate::isNull()
101 {
102         if (myCalendar == NULL)
103                 return TRUE;
104
105         return FALSE;
106 }
107
108 Calendar *TZDate::_makeCalendar(const TZDateProperties &properties)
109 {
110         LoggerD("entered");
111         UErrorCode ec = U_ZERO_ERROR;
112         TimeUtilTools util;
113
114         Calendar *cal = NULL;
115         if (properties.timezone == "")
116                 cal = Calendar::createInstance(ec);
117         else
118                 cal = Calendar::createInstance(util.makeTimeZone(properties.timezone) ,ec);
119
120         if ((cal != NULL) && U_SUCCESS(ec)) {
121                 cal->set(util.toint32_t(properties.year), util.toint32_t(properties.month),
122                         util.toint32_t(properties.day), util.toint32_t(properties.hours), util.toint32_t(properties.minutes), util.toint32_t(properties.seconds));
123                 cal->set(UCAL_MILLISECOND, util.toint32_t(properties.milliseconds));
124                 return cal;
125         }
126
127         return NULL;
128 }
129
130 std::string TZDate::_getTimezoneName(Calendar *cal)
131 {
132         UnicodeString id;
133         TimeUtilTools util;
134
135         cal->getTimeZone().getID(id);
136         std::string s_result = util.toString(id);
137         LoggerD(s_result);
138         return s_result;
139 }
140
141 const UCalendarDateFields TZDate::_convertDateField(const TZDateFields field)
142 {
143         switch (field) {
144         case TZDATE_ERA:
145                 return UCAL_ERA;
146                 break;
147         case TZDATE_YEAR:
148                 return UCAL_YEAR;
149                 break;
150         case TZDATE_MONTH:
151                 return UCAL_MONTH;
152                 break;
153         case TZDATE_WEEK_OF_YEAR:
154                 return UCAL_WEEK_OF_YEAR;
155                 break;
156         case TZDATE_WEEK_OF_MONTH:
157                 return UCAL_WEEK_OF_MONTH;
158                 break;
159         case TZDATE_DATE:
160                 return UCAL_DATE;
161                 break;
162         case TZDATE_DAY_OF_YEAR:
163                 return UCAL_DAY_OF_YEAR;
164                 break;
165         case TZDATE_DAY_OF_WEEK:
166                 return UCAL_DAY_OF_WEEK;
167                 break;
168         case TZDATE_DAY_OF_WEEK_IN_MONTH:
169                 return UCAL_DAY_OF_WEEK_IN_MONTH;
170                 break;
171         case TZDATE_AM_PM:
172                 return UCAL_AM_PM;
173                 break;
174         case TZDATE_HOUR:
175                 return UCAL_HOUR;
176                 break;
177         case TZDATE_HOUR_OF_DAY:
178                 return UCAL_HOUR_OF_DAY;
179                 break;
180         case TZDATE_MINUTE:
181                 return UCAL_MINUTE;
182                 break;
183         case TZDATE_SECOND:
184                 return UCAL_SECOND;
185                 break;
186         case TZDATE_MILLISECOND:
187                 return UCAL_MILLISECOND;
188                 break;
189         case TZDATE_ZONE_OFFSET:
190                 return UCAL_ZONE_OFFSET;
191                 break;
192         case TZDATE_DST_OFFSET:
193                 return UCAL_DST_OFFSET;
194                 break;
195         default:
196                 return UCAL_FIELD_COUNT;
197         }
198 }
199
200 TZDateProperties TZDate::_makeProperties(Calendar *cal)
201 {
202         TZDateProperties result;
203         TimeUtilTools util;
204
205         result.year = _get(TZDATE_YEAR, cal);
206         result.month = _get(TZDATE_MONTH,cal);
207         result.day = _get(TZDATE_DATE, cal);
208         result.hours = _get(TZDATE_HOUR_OF_DAY, cal);
209         result.minutes = _get(TZDATE_MINUTE, cal);
210         result.seconds = _get(TZDATE_SECOND, cal);
211         result.milliseconds = _get(TZDATE_MILLISECOND, cal);
212         result.timezone=  _getTimezoneName(cal);
213
214         return result;
215 }
216
217 TZDateProperties TZDate::makeProperties() {
218         return _makeProperties(myCalendar);
219 }
220
221 std::string TZDate::getTimezone()
222 {
223         return _getTimezoneName(myCalendar);
224 }
225
226 TZDateProperties TZDate::toTimezone(const std::string timezone) {
227         TimeUtilTools util;
228         Calendar *newCalendar = myCalendar->clone();
229         newCalendar->setTimeZone(*(util.makeTimeZone(timezone)));
230
231         if (!util.compareTimeZoneName(newCalendar, timezone)) {
232                 delete newCalendar;
233                 ThrowMsg(Commons::InvalidArgumentException, "Unsupported Timezone.");
234         }
235
236         TZDateProperties newProps =  _makeProperties(newCalendar);
237         delete newCalendar;
238
239         return newProps;
240 }
241
242 long TZDate::_get(const TZDateFields field, Calendar *cal)
243 {
244         LoggerD("<<<");
245
246         if (_convertDateField(field) == UCAL_FIELD_COUNT){
247                 LoggerD(">>> UCAL_FIELD_COUNT");
248                 return -1;
249         }
250
251         UErrorCode ec = U_ZERO_ERROR;
252         TimeUtilTools util;
253         int32_t value = cal->get(_convertDateField(field), ec);
254         if (U_SUCCESS(ec)) {
255                 long result = util.tolong(value);
256
257                 LoggerD(">>> result:" << result);
258                 return result;
259         }
260         ThrowMsg(Commons::PlatformException, "Can't get Calendar value");
261 }
262 long TZDate::get(const TZDateFields field)
263 {
264         LoggerD("<<<");
265
266         long result = _get(field, myCalendar);
267         if (field == TZDATE_DAY_OF_WEEK)
268                 result--;
269         return result;
270 }
271
272 void TZDate::set(const TZDateFields field, const long value)
273 {
274         if (_convertDateField(field) == UCAL_FIELD_COUNT)
275                 return;
276
277         TimeUtilTools util;
278         myCalendar->set(_convertDateField(field), util.toint32_t(value));
279         LoggerD("Field : " << field << " value : " << get(field));
280 }
281
282 long TZDate::getUTC(const TZDateFields field)
283 {
284         if (_convertDateField(field) == UCAL_FIELD_COUNT)
285                 return -1;
286
287         UErrorCode ec = U_ZERO_ERROR;
288         TimeUtilTools util;
289
290         Calendar *utcCalendar = myCalendar->clone();
291         utcCalendar->setTimeZone(*(TimeZone::getGMT()));
292
293         int32_t value = utcCalendar->get(_convertDateField(field), ec);
294         delete utcCalendar;
295
296         if (U_SUCCESS(ec)) {
297                 long result = util.tolong(value);
298                 if (field == TZDATE_DAY_OF_WEEK)
299                         result--;
300                 LoggerD("result : " << result);
301
302                 return result;
303         }
304
305         ThrowMsg(Commons::PlatformException, "Can't get UTC Calendar value");
306 }
307
308 void TZDate::setUTC(const TZDateFields field, const long value)
309 {
310         if (_convertDateField(field) == UCAL_FIELD_COUNT)
311                 return;
312
313         TimeUtilTools util;
314         UErrorCode ec = U_ZERO_ERROR;
315
316         long myValue = get(field);
317         long utcValue = getUTC(field);
318         if (field == TZDATE_DAY_OF_WEEK)
319                 utcValue++;
320         set(field, myValue + value - utcValue);
321
322         if (!U_SUCCESS(ec))
323                 ThrowMsg(Commons::PlatformException, "Can't set UTC Calendar value");
324 }
325
326 long long TZDate::difference(const TZDateProperties &prop) {
327         LoggerD("entered");
328
329         TimeUtilTools util;
330         UErrorCode ec = U_ZERO_ERROR;
331
332         Calendar *otherCalendar = _makeCalendar(prop);
333
334         if (!util.compareTimeZoneName(otherCalendar, prop.timezone)) {
335                 delete otherCalendar;
336                 ThrowMsg(Commons::InvalidArgumentException, "Unsupported Timezone.");
337         }
338
339         UDate myTime = myCalendar->getTime(ec);
340
341         if (U_SUCCESS(ec)) {
342                 UDate otherTime = otherCalendar->getTime(ec);
343                 if (U_SUCCESS(ec)) {
344                         LoggerD("myCalendar");
345                         util.printDate(myCalendar);
346                         LoggerD("otherCalendar");
347                         util.printDate(otherCalendar);
348                         delete otherCalendar;
349
350                         LoggerD("myTime : " <<myTime);
351                         LoggerD("otherTime : " << otherTime);
352
353                         return static_cast<long long>(myTime - otherTime);
354                 }
355         }
356         delete otherCalendar;
357         ThrowMsg(Commons::PlatformException, "Calendar error in difference");
358 }
359
360 TZDateProperties TZDate::addDuration(const DurationProperties &duration) {
361         LoggerD("entered");
362         UErrorCode ec = U_ZERO_ERROR;
363
364         TimeUtilTools util;
365
366         Calendar *cal = myCalendar->clone();
367         long long length = duration.length;
368         short unit = duration.unit;
369         int msec=0, sec=0, min=0, hour=0;
370         long long day=0;
371
372         if (unit == MSECS_UNIT) {
373                 msec = length % 1000;
374                 length /= 1000;
375                 unit = SECONDS_UNIT;
376         }
377         if ((length != 0) && (unit == SECONDS_UNIT)) {
378                 sec = length % 60;
379                 length /= 60;
380                 unit = MINUTES_UNIT;
381         }
382         if ((length != 0) && (unit == MINUTES_UNIT)) {
383                 min = length % 60;
384                 length /= 60;
385                 unit = HOURS_UNIT;
386         }
387         if ((length != 0) && (unit == HOURS_UNIT)) {
388                 hour = length % 24;
389                 length /= 24;
390                 unit = DAYS_UNIT;
391         }
392         day = length;
393         LoggerD("day:"<<day<<" hour:"<<hour<<" min:"<<min<<" sec:"<<sec<<" msec:"<<msec);
394         try {
395                 if (msec != 0) {
396                         cal->add(UCAL_MILLISECOND, util.toint32_t(msec), ec);
397                         if (!U_SUCCESS(ec))
398                                 Throw(Commons::PlatformException);
399                 }
400                 if (sec != 0) {
401                         cal->add(UCAL_SECOND, util.toint32_t(sec), ec);
402                         if (!U_SUCCESS(ec))
403                                 Throw(Commons::PlatformException);
404                 }
405                 if (min != 0) {
406                         cal->add(UCAL_MINUTE, util.toint32_t(min), ec);
407                         if (!U_SUCCESS(ec))
408                                 Throw(Commons::PlatformException);
409                 }
410                 if (hour != 0) {
411                         cal->add(UCAL_HOUR_OF_DAY, util.toint32_t(hour), ec);
412                         if (!U_SUCCESS(ec))
413                                 Throw(Commons::PlatformException);
414                 }
415
416                 UDate oldValue = cal->getTime(ec);
417                 if (!U_SUCCESS(ec))
418                         Throw(Commons::PlatformException);
419
420                 while (day != 0) {
421                         LoggerD("1st day : " << day);
422                         int amount = 0;
423
424                         if (day < INT_MIN)
425                                 amount = INT_MIN;
426                         else if (day > INT_MAX)
427                                 amount = INT_MAX;
428                         else
429                                 amount = day;
430
431                         day -= amount;
432                         LoggerD("amount : " << amount);
433                         LoggerD("2nd day : " << day);
434                         cal->add(UCAL_DATE, util.toint32_t(amount), ec);
435                         if (!U_SUCCESS(ec))
436                                 Throw(Commons::PlatformException);
437
438                         UDate newValue = cal->getTime(ec);
439                         if (!U_SUCCESS(ec))
440                                 Throw(Commons::PlatformException);
441
442                         int diff = static_cast<int>((newValue - oldValue) / 24 / 60 / 60 / 1000);
443                         LoggerD("diff : " << diff);
444                         if (diff != amount) {
445                                 Throw(Commons::OutOfRangeException);
446                         }
447                         oldValue = newValue;
448                 } ;
449         } catch (Commons::PlatformException) {
450                 delete cal;
451                 ThrowMsg(Commons::PlatformException, "Calendar error in addDuration");
452         } catch (Commons::OutOfRangeException) {
453                 delete cal;
454                 ThrowMsg(Commons::OutOfRangeException, "The result is beyond the scope that TZDate can handle.");
455         }
456
457         TZDateProperties result = _makeProperties(cal);
458         util.printDate(cal);
459         delete cal;
460
461         if (!U_SUCCESS(ec))
462                 ThrowMsg(Commons::PlatformException, "Calendar error in addDuration");
463         return result;
464 }
465
466 std::string TZDate::getUTCTimezoneName() {
467         UnicodeString id;
468         TimeUtilTools util;
469
470         TimeZone::getGMT()->getID(id);
471         std::string s_result = util.toString(id);
472         LoggerD(s_result);
473         return s_result;
474 }
475
476 std::string TZDate::getLocalTimezoneName() {
477         UnicodeString id;
478         TimeUtilTools util;
479
480         TimeZone::createDefault()->getID(id);
481         std::string s_result = util.toString(id);
482         LoggerD(s_result);
483         return s_result;
484 }
485
486 double TZDate::getTime() {
487         LoggerD("entered");
488         UErrorCode ec = U_ZERO_ERROR;
489
490         UDate date = myCalendar->getTime(ec);
491         if (U_SUCCESS(ec))
492                 return static_cast<double>(date);
493
494         ThrowMsg(Commons::PlatformException, "can't get time");
495 }
496
497 bool TZDate::setTime(const double time) {
498         LoggerD("entered");
499         UErrorCode ec = U_ZERO_ERROR;
500
501         myCalendar->setTime(static_cast<UDate>(time), ec);
502         if (U_SUCCESS(ec))
503                 return true;
504
505         return false;
506 }
507
508  std::string TZDate::toDateString(bool bLocale)  {
509         UErrorCode ec = U_ZERO_ERROR;
510         UnicodeString str;
511         TimeUtilTools util;
512
513         DateFormat *fmt = new SimpleDateFormat(util.getDateTimeFormat(TimeUtilTools::DATE_FORMAT, bLocale), (bLocale ? Locale::getDefault() : Locale::getEnglish()), ec);
514         if (U_SUCCESS(ec)) {
515                 fmt->setCalendar(*myCalendar);
516                 fmt->format(myCalendar->getTime(ec), str);
517                 delete fmt;
518
519                 if (U_SUCCESS(ec)) {
520                         std::string result = util.toString(str);
521                         str.remove();
522
523                         LoggerD (result);
524                         return result;
525                 }
526         }
527
528         ThrowMsg(Commons::PlatformException, "can't make SimpleDateFormat or can't get time");
529  }
530
531   std::string TZDate::toTimeString(bool bLocale)  {
532         UErrorCode ec = U_ZERO_ERROR;
533         UnicodeString str;
534         TimeUtilTools util;
535
536         DateFormat *fmt = new SimpleDateFormat(util.getDateTimeFormat(TimeUtilTools::TIME_FORMAT, bLocale), (bLocale ? Locale::getDefault() : Locale::getEnglish()), ec);
537         if (U_SUCCESS(ec)) {
538                 fmt->setCalendar(*myCalendar);
539                 fmt->format(myCalendar->getTime(ec), str);
540                 delete fmt;
541
542                 if (U_SUCCESS(ec)) {
543                         std::string result = util.toString(str);
544                         str.remove();
545                         LoggerD (result);
546                         return result;
547                 }
548         }
549
550         ThrowMsg(Commons::PlatformException, "can't make SimpleDateFormat or can't get time");
551  }
552  
553  std::string TZDate::toString(bool bLocale) {
554         LoggerD("entered");
555
556         UErrorCode ec = U_ZERO_ERROR;
557         UnicodeString str;
558         TimeUtilTools util;
559
560         DateFormat *fmt = new SimpleDateFormat(util.getDateTimeFormat(TimeUtilTools::DATETIME_FORMAT, bLocale), (bLocale ? Locale::getDefault() : Locale::getEnglish()), ec);
561         if (U_SUCCESS(ec)) {
562                 fmt->setCalendar(*myCalendar);
563                 fmt->format(myCalendar->getTime(ec), str);
564                 delete fmt;
565
566                 if (U_SUCCESS(ec)) {
567                         std::string result = util.toString(str);
568                         str.remove();
569                         LoggerD (result);
570                         return result;
571                 }
572         }
573         ThrowMsg(Commons::PlatformException, "can't make SimpleDateFormat or can't get time");
574 }
575
576 std::string TZDate::getTimezoneAbbreviation() {
577         LoggerD("entered");
578
579         UErrorCode ec = U_ZERO_ERROR;
580         UnicodeString str;
581         TimeUtilTools util;
582
583         DateFormat *fmt = new SimpleDateFormat(UnicodeString("V"), Locale::getEnglish(), ec);
584         if (U_SUCCESS(ec)) {
585                 fmt->setCalendar(*myCalendar);
586                 fmt->format(myCalendar->getTime(ec), str);
587                 delete fmt;
588
589                 if (U_SUCCESS(ec)) {
590                         std::string result = util.toString(str);
591                         str.remove();
592
593                         LoggerD (result);
594
595                         return result;
596                 }
597         }
598         ThrowMsg(Commons::PlatformException, "can't make SimpleDateFormat or can't get time");
599 }
600
601 long TZDate::secondsFromUTC() {
602         LoggerD("entered");
603         UErrorCode ec = U_ZERO_ERROR;
604         TimeUtilTools util;
605
606         int32_t zoneOffset = myCalendar->get(UCAL_ZONE_OFFSET, ec);
607         if (!U_SUCCESS(ec))
608                 ThrowMsg(Commons::PlatformException, "can't get zone offset");
609
610         int32_t dstOffset = myCalendar->get(UCAL_DST_OFFSET, ec);
611         if (!U_SUCCESS(ec))
612                 ThrowMsg(Commons::PlatformException, "can't get dst offset");
613
614         long result = -((util.tolong(zoneOffset + dstOffset)) / MILLISTOSEC);
615
616         LoggerD("result : " << result);
617         return result;
618 }
619
620 bool TZDate::isDST() {
621         LoggerD("entered");
622         UErrorCode ec = U_ZERO_ERROR;
623         TimeUtilTools util;
624         UBool result = myCalendar->inDaylightTime(ec);
625
626         if (!U_SUCCESS(ec))
627                 ThrowMsg(Commons::PlatformException, "can't inDaylightTime value from ICU");
628
629         return static_cast<bool>(result);
630 }
631
632 TZDateProperties TZDate::getDSTTransition(DSTTransition trans) {
633         LoggerD("entered");
634         TimeUtilTools util;
635         UErrorCode ec = U_ZERO_ERROR;
636         TZDateProperties props;
637         UDate dstTransitionDate = myCalendar->getTime(ec);
638         UBool result = false;
639
640         if (U_SUCCESS(ec)) {
641                 UnicodeString *id = util.toUnicodeString(getTimezone());
642
643                 VTimeZone *vtz = VTimeZone::createVTimeZoneByID(*id);
644                 delete id;
645
646                 TimeZoneTransition tzTrans;
647                 if (vtz->useDaylightTime() == TRUE) {
648                         if (trans == NEXT_TRANSITION)
649                                 result = vtz->getNextTransition(dstTransitionDate, FALSE,  tzTrans);
650                         else
651                                 result = vtz->getPreviousTransition(dstTransitionDate, FALSE,  tzTrans);
652                         if (result == TRUE) {
653                                 LoggerD("result is TRUE");
654                                 dstTransitionDate = tzTrans.getTime();
655                         }
656                 }
657                 delete vtz;
658
659                 if (result == false)
660                         return props;
661
662                 Calendar *dstTransCalendar = myCalendar->clone();
663                 dstTransCalendar->setTime(dstTransitionDate, ec);
664                 if (U_SUCCESS(ec)) {
665                         props =  _makeProperties(dstTransCalendar);
666                         delete dstTransCalendar;
667                         return props;
668                 }
669                 delete dstTransCalendar;
670         }
671         ThrowMsg(Commons::PlatformException, "can't getDSTTransition value from ICU");
672 }
673
674 }
675 }