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);
90 if (U_FAILURE(status)) {
91 ERR("ucal_open() Fail(%s)", u_errorName(status));
94 if (CALENDAR_SUNDAY <= wkst && wkst <= CALENDAR_SATURDAY) {
95 DBG("set wkst(%d)", wkst);
96 ucal_setAttribute(ucal, UCAL_FIRST_DAY_OF_WEEK, wkst);
101 char* cal_time_convert_ltos(const char *tzid, long long int lli, int is_allday)
103 int y, mon, d, h, min, s;
104 char buf[CAL_STR_SHORT_LEN32] = {0};
106 UErrorCode status = U_ZERO_ERROR;
109 DBG("tzid is NULL so set gmt");
113 ucal = cal_time_open_ucal(-1, tzid, -1);
115 ERR("cal_time_open_ucal() Fail");
118 ucal_setMillis(ucal, sec2ms(lli), &status);
119 if (U_FAILURE(status)) {
120 ERR("ucal_setMillFail (%s)", u_errorName(status));
125 y = ucal_get(ucal, UCAL_YEAR, &status);
126 mon = ucal_get(ucal, UCAL_MONTH, &status) + 1;
127 d = ucal_get(ucal, UCAL_DATE, &status);
128 h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
129 min = ucal_get(ucal, UCAL_MINUTE, &status);
130 s = ucal_get(ucal, UCAL_SECOND, &status);
132 if (CAL_STRING_EQUAL == strncmp(tzid, CAL_TZID_GMT, strlen(CAL_TZID_GMT))) {
133 snprintf(buf, sizeof(buf), CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS"%s",
134 y, mon, d, h, min, s, is_allday ? "" : "Z");
137 snprintf(buf, sizeof(buf), CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, y, mon, d, h, min, s);
142 return cal_strdup(buf);
145 long long int cal_time_convert_itol(const char *tzid, int y, int mon, int d, int h, int min, int s)
148 UCalendar *ucal = NULL;
149 UErrorCode status = U_ZERO_ERROR;
151 ucal = cal_time_open_ucal(-1, tzid, -1);
153 ERR("cal_time_open_ucal() Fail");
156 ucal_set(ucal, UCAL_YEAR, y);
157 ucal_set(ucal, UCAL_MONTH, mon -1);
158 ucal_set(ucal, UCAL_DATE, d);
159 ucal_set(ucal, UCAL_HOUR_OF_DAY, h);
160 ucal_set(ucal, UCAL_MINUTE, min);
161 ucal_set(ucal, UCAL_SECOND, s);
162 ucal_set(ucal, UCAL_MILLISECOND, 0);
163 lli = ms2sec(ucal_getMillis(ucal, &status));
169 long long int cal_time_get_now(void)
171 return ms2sec(ucal_getNow());
174 int cal_time_get_next_date(calendar_time_s *today, calendar_time_s *next)
176 RETV_IF(NULL == today, CALENDAR_ERROR_INVALID_PARAMETER);
177 RETV_IF(NULL == next, CALENDAR_ERROR_INVALID_PARAMETER);
179 UCalendar *ucal = NULL;
180 UErrorCode status = U_ZERO_ERROR;
182 const char *tzid = CAL_TZID_GMT;
184 utzid = (UChar *)calloc(strlen(tzid) + 1, sizeof(UChar));
185 RETVM_IF(NULL == utzid, CALENDAR_ERROR_OUT_OF_MEMORY, "calloc() Fail");
187 u_uastrcpy(utzid, tzid);
188 ucal = ucal_open(utzid, u_strlen(utzid), "en_US", UCAL_TRADITIONAL, &status);
189 if (U_FAILURE(status)) {
190 ERR("ucal_open() Fail(%s)", u_errorName(status));
195 switch (today->type) {
196 case CALENDAR_TIME_UTIME:
200 case CALENDAR_TIME_LOCALTIME:
201 ucal_setDateTime(ucal,
202 today->time.date.year,
203 today->time.date.month-1,
204 today->time.date.mday,
205 today->time.date.hour,
206 today->time.date.minute,
207 today->time.date.second,
209 DBG("today %04d/%02d/%02d %02d:%02d:%02d",
210 today->time.date.year, today->time.date.month, today->time.date.mday,
211 today->time.date.hour, today->time.date.minute, today->time.date.second);
212 ucal_add(ucal, UCAL_DAY_OF_YEAR, 1, &status);
213 next->time.date.year = ucal_get(ucal, UCAL_YEAR, &status);
214 next->time.date.month = ucal_get(ucal, UCAL_MONTH, &status) + 1;
215 next->time.date.mday = ucal_get(ucal, UCAL_DATE, &status);
216 next->time.date.hour = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
217 next->time.date.minute = ucal_get(ucal, UCAL_MINUTE, &status);
218 next->time.date.second = ucal_get(ucal, UCAL_SECOND, &status);
219 DBG("next %04d/%02d/%02d %02d:%02d:%02d",
220 next->time.date.year, next->time.date.month, next->time.date.mday,
221 next->time.date.hour, next->time.date.minute, next->time.date.second);
227 return CALENDAR_ERROR_NONE;
230 void cal_time_u_cleanup(void)
235 void cal_time_get_tz_offset(const char *tz, time_t *zone_offset, time_t *dst_offset)
237 UErrorCode status = U_ZERO_ERROR;
238 UCalendar *ucal = NULL;
240 ucal = cal_time_open_ucal(-1, tz, -1);
242 ERR("cal_time_open_ucal() Fail");
245 int32_t zone = ucal_get(ucal, UCAL_ZONE_OFFSET, &status);
246 int32_t dst = ucal_get(ucal, UCAL_DST_OFFSET, &status);
249 if (zone_offset) *zone_offset = ms2sec(zone);
250 if (dst_offset) *dst_offset = ms2sec(dst);
253 bool cal_time_in_dst(const char *tz, long long int t)
255 UErrorCode status = U_ZERO_ERROR;
256 UCalendar *ucal = NULL;
258 ucal = cal_time_open_ucal(-1, tz, -1);
260 ERR("cal_time_open_ucal() Fail");
263 ucal_setMillis(ucal, sec2ms(t), &status);
264 bool is_dst = ucal_inDaylightTime(ucal, &status);
270 int cal_time_init(void)
272 UCalendar *ucal = NULL;
274 pthread_mutex_lock(&cal_mutex_gmt);
275 if (NULL == _g_ucal_gmt) {
276 ucal = cal_time_open_ucal(-1, NULL, -1);
277 RETVM_IF(NULL == ucal, CALENDAR_ERROR_SYSTEM, "cal_time_open_ucal() Fail");
280 pthread_mutex_unlock(&cal_mutex_gmt);
281 return CALENDAR_ERROR_NONE;
284 void cal_time_fini(void)
286 pthread_mutex_lock(&cal_mutex_gmt);
288 ucal_close(_g_ucal_gmt);
291 pthread_mutex_unlock(&cal_mutex_gmt);
294 static UCalendar* __get_gmt_ucal(void)
296 pthread_mutex_lock(&cal_mutex_gmt);
297 if (NULL == _g_ucal_gmt) {
300 pthread_mutex_unlock(&cal_mutex_gmt);
304 long long int cal_time_convert_lli(char *p)
306 UErrorCode status = U_ZERO_ERROR;
309 int y = 0, m = 0, d = 0;
310 int h = 0, n = 0, s = 0;
311 sscanf(p, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
313 UCalendar *ucal = __get_gmt_ucal();
314 ucal_setDateTime(ucal, y, m -1, d, h, n, s, &status);
315 return ms2sec(ucal_getMillis(ucal, &status));
320 void cal_time_modify_caltime(calendar_time_s *caltime, long long int diff)
322 UErrorCode status = U_ZERO_ERROR;
323 RET_IF(NULL == caltime);
325 UCalendar *ucal = __get_gmt_ucal();
326 long long int lli = 0;
327 switch (caltime->type) {
328 case CALENDAR_TIME_UTIME:
329 DBG("Before (%lld)", caltime->time.utime);
330 caltime->time.utime += diff;
331 DBG("After (%lld)", caltime->time.utime);
334 case CALENDAR_TIME_LOCALTIME:
335 DBG("Before "CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
336 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
338 ucal_setDateTime(ucal, caltime->time.date.year, caltime->time.date.month - 1, caltime->time.date.mday,
339 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second, &status);
340 lli = ms2sec(ucal_getMillis(ucal, &status));
342 ucal_setMillis(ucal, sec2ms(lli), &status);
343 caltime->time.date.year = ucal_get(ucal, UCAL_YEAR, &status);
344 caltime->time.date.month = ucal_get(ucal, UCAL_MONTH, &status) + 1;
345 caltime->time.date.mday = ucal_get(ucal, UCAL_DATE, &status);
346 caltime->time.date.hour = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
347 caltime->time.date.minute = ucal_get(ucal, UCAL_MINUTE, &status);
348 caltime->time.date.second = ucal_get(ucal, UCAL_SECOND, &status);
350 DBG("After "CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
351 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
356 void cal_time_get_nth_wday(long long int t, int *nth, int *wday)
359 RET_IF(NULL == wday);
361 UErrorCode status = U_ZERO_ERROR;
362 UCalendar *ucal = __get_gmt_ucal();
363 ucal_setMillis(ucal, sec2ms(t), &status);
364 *wday = ucal_get(ucal, UCAL_DAY_OF_WEEK, &status);
365 /* check if nth is last */
366 int this_week = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &status);
367 ucal_add(ucal, UCAL_DAY_OF_YEAR, 7, &status);
368 int next_week = ucal_get(ucal, UCAL_DAY_OF_WEEK_IN_MONTH, &status);
369 *nth = next_week == 1 ? -1 : this_week;
370 DBG("nth(%d) wday(%d)", *nth, *wday);
373 void cal_time_get_datetime(long long int t, int *y, int *m, int *d, int *h, int *n, int *s)
375 UErrorCode status = U_ZERO_ERROR;
376 UCalendar *ucal = __get_gmt_ucal();
378 ERR("__get_gmt_ucal() Fail");
381 ucal_setMillis(ucal, sec2ms(t), &status);
382 if (y) *y = ucal_get(ucal, UCAL_YEAR, &status);
383 if (m) *m = ucal_get(ucal, UCAL_MONTH, &status) + 1;
384 if (d) *d = ucal_get(ucal, UCAL_DATE, &status);
385 if (h) *h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
386 if (n) *n = ucal_get(ucal, UCAL_MINUTE, &status);
387 if (s) *s = ucal_get(ucal, UCAL_SECOND, &status);
391 void cal_time_get_local_datetime(char *tzid, long long int t, int *y, int *m, int *d, int *h, int *n, int *s)
393 UErrorCode status = U_ZERO_ERROR;
394 UCalendar *ucal = cal_time_open_ucal(-1, tzid, 0);
396 ERR("__get_gmt_ucal() Fail");
399 ucal_setMillis(ucal, sec2ms(t), &status);
400 if (y) *y = ucal_get(ucal, UCAL_YEAR, &status);
401 if (m) *m = ucal_get(ucal, UCAL_MONTH, &status) + 1;
402 if (d) *d = ucal_get(ucal, UCAL_DATE, &status);
403 if (h) *h = ucal_get(ucal, UCAL_HOUR_OF_DAY, &status);
404 if (n) *n = ucal_get(ucal, UCAL_MINUTE, &status);
405 if (s) *s = ucal_get(ucal, UCAL_SECOND, &status);
409 bool cal_time_is_available_tzid(char *tzid)
411 UErrorCode ec = U_ZERO_ERROR;
412 StringEnumeration* s = TimeZone::createEnumeration();
413 int32_t s_count = s->count(ec);
415 int len = strlen(tzid);
417 for (i = 0; i < s_count; i++) {
418 char buf[CAL_STR_SHORT_LEN32] = {0};
419 const UnicodeString *unicode_tzid = s->snext(ec);
420 for (j = 0; j < unicode_tzid->length(); j++) {
421 buf[j] = unicode_tzid->charAt(j);
424 if (CAL_STRING_EQUAL == strncmp(buf, tzid, len)) {