4 * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
39 #include "cal_internal.h"
40 #include "cal_typedef.h"
42 #include "cal_utils.h"
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)
47 #define ms2sec(ms) (long long int)(ms / 1000.0)
48 #define sec2ms(s) (s * 1000.0)
50 static pthread_mutex_t cal_mutex_gmt = PTHREAD_MUTEX_INITIALIZER;
51 static UCalendar *_g_ucal_gmt = NULL;
53 void cal_time_get_registered_tzid_with_offset(int offset, char *registered_tzid, int tzid_size)
55 UErrorCode ec = U_ZERO_ERROR;
57 RET_IF(NULL == registered_tzid);
59 StringEnumeration* s = TimeZone::createEnumeration(sec2ms(offset));
60 if (0 == s->count(ec)) {
61 DBG("No tzid of offset(%d)sec", offset);
65 const UnicodeString *unicode_tzid = s->snext(ec);
66 unicode_tzid->extract(registered_tzid, tzid_size, NULL, ec);
70 UCalendar *cal_time_open_ucal(int calendar_system_type, const char *tzid, int wkst)
72 UChar utf16_timezone[CAL_STR_SHORT_LEN64] = {0};
73 u_uastrncpy(utf16_timezone, tzid, sizeof(utf16_timezone));
75 UErrorCode status = U_ZERO_ERROR;
76 UCalendar *ucal = NULL;
78 char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY] = {0};
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);
86 ucal = ucal_open(utf16_timezone, -1, uloc_getDefault(), UCAL_GREGORIAN, &status);
89 if (U_FAILURE(status)) {
91 ERR("ucal_open() Fail[%s]", u_errorName(status));
97 ERR("ucal_open() Fail[%s]", u_errorName(status));
101 if (CALENDAR_SUNDAY <= wkst && wkst <= CALENDAR_SATURDAY) {
102 DBG("set wkst(%d)", wkst);
103 ucal_setAttribute(ucal, UCAL_FIRST_DAY_OF_WEEK, wkst);
109 char* cal_time_convert_ltos(const char *tzid, long long int lli, int is_allday)
111 int y, mon, d, h, min, s;
112 char buf[CAL_STR_SHORT_LEN32] = {0};
114 UErrorCode status = U_ZERO_ERROR;
117 DBG("tzid is NULL so set gmt");
121 ucal = cal_time_open_ucal(-1, tzid, -1);
123 /* LCOV_EXCL_START */
124 ERR("cal_time_open_ucal() Fail");
128 ucal_setMillis(ucal, sec2ms(lli), &status);
129 if (U_FAILURE(status)) {
130 /* LCOV_EXCL_START */
131 ERR("ucal_setMillFail (%s)", u_errorName(status));
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);
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");
148 snprintf(buf, sizeof(buf), CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, y, mon, d, h, min, s);
152 return cal_strdup(buf);
155 long long int cal_time_convert_itol(const char *tzid, int y, int mon, int d, int h, int min, int s)
158 UCalendar *ucal = NULL;
159 UErrorCode status = U_ZERO_ERROR;
161 ucal = cal_time_open_ucal(-1, tzid, -1);
163 /* LCOV_EXCL_START */
164 ERR("cal_time_open_ucal() Fail");
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));
181 long long int cal_time_get_now(void)
183 return ms2sec(ucal_getNow());
186 int cal_time_get_next_date(calendar_time_s *today, calendar_time_s *next)
188 RETV_IF(NULL == today, CALENDAR_ERROR_INVALID_PARAMETER);
189 RETV_IF(NULL == next, CALENDAR_ERROR_INVALID_PARAMETER);
191 UCalendar *ucal = NULL;
192 UErrorCode status = U_ZERO_ERROR;
194 const char *tzid = CAL_TZID_GMT;
196 utzid = (UChar *)calloc(strlen(tzid) + 1, sizeof(UChar));
197 RETVM_IF(NULL == utzid, CALENDAR_ERROR_OUT_OF_MEMORY, "calloc() Fail");
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));
209 switch (today->type) {
210 case CALENDAR_TIME_UTIME:
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,
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);
241 return CALENDAR_ERROR_NONE;
244 void cal_time_u_cleanup(void)
249 void cal_time_get_tz_offset(const char *tz, time_t *zone_offset, time_t *dst_offset)
251 UErrorCode status = U_ZERO_ERROR;
252 UCalendar *ucal = NULL;
254 ucal = cal_time_open_ucal(-1, tz, -1);
256 /* LCOV_EXCL_START */
257 ERR("cal_time_open_ucal() Fail");
261 int32_t zone = ucal_get(ucal, UCAL_ZONE_OFFSET, &status);
262 int32_t dst = ucal_get(ucal, UCAL_DST_OFFSET, &status);
265 if (zone_offset) *zone_offset = ms2sec(zone);
266 if (dst_offset) *dst_offset = ms2sec(dst);
269 bool cal_time_in_dst(const char *tz, long long int t)
271 UErrorCode status = U_ZERO_ERROR;
272 UCalendar *ucal = NULL;
274 ucal = cal_time_open_ucal(-1, tz, -1);
276 /* LCOV_EXCL_START */
277 ERR("cal_time_open_ucal() Fail");
281 ucal_setMillis(ucal, sec2ms(t), &status);
282 bool is_dst = ucal_inDaylightTime(ucal, &status);
288 int cal_time_init(void)
290 UCalendar *ucal = NULL;
292 pthread_mutex_lock(&cal_mutex_gmt);
293 if (NULL == _g_ucal_gmt) {
294 ucal = cal_time_open_ucal(-1, NULL, -1);
296 pthread_mutex_unlock(&cal_mutex_gmt);
297 return CALENDAR_ERROR_SYSTEM;
301 pthread_mutex_unlock(&cal_mutex_gmt);
302 return CALENDAR_ERROR_NONE;
305 void cal_time_fini(void)
307 pthread_mutex_lock(&cal_mutex_gmt);
309 ucal_close(_g_ucal_gmt);
312 pthread_mutex_unlock(&cal_mutex_gmt);
315 static UCalendar* __get_gmt_ucal(void)
317 if (NULL == _g_ucal_gmt) {
323 long long int cal_time_convert_lli(char *p)
325 UErrorCode status = U_ZERO_ERROR;
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);
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));
339 void cal_time_modify_caltime(calendar_time_s *caltime, long long int diff)
341 UErrorCode status = U_ZERO_ERROR;
342 RET_IF(NULL == caltime);
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);
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);
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));
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);
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);
375 void cal_time_get_nth_wday(long long int t, int *nth, int *wday)
378 RET_IF(NULL == wday);
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);
392 void cal_time_get_datetime(long long int t, int *y, int *m, int *d, int *h, int *n, int *s)
394 UErrorCode status = U_ZERO_ERROR;
395 UCalendar *ucal = __get_gmt_ucal();
397 /* LCOV_EXCL_START */
398 ERR("__get_gmt_ucal() Fail");
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);
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)
413 UErrorCode status = U_ZERO_ERROR;
414 UCalendar *ucal = cal_time_open_ucal(-1, tzid, 0);
416 /* LCOV_EXCL_START */
417 ERR("__get_gmt_ucal() Fail");
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);
431 bool cal_time_is_available_tzid(char *tzid)
433 RETV_IF(NULL == tzid, false);
435 UErrorCode ec = U_ZERO_ERROR;
436 StringEnumeration* s = TimeZone::createEnumeration();
437 int32_t s_count = s->count(ec);
439 int len = strlen(tzid);
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);
448 if (CAL_STRING_EQUAL == strncmp(buf, tzid, len)) {
455 int _get_dst_savings(char *tzid)
457 UChar utf16_timezone[CAL_STR_SHORT_LEN64] = {0};
458 u_uastrncpy(utf16_timezone, tzid, sizeof(utf16_timezone));
460 UErrorCode status = U_ZERO_ERROR;
462 return ucal_getDSTSavings(utf16_timezone, &status);
465 bool cal_time_is_dst_savings(void)
468 readlink("/opt/etc/localtime", buf, sizeof(buf) - 1);
470 char *timezone = buf + 20; /* /usr/share/zoneinfo/ */
471 return _get_dst_savings(timezone) == 0 ? false : true;