Resolved Native API Reference issues for calendar-service
[platform/core/pim/calendar-service.git] / common / cal_time.cpp
1 /*
2  * Calendar Service
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <unicode/utypes.h>
24 #include <unicode/ucal.h>
25 #include <unicode/uloc.h>
26 #include <unicode/calendar.h>
27 #include <unicode/timezone.h>
28 #include <unicode/gregocal.h>
29 #include <unicode/simpletz.h>
30 #include <unicode/ustring.h>
31 #include <unicode/strenum.h>
32 #include <unicode/ustdio.h>
33 #include <unicode/udat.h>
34 #include <unicode/rbtz.h>
35 #include <unicode/uclean.h>
36 #include <pthread.h>
37
38 #include "calendar.h"
39 #include "cal_internal.h"
40 #include "cal_typedef.h"
41 #include "cal_time.h"
42 #include "cal_utils.h"
43
44 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
45 #define uprv_strncpy(dst, src, size) U_STANDARD_CPP_NAMESPACE strncpy(dst, src, size)
46
47 #define ms2sec(ms) (long long int)(ms / 1000.0)
48 #define sec2ms(s) (s * 1000.0)
49
50 static pthread_mutex_t cal_mutex_gmt = PTHREAD_MUTEX_INITIALIZER;
51 static UCalendar *_g_ucal_gmt = NULL;
52
53 void cal_time_get_registered_tzid_with_offset(int offset, char *registered_tzid, int tzid_size)
54 {
55         UErrorCode ec = U_ZERO_ERROR;
56
57         RET_IF(NULL == registered_tzid);
58
59         StringEnumeration* s = TimeZone::createEnumeration(sec2ms(offset));
60         if (0 == s->count(ec)) {
61                 DBG("No tzid of offset(%d)sec", offset);
62                 return;
63         }
64
65         const UnicodeString *unicode_tzid = s->snext(ec);
66         unicode_tzid->extract(registered_tzid, tzid_size, NULL, ec);
67         delete s;
68 }
69
70 UCalendar *cal_time_open_ucal(int calendar_system_type, const char *tzid, int wkst)
71 {
72         UChar utf16_timezone[CAL_STR_SHORT_LEN64] = {0};
73         u_uastrncpy(utf16_timezone, tzid, sizeof(utf16_timezone));
74
75         UErrorCode status = U_ZERO_ERROR;
76         UCalendar *ucal = NULL;
77
78         char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY] = {0};
79
80         switch (calendar_system_type) {
81         case CALENDAR_SYSTEM_EAST_ASIAN_LUNISOLAR:
82                 uloc_setKeywordValue("calendar", "chinese", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, &status);
83                 ucal = ucal_open(utf16_timezone, -1, localeBuf, UCAL_TRADITIONAL, &status);
84                 break;
85         default:
86                 ucal = ucal_open(utf16_timezone, -1, uloc_getDefault(), UCAL_GREGORIAN, &status);
87                 break;
88         }
89         if (U_FAILURE(status)) {
90                 /* LCOV_EXCL_START */
91                 ERR("ucal_open() Fail[%s]", u_errorName(status));
92                 return NULL;
93                 /* LCOV_EXCL_STOP */
94         }
95         if (NULL == ucal) {
96                 /* LCOV_EXCL_START */
97                 ERR("ucal_open() Fail[%s]", u_errorName(status));
98                 return NULL;
99                 /* LCOV_EXCL_STOP */
100         }
101         if (CALENDAR_SUNDAY <= wkst && wkst <= CALENDAR_SATURDAY) {
102                 DBG("set wkst(%d)", wkst);
103                 ucal_setAttribute(ucal, UCAL_FIRST_DAY_OF_WEEK, wkst);
104         }
105
106         return ucal;
107 }
108
109 char* cal_time_convert_ltos(const char *tzid, long long int lli, int is_allday)
110 {
111         int y, mon, d, h, min, s;
112         char buf[CAL_STR_SHORT_LEN32] = {0};
113         UCalendar *ucal;
114         UErrorCode status = U_ZERO_ERROR;
115
116         if (NULL == tzid) {
117                 DBG("tzid is NULL so set gmt");
118                 tzid = CAL_TZID_GMT;
119         }
120
121         ucal = cal_time_open_ucal(-1, tzid, -1);
122         if (NULL == ucal) {
123                 /* LCOV_EXCL_START */
124                 ERR("cal_time_open_ucal() Fail");
125                 return NULL;
126                 /* LCOV_EXCL_STOP */
127         }
128         ucal_setMillis(ucal, sec2ms(lli), &status);
129         if (U_FAILURE(status)) {
130                 /* LCOV_EXCL_START */
131                 ERR("ucal_setMillFail (%s)", u_errorName(status));
132                 ucal_close(ucal);
133                 return NULL;
134                 /* LCOV_EXCL_STOP */
135         }
136
137         y = ucal_get(ucal, UCAL_YEAR, &status);
138         mon = ucal_get(ucal, UCAL_MONTH, &status) + 1;
139         d = ucal_get(ucal, UCAL_DATE, &status);
140         h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
141         min = ucal_get(ucal, UCAL_MINUTE, &status);
142         s = ucal_get(ucal, UCAL_SECOND, &status);
143
144         if (CAL_STRING_EQUAL == strncmp(tzid, CAL_TZID_GMT, strlen(CAL_TZID_GMT)))
145                 snprintf(buf, sizeof(buf), CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS"%s",
146                                 y, mon, d, h, min, s, is_allday ? "" : "Z");
147         else
148                 snprintf(buf, sizeof(buf), CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, y, mon, d, h, min, s);
149
150         ucal_close(ucal);
151
152         return cal_strdup(buf);
153 }
154
155 long long int cal_time_convert_itol(const char *tzid, int y, int mon, int d, int h, int min, int s)
156 {
157         long long int lli;
158         UCalendar *ucal = NULL;
159         UErrorCode status = U_ZERO_ERROR;
160
161         ucal = cal_time_open_ucal(-1, tzid, -1);
162         if (NULL == ucal) {
163                 /* LCOV_EXCL_START */
164                 ERR("cal_time_open_ucal() Fail");
165                 return 0;
166                 /* LCOV_EXCL_STOP */
167         }
168         ucal_set(ucal, UCAL_YEAR, y);
169         ucal_set(ucal, UCAL_MONTH, mon -1);
170         ucal_set(ucal, UCAL_DATE, d);
171         ucal_set(ucal, UCAL_HOUR_OF_DAY, h);
172         ucal_set(ucal, UCAL_MINUTE, min);
173         ucal_set(ucal, UCAL_SECOND, s);
174         ucal_set(ucal, UCAL_MILLISECOND, 0);
175         lli = ms2sec(ucal_getMillis(ucal, &status));
176
177         ucal_close(ucal);
178         return lli;
179 }
180
181 long long int cal_time_get_now(void)
182 {
183         return ms2sec(ucal_getNow());
184 }
185
186 int cal_time_get_next_date(calendar_time_s *today, calendar_time_s *next)
187 {
188         RETV_IF(NULL == today, CALENDAR_ERROR_INVALID_PARAMETER);
189         RETV_IF(NULL == next, CALENDAR_ERROR_INVALID_PARAMETER);
190
191         UCalendar *ucal = NULL;
192         UErrorCode status = U_ZERO_ERROR;
193         UChar *utzid = NULL;
194         const char *tzid = CAL_TZID_GMT;
195
196         utzid = (UChar *)calloc(strlen(tzid) + 1, sizeof(UChar));
197         RETVM_IF(NULL == utzid, CALENDAR_ERROR_OUT_OF_MEMORY, "calloc() Fail");
198
199         u_uastrcpy(utzid, tzid);
200         ucal = ucal_open(utzid, u_strlen(utzid), "en_US", UCAL_TRADITIONAL, &status);
201         if (U_FAILURE(status)) {
202                 /* LCOV_EXCL_START */
203                 ERR("ucal_open() Fail(%s)", u_errorName(status));
204                 CAL_FREE(utzid);
205                 return status;
206                 /* LCOV_EXCL_STOP */
207         }
208
209         switch (today->type) {
210         case CALENDAR_TIME_UTIME:
211
212                 break;
213
214         case CALENDAR_TIME_LOCALTIME:
215                 ucal_setDateTime(ucal,
216                                 today->time.date.year,
217                                 today->time.date.month-1,
218                                 today->time.date.mday,
219                                 today->time.date.hour,
220                                 today->time.date.minute,
221                                 today->time.date.second,
222                                 &status);
223                 DBG("today %04d/%02d/%02d %02d:%02d:%02d",
224                                 today->time.date.year, today->time.date.month, today->time.date.mday,
225                                 today->time.date.hour, today->time.date.minute, today->time.date.second);
226                 ucal_add(ucal, UCAL_DAY_OF_YEAR, 1, &status);
227                 next->time.date.year = ucal_get(ucal, UCAL_YEAR, &status);
228                 next->time.date.month = ucal_get(ucal, UCAL_MONTH, &status) + 1;
229                 next->time.date.mday = ucal_get(ucal, UCAL_DATE, &status);
230                 next->time.date.hour = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
231                 next->time.date.minute = ucal_get(ucal, UCAL_MINUTE, &status);
232                 next->time.date.second = ucal_get(ucal, UCAL_SECOND, &status);
233                 DBG("next %04d/%02d/%02d %02d:%02d:%02d",
234                                 next->time.date.year, next->time.date.month, next->time.date.mday,
235                                 next->time.date.hour, next->time.date.minute, next->time.date.second);
236                 break;
237         }
238
239         CAL_FREE(utzid);
240
241         return CALENDAR_ERROR_NONE;
242 }
243
244 void cal_time_u_cleanup(void)
245 {
246         u_cleanup();
247 }
248
249 void cal_time_get_tz_offset(const char *tz, time_t *zone_offset, time_t *dst_offset)
250 {
251         UErrorCode status = U_ZERO_ERROR;
252         UCalendar *ucal = NULL;
253
254         ucal = cal_time_open_ucal(-1, tz, -1);
255         if (NULL == ucal) {
256                 /* LCOV_EXCL_START */
257                 ERR("cal_time_open_ucal() Fail");
258                 return;
259                 /* LCOV_EXCL_STOP */
260         }
261         int32_t zone = ucal_get(ucal, UCAL_ZONE_OFFSET, &status);
262         int32_t dst = ucal_get(ucal, UCAL_DST_OFFSET, &status);
263         ucal_close(ucal);
264
265         if (zone_offset) *zone_offset = ms2sec(zone);
266         if (dst_offset) *dst_offset = ms2sec(dst);
267 }
268
269 bool cal_time_in_dst(const char *tz, long long int t)
270 {
271         UErrorCode status = U_ZERO_ERROR;
272         UCalendar *ucal = NULL;
273
274         ucal = cal_time_open_ucal(-1, tz, -1);
275         if (NULL == ucal) {
276                 /* LCOV_EXCL_START */
277                 ERR("cal_time_open_ucal() Fail");
278                 return false;
279                 /* LCOV_EXCL_STOP */
280         }
281         ucal_setMillis(ucal, sec2ms(t), &status);
282         bool is_dst = ucal_inDaylightTime(ucal, &status);
283         ucal_close(ucal);
284
285         return is_dst;
286 }
287
288 int cal_time_init(void)
289 {
290         UCalendar *ucal = NULL;
291
292         pthread_mutex_lock(&cal_mutex_gmt);
293         if (NULL == _g_ucal_gmt) {
294                 ucal = cal_time_open_ucal(-1, NULL, -1);
295                 if (NULL == ucal) {
296                         pthread_mutex_unlock(&cal_mutex_gmt);
297                         return CALENDAR_ERROR_SYSTEM;
298                 }
299                 _g_ucal_gmt = ucal;
300         }
301         pthread_mutex_unlock(&cal_mutex_gmt);
302         return CALENDAR_ERROR_NONE;
303 }
304
305 void cal_time_fini(void)
306 {
307         pthread_mutex_lock(&cal_mutex_gmt);
308         if (_g_ucal_gmt) {
309                 ucal_close(_g_ucal_gmt);
310                 _g_ucal_gmt = NULL;
311         }
312         pthread_mutex_unlock(&cal_mutex_gmt);
313 }
314
315 static UCalendar* __get_gmt_ucal(void)
316 {
317         if (NULL == _g_ucal_gmt) {
318                 cal_time_init();
319         }
320         return _g_ucal_gmt;
321 }
322
323 long long int cal_time_convert_lli(char *p)
324 {
325         UErrorCode status = U_ZERO_ERROR;
326
327         if (p && *p) {
328                 int y = 0, m = 0, d = 0;
329                 int h = 0, n = 0, s = 0;
330                 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
331
332                 UCalendar *ucal = __get_gmt_ucal();
333                 ucal_setDateTime(ucal, y, m -1, d, h, n, s, &status);
334                 return ms2sec(ucal_getMillis(ucal, &status));
335         }
336         return 0;
337 }
338
339 void cal_time_modify_caltime(calendar_time_s *caltime, long long int diff)
340 {
341         UErrorCode status = U_ZERO_ERROR;
342         RET_IF(NULL == caltime);
343
344         UCalendar *ucal = __get_gmt_ucal();
345         long long int lli = 0;
346         switch (caltime->type) {
347         case CALENDAR_TIME_UTIME:
348                 DBG("Before (%lld)", caltime->time.utime);
349                 caltime->time.utime += diff;
350                 DBG("After (%lld)", caltime->time.utime);
351                 break;
352
353         case CALENDAR_TIME_LOCALTIME:
354                 DBG("Before" CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
355                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
356
357                 ucal_setDateTime(ucal, caltime->time.date.year, caltime->time.date.month - 1, caltime->time.date.mday,
358                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second, &status);
359                 lli = ms2sec(ucal_getMillis(ucal, &status));
360                 lli += diff;
361                 ucal_setMillis(ucal, sec2ms(lli), &status);
362                 caltime->time.date.year = ucal_get(ucal, UCAL_YEAR, &status);
363                 caltime->time.date.month = ucal_get(ucal, UCAL_MONTH, &status) + 1;
364                 caltime->time.date.mday = ucal_get(ucal, UCAL_DATE, &status);
365                 caltime->time.date.hour = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
366                 caltime->time.date.minute = ucal_get(ucal, UCAL_MINUTE, &status);
367                 caltime->time.date.second = ucal_get(ucal, UCAL_SECOND, &status);
368
369                 DBG("After" CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
370                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
371                 break;
372         }
373 }
374
375 void cal_time_get_nth_wday(long long int t, int *nth, int *wday)
376 {
377         RET_IF(NULL == nth);
378         RET_IF(NULL == wday);
379
380         UErrorCode status = U_ZERO_ERROR;
381         UCalendar *ucal = __get_gmt_ucal();
382         ucal_setMillis(ucal, sec2ms(t), &status);
383         *wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &status);
384         /* check if nth is last */
385         int this_week = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &status);
386         ucal_add(ucal, UCAL_DAY_OF_YEAR, 7, &status);
387         int next_week = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &status);
388         *nth = next_week == 1 ? -1 : this_week;
389         DBG("nth(%d) wday(%d)", *nth, *wday);
390 }
391
392 void cal_time_get_datetime(long long int t, int *y, int *m, int *d, int *h, int *n, int *s)
393 {
394         UErrorCode status = U_ZERO_ERROR;
395         UCalendar *ucal = __get_gmt_ucal();
396         if (NULL == ucal) {
397                 /* LCOV_EXCL_START */
398                 ERR("__get_gmt_ucal() Fail");
399                 return;
400                 /* LCOV_EXCL_STOP */
401         }
402         ucal_setMillis(ucal, sec2ms(t), &status);
403         if (y) *y = ucal_get(ucal, UCAL_YEAR, &status);
404         if (m) *m = ucal_get(ucal, UCAL_MONTH, &status) + 1;
405         if (d) *d = ucal_get(ucal, UCAL_DATE, &status);
406         if (h) *h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
407         if (n) *n = ucal_get(ucal, UCAL_MINUTE, &status);
408         if (s) *s = ucal_get(ucal, UCAL_SECOND, &status);
409 }
410
411 void cal_time_get_local_datetime(char *tzid, long long int t, int *y, int *m, int *d, int *h, int *n, int *s)
412 {
413         UErrorCode status = U_ZERO_ERROR;
414         UCalendar *ucal = cal_time_open_ucal(-1, tzid, 0);
415         if (NULL == ucal) {
416                 /* LCOV_EXCL_START */
417                 ERR("__get_gmt_ucal() Fail");
418                 return;
419                 /* LCOV_EXCL_STOP */
420         }
421         ucal_setMillis(ucal, sec2ms(t), &status);
422         if (y) *y = ucal_get(ucal, UCAL_YEAR, &status);
423         if (m) *m = ucal_get(ucal, UCAL_MONTH, &status) + 1;
424         if (d) *d = ucal_get(ucal, UCAL_DATE, &status);
425         if (h) *h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
426         if (n) *n = ucal_get(ucal, UCAL_MINUTE, &status);
427         if (s) *s = ucal_get(ucal, UCAL_SECOND, &status);
428         ucal_close(ucal);
429 }
430
431 bool cal_time_is_available_tzid(char *tzid)
432 {
433         RETV_IF(NULL == tzid, false);
434
435         UErrorCode ec = U_ZERO_ERROR;
436         StringEnumeration* s = TimeZone::createEnumeration();
437         int32_t s_count = s->count(ec);
438
439         int len = strlen(tzid);
440         int i, j;
441         for (i = 0; i < s_count; i++) {
442                 char buf[CAL_STR_SHORT_LEN32] = {0};
443                 const UnicodeString *unicode_tzid = s->snext(ec);
444                 for (j = 0; j < unicode_tzid->length() && j < CAL_STR_SHORT_LEN32 - 1; j++) {
445                         buf[j] = unicode_tzid->charAt(j);
446                 }
447                 buf[j] = '\0';
448                 if (CAL_STRING_EQUAL == strncmp(buf, tzid, len)) {
449                         return true;
450                 }
451         }
452         return false;
453 }
454
455 int _get_dst_savings(char *tzid)
456 {
457         UChar utf16_timezone[CAL_STR_SHORT_LEN64] = {0};
458         u_uastrncpy(utf16_timezone, tzid, sizeof(utf16_timezone));
459
460         UErrorCode status = U_ZERO_ERROR;
461
462         return ucal_getDSTSavings(utf16_timezone, &status);
463 }
464
465 bool cal_time_is_dst_savings(void)
466 {
467         char buf[128] = {0};
468         readlink("/opt/etc/localtime", buf, sizeof(buf) - 1);
469
470         char *timezone = buf + 20; /* /usr/share/zoneinfo/ */
471         return _get_dst_savings(timezone) == 0 ? false : true;
472 }
473