* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* cm_date.c
*
*
* IDENTIFICATION
* src/common/cm_date.c
*
* -------------------------------------------------------------------------
*/
#include "cm_common_module.h"
#include "cm_date.h"
#include "cm_decimal.h"
#include "cm_nls.h"
#include "cm_timer.h"
uint16 g_month_days[2][12] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static text_t g_week_days[7] = {
{ "SUNDAY", 6 },
{ "MONDAY", 6 },
{ "TUESDAY", 7 },
{ "WEDNESDAY", 9 },
{ "THURSDAY", 8 },
{ "FRIDAY", 6 },
{ "SATURDAY", 8 }
};
static text_t g_month_names[12] = {
{ "JANUARY", 7 },
{ "FEBRUARY", 8 },
{ "MARCH", 5 },
{ "APRIL", 5 },
{ "MAY", 3 },
{ "JUNE", 4 },
{ "JULY", 4 },
{ "AUGUST", 6 },
{ "SEPTEMBER", 9 },
{ "OCTOBER", 7 },
{ "NOVEMBER", 8 },
{ "DECEMBER", 8 }
};
static text_t g_month_roman_names[12] = {
{ "I", 1 },
{ "II", 2 },
{ "III", 3 },
{ "IV", 2 },
{ "V", 1 },
{ "VI", 2 },
{ "VII", 3 },
{ "VIII", 4 },
{ "IX", 2 },
{ "X", 1 },
{ "XI", 2 },
{ "XII", 3 }
};
const uint64 powers_of_10[20] = {1,
10,
100,
1000,
10000UL,
100000UL,
1000000UL,
10000000UL,
100000000ULL,
1000000000ULL,
10000000000ULL,
100000000000ULL,
1000000000000ULL,
10000000000000ULL,
100000000000000ULL,
1000000000000000ULL,
10000000000000000ULL,
100000000000000000ULL,
1000000000000000000ULL,
10000000000000000000ULL};
typedef enum g_date_time_mask {
MASK_NONE = 0,
MASK_YEAR = 0x0000001,
MASK_MONTH = 0x0000002,
MASK_DAY = 0x0000004,
MASK_HOUR = 0x0000008,
MASK_MINUTE = 0x0000010,
MASK_SECOND = 0x0000020,
MASK_USEC = 0x0000040,
MASK_TZ_HOUR = 0x0000080,
MASK_TZ_MINUTE = 0x0000100,
MASK_AM_PM = 0x0000200,
MASK_DOW = 0x0000400,
} date_time_mask_t;
static format_item_t g_formats[] = {
{
.name = { (char *)"%Y", 2 },
.id = FMT_YEAR4,
.fmask = MASK_YEAR,
.placer = 4,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%D", 2 },
.id = FMT_DAY_OF_MONTH,
.fmask = MASK_DAY,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%M", 2 },
.id = FMT_MONTH_NAME,
.fmask = MASK_MONTH,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%h", 2 },
.id = FMT_HOUR_OF_DAY24,
.fmask = MASK_HOUR,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%i", 2 },
.id = FMT_MINUTE,
.fmask = MASK_MINUTE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%s", 2 },
.id = FMT_SECOND,
.fmask = MASK_SECOND,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"%x", 2 },
.id = FMT_YEAR4,
.fmask = MASK_YEAR,
.placer = 4,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)" ", 1 },
.id = FMT_SPACE,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"-", 1 },
.id = FMT_MINUS,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"\\", 1 },
.id = FMT_SLASH,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"/", 1 },
.id = FMT_BACK_SLASH,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)",", 1 },
.id = FMT_COMMA,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)".", 1 },
.id = FMT_DOT,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)";", 1 },
.id = FMT_SEMI_COLON,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)":", 1 },
.id = FMT_COLON,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"X", 1 },
.id = FMT_X,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"\"", 1 },
.id = FMT_DQ_TEXT,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"AM", 2 },
.id = FMT_AM_INDICATOR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"A.M.", 4 },
.id = FMT_AM_INDICATOR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"PM", 2 },
.id = FMT_PM_INDICATOR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"P.M.", 4 },
.id = FMT_PM_INDICATOR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"CC", 2 },
.id = FMT_CENTURY,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"SCC", 3 },
.id = FMT_CENTURY,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"DAY", 3 },
.id = FMT_DAY_NAME,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"DY", 2 },
.id = FMT_DAY_ABBR_NAME,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"DDD", 3 },
.id = FMT_DAY_OF_YEAR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"DD", 2 },
.id = FMT_DAY_OF_MONTH,
.fmask = MASK_DAY,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"D", 1 },
.id = FMT_DAY_OF_WEEK,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"FF1", 3 },
.id = FMT_FRAC_SECOND1,
.fmask = MASK_USEC,
.placer = 1,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF2", 3 },
.id = FMT_FRAC_SECOND2,
.fmask = MASK_USEC,
.placer = 2,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF3", 3 },
.id = FMT_FRAC_SECOND3,
.fmask = MASK_USEC,
.placer = 3,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF4", 3 },
.id = FMT_FRAC_SECOND4,
.fmask = MASK_USEC,
.placer = 4,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF5", 3 },
.id = FMT_FRAC_SECOND5,
.fmask = MASK_USEC,
.placer = 5,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF6", 3 },
.id = FMT_FRAC_SECOND6,
.fmask = MASK_USEC,
.placer = 6,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"FF", 2 },
.id = FMT_FRAC_SEC_VAR_LEN,
.fmask = MASK_USEC,
.placer = 6,
.reversible = OG_TRUE,
.dt_used = OG_FALSE,
},
{
.name = { (char *)"HH12", 4 },
.id = FMT_HOUR_OF_DAY12,
.fmask = MASK_HOUR,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"HH24", 4 },
.id = FMT_HOUR_OF_DAY24,
.fmask = MASK_HOUR,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"HH", 2 },
.id = FMT_HOUR_OF_DAY12,
.fmask = MASK_HOUR,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"MI", 2 },
.id = FMT_MINUTE,
.fmask = MASK_MINUTE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"MM", 2 },
.id = FMT_MONTH,
.fmask = MASK_MONTH,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"RM", 2 },
.id = FMT_MONTH_RM,
.fmask = MASK_MONTH,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"MONTH", 5 },
.id = FMT_MONTH_NAME,
.fmask = MASK_MONTH,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"MON", 3 },
.id = FMT_MONTH_ABBR_NAME,
.fmask = MASK_MONTH,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"Q", 1 },
.id = FMT_QUARTER,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"SSSSS", 5 },
.id = FMT_SECOND_PASS,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"SS", 2 },
.id = FMT_SECOND,
.fmask = MASK_SECOND,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"WW", 2 },
.id = FMT_WEEK_OF_YEAR,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"W", 1 },
.id = FMT_WEEK_OF_MONTH,
.fmask = MASK_NONE,
.placer = -1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"YYYY", 4 },
.id = FMT_YEAR4,
.fmask = MASK_YEAR,
.placer = 4,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"YYY", 3 },
.id = FMT_YEAR3,
.fmask = MASK_NONE,
.placer = 3,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"YY", 2 },
.id = FMT_YEAR2,
.fmask = MASK_NONE,
.placer = 2,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"Y", 1 },
.id = FMT_YEAR1,
.fmask = MASK_NONE,
.placer = 1,
.reversible = OG_FALSE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"TZH", 3 },
.id = FMT_TZ_HOUR,
.fmask = MASK_TZ_HOUR,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
{
.name = { (char *)"TZM", 3 },
.id = FMT_TZ_MINUTE,
.fmask = MASK_TZ_MINUTE,
.placer = -1,
.reversible = OG_TRUE,
.dt_used = OG_TRUE,
},
};
#define DATE_FORMAT_COUNT (sizeof(g_formats) / sizeof(format_item_t))
#define EVEN_NUM 2
#ifdef __cplusplus
extern "C" {
#endif
static void cm_text2date_init(date_detail_t *datetime)
{
datetime->year = CM_MIN_YEAR;
datetime->mon = 1;
datetime->day = 1;
datetime->hour = 0;
datetime->min = 0;
datetime->sec = 0;
datetime->millisec = 0;
datetime->microsec = 0;
datetime->nanosec = 0;
datetime->neg = 0;
return ;
}
static void cm_set_all_zero_detail(date_detail_t *detail)
{
detail->year = 0;
detail->mon = 0;
detail->day = 0;
detail->hour = 0;
detail->min = 0;
detail->sec = 0;
detail->millisec = 0;
detail->microsec = 0;
detail->nanosec = 0;
return ;
}
static bool32 cm_check_valid_zero_time(date_detail_t *datetime)
{
if (cm_is_all_zero_time(datetime)) {
return OG_TRUE;
}
if (datetime->year == 0) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "YEAR", 1, 9999);
return OG_FALSE;
}
if (datetime->mon == 0) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "MONTH", 1, 12);
return OG_FALSE;
}
if (datetime->day == 0) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "DAY", 1, 31);
return OG_FALSE;
}
return OG_TRUE;
}
void cm_now_detail(date_detail_t *detail)
{
#ifdef WIN32
SYSTEMTIME sys_time;
GetLocalTime(&sys_time);
CM_POINTER(detail);
detail->year = (uint16)sys_time.wYear;
detail->mon = (uint8)sys_time.wMonth;
detail->day = (uint8)sys_time.wDay;
detail->hour = (uint8)sys_time.wHour;
detail->min = (uint8)sys_time.wMinute;
detail->sec = (uint8)sys_time.wSecond;
detail->millisec = (uint16)sys_time.wMilliseconds;
detail->microsec = 0;
detail->nanosec = 0;
#else
time_t t_var;
struct timeval tv;
struct tm ut;
CM_POINTER(detail);
gettimeofday(&tv, NULL);
t_var = tv.tv_sec;
localtime_r(&t_var, &ut);
detail->year = (uint16)ut.tm_year + 1900;
detail->mon = (uint8)ut.tm_mon + 1;
detail->day = (uint8)ut.tm_mday;
detail->hour = (uint8)ut.tm_hour;
detail->min = (uint8)ut.tm_min;
detail->sec = (uint8)ut.tm_sec;
detail->millisec = (uint32)((tv.tv_usec) / 1000);
detail->microsec = (uint16)(tv.tv_usec % 1000);
detail->nanosec = 0;
#endif
}
static inline int32 days_before_year(int32 year_input)
{
int32 year = year_input;
--year;
return year * 365 + year / 4 - year / 100 + year / 400;
}
static inline int32 total_days_before_date(const date_detail_t *detail)
{
int32 i;
int32 total_days;
CM_POINTER(detail);
total_days = days_before_year((int32)detail->year) - CM_BASELINE_DAY;
uint16 *day_tab = (uint16 *)g_month_days[IS_LEAP_YEAR(detail->year)];
for (i = 0; i < (int32)(detail->mon - 1); i++) {
total_days += (int32)day_tab[i];
}
total_days += detail->day;
return total_days;
}
date_t cm_encode_date(const date_detail_t *detail)
{
int32 total_days;
date_t date_tmp;
CM_POINTER(detail);
if (cm_is_all_zero_time(detail)) {
return CM_ALL_ZERO_DATETIME;
}
CM_ASSERT(CM_IS_VALID_YEAR(detail->year));
CM_ASSERT(detail->mon >= 1 && detail->mon <= 12);
CM_ASSERT(detail->day >= 1 && detail->day <= 31);
CM_ASSERT(detail->hour <= 23);
CM_ASSERT(detail->min <= 59);
CM_ASSERT(detail->sec <= 59);
CM_ASSERT(detail->microsec <= 999);
CM_ASSERT(detail->millisec <= 999);
total_days = total_days_before_date(detail);
date_tmp = (int64)total_days * SECONDS_PER_DAY;
date_tmp += (uint32)detail->hour * SECONDS_PER_HOUR;
date_tmp += (uint32)detail->min * SECONDS_PER_MIN;
date_tmp += detail->sec;
date_tmp = date_tmp * MILLISECS_PER_SECOND + detail->millisec;
date_tmp = date_tmp * MICROSECS_PER_MILLISEC + detail->microsec;
return date_tmp;
}
bool32 cm_str2week(text_t *value, uint8 *week)
{
uint8 day_number_of_week = (uint8)sizeof(g_week_days) / sizeof(text_t);
for (uint8 i = 0; i < day_number_of_week; i++) {
if (cm_text_str_contain_equal_ins(value, g_week_days[i].str, 3)) {
*week = i;
return OG_TRUE;
}
}
return OG_FALSE;
}
static void cm_encode_timestamp_tz(const date_detail_t *detail, timestamp_tz_t *tstz)
{
tstz->tstamp = cm_encode_date(detail);
tstz->tz_offset = detail->tz_offset;
return;
}
#define DAYS_1 365
#define DAYS_4 (DAYS_1 * 4 + 1)
#define DAYS_100 (DAYS_4 * 25 - 1)
#define DAYS_400 (DAYS_100 * 4 + 1)
static inline void cm_decode_leap(date_detail_t *detail, int32 *d)
{
uint32 hundred_count;
int32 days = *d;
while (days >= DAYS_400) {
detail->year += 400;
days -= DAYS_400;
}
for (hundred_count = 1; days >= DAYS_100 && hundred_count < 4; hundred_count++) {
detail->year += 100;
days -= DAYS_100;
}
while (days >= DAYS_4) {
detail->year += 4;
days -= DAYS_4;
}
while (days > DAYS_1) {
if (IS_LEAP_YEAR(detail->year)) {
days--;
}
detail->year++;
days -= DAYS_1;
}
*d = days;
}
void cm_decode_date(date_t date_input, date_detail_t *detail)
{
int32 i;
int32 days;
uint16 *day_tab = NULL;
int64 time;
int64 date = date_input;
CM_POINTER(detail);
if (date == CM_ALL_ZERO_DATETIME) {
cm_set_all_zero_detail(detail);
return;
}
time = date;
date /= UNITS_PER_DAY;
time -= date * UNITS_PER_DAY;
if (time < 0) {
time += UNITS_PER_DAY;
date -= 1;
}
detail->microsec = (uint16)(time % MICROSECS_PER_MILLISEC);
time /= MICROSECS_PER_MILLISEC;
detail->millisec = (uint16)(time % MILLISECS_PER_SECOND);
time /= MILLISECS_PER_SECOND;
detail->hour = (int16)(time / SECONDS_PER_HOUR);
time -= (uint32)detail->hour * SECONDS_PER_HOUR;
detail->min = (uint8)(time / SECONDS_PER_MIN);
time -= (uint32)detail->min * SECONDS_PER_MIN;
detail->sec = (uint8)time;
days = (int32)(date + CM_BASELINE_DAY);
detail->year = 1;
cm_decode_leap(detail, &days);
if (days == 0) {
detail->year--;
detail->mon = 12;
detail->day = 31;
} else {
day_tab = g_month_days[IS_LEAP_YEAR(detail->year)];
detail->mon = 1;
i = 0;
while (days > (int32)day_tab[i]) {
days -= (int32)day_tab[i];
i++;
}
detail->mon = (uint8)(detail->mon + i);
detail->day = (uint8)(days);
}
}
date_t cm_now(void)
{
date_t dt = CM_UNIX_EPOCH + CM_HOST_TIMEZONE;
timeval_t tv;
(void)cm_gettimeofday(&tv);
dt += ((int64)tv.tv_sec * MICROSECS_PER_SECOND + tv.tv_usec);
return dt;
}
date_t cm_utc_now(void)
{
date_t dt = CM_UNIX_EPOCH;
timeval_t tv;
(void)cm_gettimeofday(&tv);
dt += ((int64)tv.tv_sec * MICROSECS_PER_SECOND + tv.tv_usec);
return dt;
}
date_t cm_date_now(void)
{
date_t dt = CM_UNIX_EPOCH + CM_HOST_TIMEZONE;
timeval_t tv;
(void)cm_gettimeofday(&tv);
dt += ((int64)tv.tv_sec * MICROSECS_PER_SECOND);
return dt;
}
date_t cm_monotonic_now(void)
{
#ifndef WIN32
struct timespec signal_tv;
date_t dt;
(void)clock_gettime(CLOCK_MONOTONIC, &signal_tv);
dt = ((int64)signal_tv.tv_sec * MICROSECS_PER_SECOND + signal_tv.tv_nsec / 1000);
return dt;
#else
return cm_now();
#endif
}
time_t cm_current_time(void)
{
return time(NULL);
}
void cm_decode_time(time_t time, date_detail_t *detail)
{
#ifdef WIN32
const struct tm *now_time_ptr;
now_time_ptr = localtime(&time);
detail->year = (uint16)now_time_ptr->tm_year + 1900;
detail->mon = (uint8)now_time_ptr->tm_mon + 1;
detail->day = (uint8)now_time_ptr->tm_mday;
detail->hour = (uint8)now_time_ptr->tm_hour;
detail->min = (uint8)now_time_ptr->tm_min;
detail->sec = (uint8)now_time_ptr->tm_sec;
#else
struct tm now_time;
(void)localtime_r(&time, &now_time);
detail->year = (uint16)now_time.tm_year + 1900;
detail->mon = (uint8)now_time.tm_mon + 1;
detail->day = (uint8)now_time.tm_mday;
detail->hour = (uint8)now_time.tm_hour;
detail->min = (uint8)now_time.tm_min;
detail->sec = (uint8)now_time.tm_sec;
#endif
detail->millisec = 0;
detail->microsec = 0;
detail->nanosec = 0;
}
time_t cm_encode_time(date_detail_t *detail)
{
struct tm now_time;
now_time.tm_year = (int)detail->year - 1900;
now_time.tm_mon = (int)detail->mon - 1;
now_time.tm_mday = (int)detail->day;
now_time.tm_hour = (int)detail->hour;
now_time.tm_min = (int)detail->min;
now_time.tm_sec = (int)detail->sec;
now_time.tm_isdst = 0;
return mktime(&now_time);
}
void cm_decode_ora_date(date_t date, uint8 *ora_date)
{
date_detail_t date_detail;
cm_decode_date(date, &date_detail);
ora_date[0] = (uint8)(date_detail.year / 100 + 100);
ora_date[1] = date_detail.year % 100 + 100;
ora_date[2] = date_detail.mon;
ora_date[3] = date_detail.day;
ora_date[4] = date_detail.hour + 1;
ora_date[5] = date_detail.min + 1;
ora_date[6] = date_detail.sec + 1;
}
date_t cm_encode_ora_date(uint8 *ora_date)
{
date_detail_t date_detail;
date_detail.year = (ora_date[0] - 100) * 100 + (ora_date[1] - 100);
date_detail.mon = ora_date[2];
date_detail.day = ora_date[3];
date_detail.hour = ora_date[4] - 1;
date_detail.min = ora_date[5] - 1;
date_detail.sec = ora_date[6] - 1;
date_detail.millisec = 0;
date_detail.microsec = 0;
date_detail.nanosec = 0;
return cm_encode_date(&date_detail);
}
#define OG_SET_DATETIME_FMT_ERROR \
OG_THROW_ERROR(ERR_TEXT_FORMAT_ERROR, "datetime")
* Fetch the double-quote-text item from format text, and extract the text into extra
*/
static inline status_t cm_fetch_dqtext_item(text_t *fmt, text_t *extra, bool32 do_trim)
{
int32 pos;
CM_REMOVE_FIRST(fmt);
pos = cm_text_chr(fmt, '"');
if (pos < 0) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
extra->str = fmt->str;
extra->len = (uint32)pos;
if (do_trim) {
cm_trim_text(extra);
}
CM_REMOVE_FIRST_N(fmt, pos + 1);
return OG_SUCCESS;
}
* extra -- the extra information for the format_item
*/
static inline status_t cm_fetch_format_item(text_t *fmt, format_item_t **item, text_t *extra, bool32 do_trim)
{
uint32 i;
text_t cmp_text;
CM_POINTER(fmt);
if (do_trim) {
cm_trim_text(fmt);
}
cmp_text.str = fmt->str;
for (i = 0; i < DATE_FORMAT_COUNT; i++) {
cmp_text.len = MIN(g_formats[i].name.len, fmt->len);
if (cm_text_equal_ins(&g_formats[i].name, &cmp_text)) {
*item = &g_formats[i];
if ((*item)->id == FMT_DQ_TEXT) {
return cm_fetch_dqtext_item(fmt, extra, do_trim);
}
CM_REMOVE_FIRST_N(fmt, cmp_text.len);
return OG_SUCCESS;
}
}
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
#define CM_YEARS_PER_CMNTURY 100u
static inline uint32 cm_get_century(const date_detail_t *detail)
{
return ((uint32)detail->year - 1) / CM_YEARS_PER_CMNTURY + 1;
}
#define FORMAT_ITEM_BUFFER_SIZE 16
static inline status_t cm_append_date_text(const date_detail_t *detail, const date_detail_ex_t *detail_ex,
format_item_t *item, text_t *fmt_extra,
uint32 prec, text_t *date_text, uint32 max_len)
{
char item_str[FORMAT_ITEM_BUFFER_SIZE] = { 0 };
text_t append_text = { .str = NULL, .len = 0 };
CM_POINTER4(detail, detail_ex, item, date_text);
uint32 frac;
uint8 hh12_value = 0;
int32 tz_hour;
int32 tz_minute;
switch (item->id) {
case FMT_AM_INDICATOR:
case FMT_PM_INDICATOR:
append_text.str = detail_ex->is_am ? (char *)"AM" : (char *)"PM";
append_text.len = 2;
break;
case FMT_DQ_TEXT:
append_text = *fmt_extra;
break;
case FMT_DOT:
case FMT_SPACE:
case FMT_MINUS:
case FMT_SLASH:
case FMT_BACK_SLASH:
case FMT_COMMA:
case FMT_SEMI_COLON:
case FMT_COLON:
append_text = item->name;
break;
case FMT_X:
append_text.str = (char *)".";
append_text.len = 1;
break;
case FMT_DAY_NAME:
append_text = g_week_days[detail_ex->day_of_week];
break;
case FMT_DAY_ABBR_NAME:
append_text.str = g_week_days[detail_ex->day_of_week].str;
append_text.len = 3;
break;
case FMT_MONTH_ABBR_NAME:
append_text.str = g_month_names[detail->mon - 1].str;
append_text.len = 3;
break;
case FMT_MONTH_RM:
append_text = g_month_roman_names[detail->mon - 1];
break;
case FMT_MONTH_NAME:
append_text = g_month_names[detail->mon - 1];
break;
case FMT_YEAR1:
case FMT_YEAR2:
case FMT_YEAR3:
case FMT_YEAR4:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%04u", detail->year));
CM_ASSERT(item->placer > 0 && item->placer <= 4);
append_text.len = (uint32)item->placer;
append_text.str = item_str + (4 - item->placer);
break;
case FMT_CENTURY:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%02u",
cm_get_century(detail)));
break;
case FMT_DAY_OF_WEEK:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%d",
detail_ex->day_of_week + 1));
break;
case FMT_HOUR_OF_DAY12:
if (detail->hour == 0) {
hh12_value = 12;
} else if (detail->hour > 12) {
hh12_value = detail->hour - 12;
} else {
hh12_value = detail->hour;
}
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02u", hh12_value));
break;
case FMT_HOUR_OF_DAY24:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02d", detail->hour));
break;
case FMT_QUARTER:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%u", detail_ex->quarter));
break;
case FMT_SECOND:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02u", detail->sec));
break;
case FMT_SECOND_PASS:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%05u", detail_ex->seconds));
break;
case FMT_WEEK_OF_YEAR:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02u", detail_ex->week));
break;
case FMT_WEEK_OF_MONTH:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%d",
(detail->day / 7) + 1));
break;
case FMT_DAY_OF_MONTH:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%02u",
(detail->day)));
break;
case FMT_DAY_OF_YEAR:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%03u",
detail_ex->day_of_year));
break;
case FMT_FRAC_SECOND1:
case FMT_FRAC_SECOND2:
case FMT_FRAC_SECOND3:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%03u",
detail->millisec));
CM_ASSERT(item->placer > 0 && item->placer <= 3);
append_text.str = item_str;
append_text.len = (uint32)item->placer;
break;
case FMT_FRAC_SECOND4:
case FMT_FRAC_SECOND5:
case FMT_FRAC_SECOND6:
frac = (uint32)detail->millisec * MICROSECS_PER_MILLISEC + detail->microsec;
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%06u",
frac));
CM_ASSERT(item->placer >= 4 && item->placer <= 6);
append_text.str = item_str;
append_text.len = (uint32)item->placer;
break;
case FMT_FRAC_SEC_VAR_LEN:
if (prec == 0) {
if (date_text->len > 0 && date_text->str[date_text->len - 1] == '.') {
date_text->len--;
}
return OG_SUCCESS;
}
frac = (uint32)detail->millisec * MICROSECS_PER_MILLISEC + detail->microsec;
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%06u",
frac));
CM_ASSERT(prec <= OG_MAX_DATETIME_PRECISION);
append_text.str = item_str;
append_text.len = prec;
break;
case FMT_MINUTE:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02u", detail->min));
break;
case FMT_MONTH:
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1,
"%02u", detail->mon));
break;
case FMT_TZ_HOUR:
tz_hour = TIMEZONE_GET_HOUR(detail->tz_offset);
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%+03d",
tz_hour));
break;
case FMT_TZ_MINUTE:
tz_minute = TIMEZONE_GET_MINUTE(detail->tz_offset);
PRTS_RETURN_IFERR(snprintf_s(item_str, FORMAT_ITEM_BUFFER_SIZE, FORMAT_ITEM_BUFFER_SIZE - 1, "%02d",
tz_minute));
break;
default:
return OG_SUCCESS;
}
if (append_text.str == NULL) {
return cm_concat_string(date_text, max_len, item_str);
}
cm_concat_text(date_text, max_len, &append_text);
return OG_SUCCESS;
}
static uint32 cm_get_day_of_year(const date_detail_t *detail)
{
uint32 days;
uint32 i;
CM_POINTER(detail);
if (cm_is_all_zero_time(detail)) {
days = 0;
return days;
}
uint16 *day_tab = (uint16 *)g_month_days[IS_LEAP_YEAR(detail->year)];
days = 0;
for (i = 0; i < ((uint32)detail->mon > 0 ? (uint32)detail->mon - 1 : 0); i++) {
days += day_tab[i];
}
days += (uint32)detail->day;
return days;
}
#define CM_DAYS_PER_WEEK 7
static inline int32 cm_get_day_of_week(const date_detail_t *detail)
{
int32 day_of_week = total_days_before_date(detail) + CM_BASELINE_DAY;
day_of_week %= CM_DAYS_PER_WEEK;
if (day_of_week < 0) {
day_of_week += CM_DAYS_PER_WEEK;
}
CM_ASSERT(day_of_week >= 0 && day_of_week < CM_DAYS_PER_WEEK);
return day_of_week;
}
void cm_get_detail_ex(const date_detail_t *detail, date_detail_ex_t *detail_ex)
{
CM_POINTER2(detail, detail_ex);
detail_ex->day_of_week = (uint8)cm_get_day_of_week(detail);
detail_ex->is_am = (bool32)(detail->hour < 12);
detail_ex->quarter = (uint8)((detail->mon - 1) / 3 + 1);
detail_ex->day_of_year = (uint16)cm_get_day_of_year(detail);
detail_ex->week = (uint8)((detail_ex->day_of_year - 1) / 7 + 1);
detail_ex->seconds = (uint32)(detail->hour * 3600 + detail->min * 60 + detail->sec);
}
static status_t cm_detail2text(date_detail_t *detail, text_t *fmt, uint32 precision, text_t *text,
uint32 max_len)
{
date_detail_ex_t detail_ex;
format_item_t *item = NULL;
text_t fmt_extra = { .str = NULL, .len = 0 };
CM_POINTER3(detail, fmt, text);
cm_get_detail_ex(detail, &detail_ex);
text->len = 0;
while (fmt->len > 0) {
if (cm_fetch_format_item(fmt, &item, &fmt_extra, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if ((!cm_validate_timezone(detail->tz_offset)) && (item->id == FMT_TZ_HOUR || item->id == FMT_TZ_MINUTE)) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (detail->day == 0 && (item->id == FMT_DAY_NAME || item->id == FMT_DAY_ABBR_NAME)) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (detail->mon == 0 &&
(item->id == FMT_MONTH_ABBR_NAME || item->id == FMT_MONTH_RM || item->id == FMT_MONTH_NAME)) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
OG_RETURN_IFERR(cm_append_date_text(detail, &detail_ex, item,
&fmt_extra, precision, text, max_len));
}
CM_NULL_TERM(text);
return OG_SUCCESS;
}
status_t cm_verify_date_fmt(const text_t *fmt)
{
format_item_t *fmt_item = NULL;
uint32 mask = 0;
text_t fmt_extra;
text_t fmt_text = *fmt;
while (fmt_text.len > 0) {
if (cm_fetch_format_item(&fmt_text, &fmt_item, &fmt_extra, OG_FALSE) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_UNRECOGNIZED_FORMAT_ERROR);
return OG_ERROR;
}
if (!fmt_item->reversible || !fmt_item->dt_used) {
OG_THROW_ERROR(ERR_TEXT_FORMAT_ERROR, "date");
return OG_ERROR;
}
if ((mask & fmt_item->fmask) != 0) {
OG_THROW_ERROR(ERR_MUTIPLE_FORMAT_ERROR);
return OG_ERROR;
}
mask |= fmt_item->fmask;
}
return OG_SUCCESS;
}
status_t cm_verify_timestamp_fmt(const text_t *fmt)
{
format_item_t *fmt_item = NULL;
uint32 mask = 0;
text_t fmt_extra;
text_t fmt_text = *fmt;
while (fmt_text.len > 0) {
if (cm_fetch_format_item(&fmt_text, &fmt_item, &fmt_extra, OG_FALSE) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_UNRECOGNIZED_FORMAT_ERROR);
return OG_ERROR;
}
if (!fmt_item->reversible) {
OG_THROW_ERROR(ERR_TEXT_FORMAT_ERROR, "timestamp");
return OG_ERROR;
}
if ((mask & fmt_item->fmask) != 0) {
OG_THROW_ERROR(ERR_MUTIPLE_FORMAT_ERROR);
return OG_ERROR;
}
mask |= fmt_item->fmask;
}
return OG_SUCCESS;
}
status_t cm_date2text_ex(date_t date, text_t *fmt, uint32 precision, text_t *text, uint32 max_len)
{
date_detail_t detail;
text_t format_text;
CM_POINTER(text);
cm_decode_date(date, &detail);
if (fmt == NULL || fmt->str == NULL) {
cm_default_nls_geter(NLS_DATE_FORMAT, &format_text);
} else {
format_text = *fmt;
}
return cm_detail2text(&detail, &format_text, precision, text, max_len);
}
status_t cm_timestamp2text_ex(timestamp_t ts, text_t *fmt, uint32 precision, text_t *text,
uint32 max_len)
{
date_detail_t detail;
text_t format_text;
CM_POINTER(text);
cm_decode_date(ts, &detail);
if (fmt == NULL || fmt->str == NULL) {
cm_default_nls_geter(NLS_TIMESTAMP_FORMAT, &format_text);
} else {
format_text = *fmt;
}
return cm_detail2text(&detail, &format_text, precision, text, max_len);
}
status_t cm_timestamp_tz2text_ex(timestamp_tz_t *tstz, text_t *fmt, uint32 precision, text_t *text,
uint32 max_len)
{
date_detail_t detail;
text_t format_text;
CM_POINTER(text);
cm_decode_date(tstz->tstamp, &detail);
detail.tz_offset = tstz->tz_offset;
if (fmt == NULL || fmt->str == NULL) {
cm_default_nls_geter(NLS_TIMESTAMP_FORMAT, &format_text);
} else {
format_text = *fmt;
}
return cm_detail2text(&detail, &format_text, precision, text, max_len);
}
status_t cm_time2text(time_t time, text_t *fmt, text_t *text, uint32 max_len)
{
date_detail_t detail;
text_t format_text;
CM_POINTER2(fmt, text);
cm_decode_time(time, &detail);
if (fmt == NULL || fmt->str == NULL) {
cm_default_nls_geter(NLS_DATE_FORMAT, &format_text);
} else {
format_text = *fmt;
}
return cm_detail2text(&detail, &format_text, OG_MAX_DATETIME_PRECISION, text, max_len);
}
date_t cm_time2date(time_t time)
{
date_detail_t detail;
cm_decode_time(time, &detail);
return cm_encode_date(&detail);
}
time_t cm_date2time(date_t date)
{
date_detail_t detail;
cm_decode_date(date, &detail);
return cm_encode_time(&detail);
}
date_t cm_timestamp2date(date_t date_input)
{
int64 time;
uint16 millisec;
uint16 microsec;
int64 date = date_input;
time = date;
date -= (date / UNITS_PER_DAY) * UNITS_PER_DAY;
if (date < 0) {
date += UNITS_PER_DAY;
}
microsec = (uint16)(date % MICROSECS_PER_MILLISEC);
millisec = (uint16)((date / MICROSECS_PER_MILLISEC) % MILLISECS_PER_SECOND);
return (time - millisec * MICROSECS_PER_MILLISEC - microsec);
}
static inline int64 cm_scn_delta(void)
{
return CM_UNIX_EPOCH + CM_HOST_TIMEZONE;
}
void cm_date2timeval(date_t date, struct timeval *val)
{
int64 value = date - cm_scn_delta();
val->tv_sec = (long)(value / 1000000);
val->tv_usec = (long)(value % 1000000);
}
date_t cm_timeval2date(struct timeval tv)
{
date_t dt = cm_scn_delta();
dt += ((int64)tv.tv_sec * MICROSECS_PER_SECOND + tv.tv_usec);
return dt;
}
date_t cm_timeval2realdate(struct timeval tv)
{
date_t dt = cm_scn_delta();
dt += ((int64)tv.tv_sec * MICROSECS_PER_SECOND);
return dt;
}
* convert time_t to str
* @param time, format, string(out)
*/
status_t cm_time2str(time_t time, const char *fmt, char *str, uint32 str_max_size)
{
text_t fmt_text;
text_t time_text;
cm_str2text((char *)fmt, &fmt_text);
time_text.str = str;
time_text.len = 0;
return cm_time2text(time, &fmt_text, &time_text, str_max_size);
}
typedef struct st_month_name_entry {
text_t full_name;
text_t abbr_name;
} month_name_entry_t;
static const month_name_entry_t g_month_names_en[] = {
{ { .str = "JANUARY", .len = 7 }, { .str = "JAN", .len = 3 } },
{ { .str = "FEBRUARY", .len = 8 }, { .str = "FEB", .len = 3 } },
{ { .str = "MARCH", .len = 5 }, { .str = "MAR", .len = 3 } },
{ { .str = "APRIL", .len = 5 }, { .str = "APR", .len = 3 } },
{ { .str = "MAY", .len = 3 }, { .str = "MAY", .len = 3 } },
{ { .str = "JUNE", .len = 4 }, { .str = "JUN", .len = 3 } },
{ { .str = "JULY", .len = 4 }, { .str = "JUL", .len = 3 } },
{ { .str = "AUGUST", .len = 6 }, { .str = "AUG", .len = 3 } },
{ { .str = "SEPTEMBER", .len = 9 }, { .str = "SEP", .len = 3 } },
{ { .str = "OCTOBER", .len = 7 }, { .str = "OCT", .len = 3 } },
{ { .str = "NOVEMBER", .len = 8 }, { .str = "NOV", .len = 3 } },
{ { .str = "DECEMBER", .len = 8 }, { .str = "DEC", .len = 3 } }
};
static const text_t g_nls_american = { .len = 8, .str = (char *)"AMERICAN" };
static const text_t g_nls_english = { .len = 7, .str = (char *)"ENGLISH" };
static const text_t g_nls_english_us = { .len = 10, .str = (char *)"ENGLISH_US" };
static const text_t g_nls_america = { .len = 7, .str = (char *)"AMERICA" };
typedef struct st_date_nls_params {
text_t language;
text_t territory;
bool32 is_set;
} date_nls_params_t;
static status_t cm_get_month_by_name(text_t *date_text, uint32 *mask, uint8 *mon,
const date_nls_params_t *nls_params)
{
text_t cmp_text;
const month_name_entry_t *month_table = g_month_names_en;
CM_POINTER3(date_text, mask, mon);
if ((*mask & MASK_MONTH) != 0) {
return OG_ERROR;
}
if (date_text->len < DATE_MIN_LEN) {
return OG_ERROR;
}
if (nls_params != NULL && nls_params->is_set && nls_params->language.len > 0) {
if (cm_text_equal_ins(&nls_params->language, &g_nls_american) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english_us) ||
cm_text_equal_ins(&nls_params->language, &g_nls_america)) {
month_table = g_month_names_en;
} else {
return OG_ERROR;
}
}
*mask |= MASK_MONTH;
cmp_text.str = date_text->str;
for (uint32 i = 0; i < 12; i++) {
if (date_text->len < month_table[i].full_name.len) {
continue;
}
cmp_text.len = month_table[i].full_name.len;
if (!cm_text_equal_ins(&cmp_text, &month_table[i].full_name)) {
continue;
}
*mon = (uint8)(i + 1);
date_text->len -= month_table[i].full_name.len;
date_text->str += month_table[i].full_name.len;
return OG_SUCCESS;
}
return OG_ERROR;
}
static status_t cm_get_month_by_abbr_name(text_t *date_text, uint32 *mask, uint8 *mon,
const date_nls_params_t *nls_params)
{
text_t cmp_text;
text_t mon_text;
const month_name_entry_t *month_table = g_month_names_en;
CM_POINTER3(date_text, mask, mon);
if ((*mask & MASK_MONTH) != 0) {
return OG_ERROR;
}
*mask |= MASK_MONTH;
if (date_text->len < 3) {
return OG_ERROR;
}
if (nls_params != NULL && nls_params->is_set && nls_params->language.len > 0) {
if (cm_text_equal_ins(&nls_params->language, &g_nls_american) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english_us) ||
cm_text_equal_ins(&nls_params->language, &g_nls_america)) {
month_table = g_month_names_en;
} else {
return OG_ERROR;
}
}
cmp_text.str = date_text->str;
cmp_text.len = 3;
mon_text.len = 3;
for (uint32 i = 0; i < 12; i++) {
mon_text.str = month_table[i].abbr_name.str;
if (!cm_text_equal_ins(&cmp_text, &mon_text)) {
continue;
}
*mon = (uint8)(i + 1);
date_text->len -= 3;
date_text->str += 3;
return OG_SUCCESS;
}
return OG_ERROR;
}
static status_t cm_get_month_by_roman_name(text_t *date_text, uint32 *mask, uint8 *mon)
{
text_t cmp_text;
CM_POINTER3(date_text, mask, mon);
if ((*mask & MASK_MONTH) != 0) {
return OG_ERROR;
}
if (date_text->len == 0) {
return OG_ERROR;
}
*mask |= MASK_MONTH;
cmp_text.str = date_text->str;
for (int32 i = 11; i >= 0; i--) {
if (date_text->len < g_month_roman_names[i].len) {
continue;
}
cmp_text.len = g_month_roman_names[i].len;
if (!cm_text_equal_ins(&cmp_text, &g_month_roman_names[i])) {
continue;
}
*mon = (uint8)(i + 1);
date_text->len -= g_month_roman_names[i].len;
date_text->str += g_month_roman_names[i].len;
return OG_SUCCESS;
}
return OG_ERROR;
}
typedef struct st_day_name_entry {
text_t full_name;
text_t abbr_name;
} day_name_entry_t;
static const day_name_entry_t g_day_names_en[] = {
{ { .str = "SUNDAY", .len = 6 }, { .str = "SUN", .len = 3 } },
{ { .str = "MONDAY", .len = 6 }, { .str = "MON", .len = 3 } },
{ { .str = "TUESDAY", .len = 7 }, { .str = "TUE", .len = 3 } },
{ { .str = "WEDNESDAY", .len = 9 }, { .str = "WED", .len = 3 } },
{ { .str = "THURSDAY", .len = 8 }, { .str = "THU", .len = 3 } },
{ { .str = "FRIDAY", .len = 6 }, { .str = "FRI", .len = 3 } },
{ { .str = "SATURDAY", .len = 8 }, { .str = "SAT", .len = 3 } }
};
static status_t cm_get_day_by_name(text_t *date_text, uint32 *mask, uint8 *day,
const date_nls_params_t *nls_params)
{
text_t cmp_text;
const day_name_entry_t *day_table = g_day_names_en;
CM_POINTER3(date_text, mask, day);
if ((*mask & MASK_DOW) != 0) {
return OG_ERROR;
}
if (date_text->len < 3) {
return OG_ERROR;
}
if (nls_params != NULL && nls_params->is_set && nls_params->language.len > 0) {
if (cm_text_equal_ins(&nls_params->language, &g_nls_american) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english_us) ||
cm_text_equal_ins(&nls_params->language, &g_nls_america)) {
day_table = g_day_names_en;
} else {
return OG_ERROR;
}
}
*mask |= MASK_DOW;
cmp_text.str = date_text->str;
for (uint32 i = 0; i < 7; i++) {
if (date_text->len < day_table[i].full_name.len) {
continue;
}
cmp_text.len = day_table[i].full_name.len;
if (!cm_text_equal_ins(&cmp_text, &day_table[i].full_name)) {
continue;
}
*day = (uint8)i;
date_text->len -= day_table[i].full_name.len;
date_text->str += day_table[i].full_name.len;
return OG_SUCCESS;
}
return OG_ERROR;
}
static status_t cm_get_day_by_abbr_name(text_t *date_text, uint32 *mask, uint8 *day,
const date_nls_params_t *nls_params)
{
text_t cmp_text;
text_t day_text;
const day_name_entry_t *day_table = g_day_names_en;
CM_POINTER3(date_text, mask, day);
if ((*mask & MASK_DOW) != 0) {
return OG_ERROR;
}
*mask |= MASK_DOW;
if (date_text->len < 3) {
return OG_ERROR;
}
if (nls_params != NULL && nls_params->is_set && nls_params->language.len > 0) {
if (cm_text_equal_ins(&nls_params->language, &g_nls_american) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english) ||
cm_text_equal_ins(&nls_params->language, &g_nls_english_us) ||
cm_text_equal_ins(&nls_params->language, &g_nls_america)) {
day_table = g_day_names_en;
} else {
return OG_ERROR;
}
}
cmp_text.str = date_text->str;
cmp_text.len = TEXT_LEN;
day_text.len = TEXT_LEN;
for (uint32 i = 0; i < DAYS_PER_WEEK; i++) {
day_text.str = day_table[i].abbr_name.str;
if (!cm_text_equal_ins(&cmp_text, &day_text)) {
continue;
}
*day = (uint8)i;
date_text->len -= TEXT_LEN;
date_text->str += TEXT_LEN;
return OG_SUCCESS;
}
return OG_ERROR;
}
static inline void cm_init_nls_params(date_nls_params_t *params)
{
params->language.str = NULL;
params->language.len = 0;
params->territory.str = NULL;
params->territory.len = 0;
params->is_set = OG_FALSE;
}
static const text_t g_nls_language = { .len = 17, .str = (char *)"NLS_DATE_LANGUAGE" };
static const text_t g_nls_territory = { .len = 13, .str = (char *)"NLS_TERRITORY" };
static status_t cm_parse_nls_params(const text_t *nls_text, date_nls_params_t *params)
{
text_t remaining;
text_t key;
text_t value;
remaining = *nls_text;
cm_trim_text(&remaining);
while (remaining.len > 0) {
if (cm_text_split_on_char(&remaining, '=', &key, &value) != OG_SUCCESS) {
return OG_ERROR;
}
if (cm_text_equal_ins(&key, &g_nls_language)) {
params->language = value;
params->is_set = 1;
} else if (cm_text_equal_ins(&key, &g_nls_territory)) {
params->territory = value;
params->is_set = 1;
} else {
return OG_ERROR;
}
cm_text_skip_spaces(&remaining);
if (remaining.len > 0 && remaining.str[0] == ',') {
cm_text_remove_head(&remaining, 1);
}
cm_text_skip_spaces(&remaining);
}
return OG_SUCCESS;
}
static status_t cm_check_number(text_t *num_text,
uint32 size,
int64 start,
int64 end,
int64 *num_val)
{
char num[8];
CM_POINTER2(num_text, num_val);
if (size >= sizeof(num)) {
return OG_ERROR;
}
if (size != 0) {
MEMS_RETURN_IFERR(memcpy_sp(num, sizeof(num), num_text->str, (size_t)size));
}
num[size] = '\0';
*num_val = (int64)atoi(num);
if (*num_val >= start && *num_val <= end) {
return OG_SUCCESS;
} else {
return OG_ERROR;
}
}
static status_t cm_check_number_with_sign(text_t *num_text,
uint32 size,
int32 start,
int32 end,
int32 *num_val)
{
char num[8];
status_t status;
text_t number_text_src;
CM_POINTER2(num_text, num_val);
if (size >= sizeof(num)) {
return OG_ERROR;
}
if (size != 0) {
MEMS_RETURN_IFERR(memcpy_sp(num, sizeof(num), num_text->str, (size_t)size));
}
num[size] = '\0';
number_text_src.str = num;
number_text_src.len = size;
status = cm_text2int(&number_text_src, num_val);
OG_RETURN_IFERR(status);
if (*num_val >= start && *num_val <= end) {
return OG_SUCCESS;
} else {
return OG_ERROR;
}
}
static uint32 cm_get_num_len_in_str(const text_t *text, uint32 part_len, bool32 with_sign)
{
uint32 i;
CM_POINTER(text);
for (i = 0; i < MIN(part_len, text->len); i++) {
if (!CM_IS_DIGIT(text->str[i])) {
if (with_sign && (i == 0 && CM_IS_SIGN_CHAR(text->str[i]))) {
continue;
} else {
return i;
}
}
}
return i;
}
* \brief Revise this function in order to enable to handle 9 digital precision
* (i.e., nanoseconds).
*
*/
static inline status_t cm_verify_number(const text_t *num_text, uint32 size, uint32 start, uint32 end,
uint32 *num_value, uint32 *act_len_val)
{
uint32 i;
char num[11] = "0000000000";
uint32 act_len;
CM_POINTER2(num_text, num_value);
act_len = (num_text->len) < size ? num_text->len : size;
*act_len_val = act_len;
for (i = 0; i < act_len; i++) {
if (*(num_text->str + i) == ' ') {
act_len = i;
*act_len_val = i;
break;
}
if (!(*(num_text->str + i) >= '0' && *(num_text->str + i) <= '9')) {
return OG_ERROR;
}
}
if (act_len != 0) {
MEMS_RETURN_IFERR(memcpy_sp(num, sizeof(num), num_text->str, (size_t)act_len));
}
* For example, using FF3 for .12, the expected num_value should be 120 milliseconds.
* Since num is initially set by all zeros, therefore, the end position should be specified. */
num[size] = '\0';
*num_value = (uint32)atoi(num);
if (*num_value >= start && *num_value <= end) {
return OG_SUCCESS;
} else {
return OG_ERROR;
}
}
static inline status_t cm_verify_part(text_t *date_text,
uint32 *mask,
date_time_mask_t mask_id,
uint32 part_len,
uint32 start_value,
uint32 end_value,
uint32 *part_value)
{
uint32 act_len;
if ((*mask & mask_id) != 0) {
return OG_ERROR;
}
cm_trim_text(date_text);
if (cm_verify_number(date_text, part_len, start_value, end_value, part_value, &act_len) != OG_SUCCESS) {
return OG_ERROR;
}
*mask |= mask_id;
if (date_text->len < part_len) {
date_text->str += date_text->len;
date_text->len = 0;
} else {
date_text->len -= act_len;
date_text->str += act_len;
}
return OG_SUCCESS;
}
static inline uint32 cm_find_point(text_t *date_text)
{
uint32 len = date_text->len;
uint32 i = 0;
for (; i < len; i++) {
if (date_text->str[i] == '.') {
break;
}
}
return i;
}
static status_t cm_get_number_and_check(const char *name, uint32 part_length, int64 begin,
int64 end, text_t *date_txt, int64 *number_value)
{
uint16 item_length = cm_get_num_len_in_str(date_txt, part_length, OG_FALSE);
if (item_length == 0 ||
cm_check_number(date_txt, item_length, begin, end, number_value) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, name, begin, end);
return OG_ERROR;
}
date_txt->len -= item_length;
date_txt->str += item_length;
return OG_SUCCESS;
}
static status_t cm_get_num_and_check_with_sign(const char *name, uint32 part_len, int32 start,
int32 end, text_t *date_text, int32 *num_value)
{
uint16 item_len = cm_get_num_len_in_str(date_text, part_len, OG_TRUE);
if (item_len == 0 ||
cm_check_number_with_sign(date_text, item_len, start, end, num_value) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, name, start, end);
return OG_ERROR;
}
date_text->len -= item_len;
date_text->str += item_len;
return OG_SUCCESS;
}
static inline status_t cm_verify_mask(uint32 *mask, date_time_mask_t mask_id)
{
OG_RETVALUE_IFTRUE((*(mask) & (mask_id)), OG_ERROR);
*mask |= mask_id;
return OG_SUCCESS;
}
static inline status_t cm_get_date_item(text_t *date_text,
const format_item_t *fmt_item,
text_t *fmt_extra,
date_detail_t *date,
uint32 *mask,
const date_nls_params_t *nls_params)
{
text_t part_text;
int64 num_value = 0;
int32 num_value_with_sign = 0;
bool8 neg = 0;
uint32 item_len = 0;
status_t status = 0;
CM_POINTER4(date_text, fmt_item, date, mask);
part_text.str = date_text->str;
switch (fmt_item->id) {
case FMT_SPACE:
case FMT_MINUS:
case FMT_BACK_SLASH:
case FMT_COMMA:
case FMT_DOT:
case FMT_SEMI_COLON:
case FMT_COLON:
cm_check_special_char(date_text);
break;
case FMT_SLASH:
part_text.len = 1;
if (!cm_text_equal_ins(&part_text, &fmt_item->name)) {
return OG_ERROR;
}
CM_REMOVE_FIRST(date_text);
break;
case FMT_X:
part_text.len = 1;
if (!cm_text_equal_ins(&part_text, &fmt_item->name)) {
if (!cm_text_str_equal(&part_text, (const char *)".")) {
return OG_ERROR;
}
}
CM_REMOVE_FIRST(date_text);
break;
case FMT_DQ_TEXT:
part_text.len = fmt_extra->len;
if (!cm_text_equal_ins(&part_text, fmt_extra)) {
return OG_ERROR;
}
CM_REMOVE_FIRST_N(date_text, fmt_extra->len);
break;
case FMT_MONTH_NAME:
return cm_get_month_by_name(date_text, mask, &date->mon, nls_params);
case FMT_MONTH_RM:
return cm_get_month_by_roman_name(date_text, mask, &date->mon);
case FMT_MONTH_ABBR_NAME:
return cm_get_month_by_abbr_name(date_text, mask, &date->mon, nls_params);
case FMT_DAY_NAME:
return cm_get_day_by_name(date_text, mask, &date->day, nls_params);
case FMT_DAY_ABBR_NAME:
return cm_get_day_by_abbr_name(date_text, mask, &date->day, nls_params);
case FMT_AM:
case FMT_PM:
case FMT_A_M:
case FMT_P_M:
case FMT_AM_INDICATOR:
case FMT_PM_INDICATOR: {
if (date_text->len < fmt_item->name.len) {
return OG_ERROR;
}
text_t input_part = { .str = date_text->str, .len = fmt_item->name.len };
if (!cm_text_equal_ins(&input_part, &fmt_item->name)) {
return OG_ERROR;
}
bool32 is_pm = (fmt_item->id == FMT_PM ||
fmt_item->id == FMT_P_M ||
fmt_item->id == FMT_PM_DOT ||
fmt_item->id == FMT_PM_INDICATOR);
if ((*mask & MASK_HOUR) != 0) {
if (date->hour == HOUR_12) {
date->hour = is_pm ? HOUR_12 : HOUR_0;
} else if (is_pm) {
date->hour += HOUR_12;
}
}
*mask |= MASK_AM_PM;
CM_REMOVE_FIRST_N(date_text, fmt_item->name.len);
break;
}
case FMT_DAY_OF_MONTH:
cm_check_special_char(date_text);
status = cm_verify_mask(mask, MASK_DAY);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("DAY", DAY_FIELD_INDEX, DAY_MIN_VALUE,
DAY_MAX_VALUE, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->day = (uint8)num_value;
break;
case FMT_FRAC_SECOND1:
case FMT_FRAC_SECOND2:
case FMT_FRAC_SECOND3:
case FMT_FRAC_SECOND4:
case FMT_FRAC_SECOND5:
case FMT_FRAC_SECOND6:
case FMT_FRAC_SEC_VAR_LEN:
cm_check_special_char(date_text);
if (fmt_item->placer <= 0) {
OG_THROW_ERROR_EX(ERR_ASSERT_ERROR, "fmt_item->placer(%d) > 0", fmt_item->placer);
return OG_ERROR;
}
if (cm_verify_part(date_text, mask, MASK_USEC, (fmt_item->placer), 0, 999999, (uint32 *)&num_value) !=
OG_SUCCESS) {
return OG_ERROR;
}
num_value *= g_1ten_powers[6 - fmt_item->placer];
date->microsec = num_value % MICROSECS_PER_MILLISEC;
date->millisec = num_value / MICROSECS_PER_MILLISEC;
break;
case FMT_HOUR_OF_DAY12:
cm_check_special_char(date_text);
status = cm_verify_mask(mask, MASK_HOUR);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("HOUR", 2, 1, 12, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->hour = (uint8)num_value;
break;
case FMT_HOUR_OF_DAY24:
if (*((date_text)->str) == '-') {
neg = 1;
}
cm_check_special_char(date_text);
item_len = cm_find_point(date_text);
status = cm_verify_mask(mask, MASK_HOUR);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
if ((item_len % EVEN_NUM) == 0) {
status = cm_get_number_and_check("HOUR", 2, -99, 99, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
} else {
status = cm_get_number_and_check("HOUR", 3, -838, 838, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
}
date->hour = (int32)num_value;
date->neg = neg;
break;
case FMT_MINUTE:
cm_check_special_char(date_text);
status = cm_verify_mask(mask, MASK_MINUTE);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("MINUTE", 2, 0, 59, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->min = (uint8)num_value;
break;
case FMT_MONTH:
cm_check_special_char(date_text);
status = cm_verify_mask(mask, MASK_MONTH);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("MONTH", 2, 1, 12, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->mon = (uint8)num_value;
break;
case FMT_SECOND:
cm_check_special_char(date_text);
status = cm_verify_mask(mask, MASK_SECOND);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("SECOND", 2, 0, 59, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->sec = (uint8)num_value;
break;
case FMT_YEAR4:
status = cm_verify_mask(mask, MASK_YEAR);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("YEAR", 4, CM_MIN_YEAR, CM_MAX_YEAR, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->year = (uint16)num_value;
break;
case FMT_TZ_HOUR:
status = cm_verify_mask(mask, MASK_TZ_HOUR);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_num_and_check_with_sign("Time zone hour", 3, -12, 14, date_text, &num_value_with_sign);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
date->tz_offset = (timezone_info_t)(((int8)num_value_with_sign) * SECONDS_PER_MIN);
break;
case FMT_TZ_MINUTE:
status = cm_verify_mask(mask, MASK_TZ_MINUTE);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
status = cm_get_number_and_check("Time zone minute", 2, 0, 59, date_text, &num_value);
if (SECUREC_UNLIKELY(status != OG_SUCCESS)) {
cm_set_error_pos(__FILE__, __LINE__);
return status;
}
if (date->tz_offset < 0) {
date->tz_offset -= (uint8)num_value;
} else {
date->tz_offset += (uint8)num_value;
}
break;
default:
break;
}
return OG_SUCCESS;
}
static status_t cm_text2date_detail(const text_t *text, const text_t *fmt,
const date_nls_params_t *nls_params,
date_detail_t *datetime, uint32 datetype)
{
format_item_t *fmt_item = NULL;
uint32 mask;
text_t fmt_text;
text_t date_text;
text_t fmt_extra = { .str = NULL, .len = 0 };
CM_POINTER3(text, fmt, datetime);
fmt_text = *fmt;
date_text = *text;
cm_trim_text(&fmt_text);
cm_trim_text(&date_text);
mask = 0;
while (fmt_text.len > 0) {
if (cm_fetch_format_item(&fmt_text, &fmt_item, &fmt_extra, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
if (!fmt_item->reversible) {
return OG_ERROR;
}
cm_trim_text(&date_text);
if (CM_IS_EMPTY(&date_text)) {
break;
}
if (cm_get_date_item(&date_text, fmt_item, &fmt_extra, datetime, &mask, nls_params) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (date_text.len > 0) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_adjust_timestamp(timestamp_t *ts, int32 precision)
{
if (precision == OG_MAX_DATETIME_PRECISION || *ts == 0) {
return OG_SUCCESS;
}
*ts = (timestamp_t)cm_truncate_bigint(*ts, (uint32)(OG_MAX_DATETIME_PRECISION - precision));
if (!CM_IS_VALID_TIMESTAMP(*ts)) {
OG_THROW_ERROR(ERR_TYPE_OVERFLOW, "DATETIME");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_adjust_timestamp_tz(timestamp_tz_t *tstz, int32 precision)
{
return cm_adjust_timestamp(&tstz->tstamp, precision);
}
status_t cm_check_tstz_is_valid(timestamp_tz_t *tstz)
{
if (!CM_IS_VALID_TIMESTAMP(tstz->tstamp)) {
return OG_ERROR;
}
if (!cm_validate_timezone(tstz->tz_offset)) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_text2timestamp_tz(const text_t *text, const text_t *fmt, timezone_info_t default_tz, timestamp_tz_t *tstz)
{
text_t fmt_text;
date_detail_t detail;
CM_POINTER(text);
if (fmt == NULL) {
cm_default_nls_geter(NLS_TIMESTAMP_TZ_FORMAT, &fmt_text);
} else {
fmt_text = *fmt;
}
cm_text2date_init(&detail);
detail.tz_offset = default_tz;
if (cm_text2date_detail(text, &fmt_text, NULL, &detail, OG_TYPE_TIMESTAMP_TZ) != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (!cm_check_valid_zero_time(&detail)) {
return OG_ERROR;
}
cm_encode_timestamp_tz(&detail, tstz);
if (cm_check_tstz_is_valid(tstz)) {
OG_THROW_ERROR(ERR_TYPE_OVERFLOW, "TIMESTAMP_TZ");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_text2date(const text_t *text, const text_t *fmt, date_t *date)
{
text_t fmt_text;
date_detail_t detail;
CM_POINTER(text);
if (fmt == NULL) {
cm_default_nls_geter(NLS_DATE_FORMAT, &fmt_text);
} else {
fmt_text = *fmt;
}
cm_text2date_init(&detail);
if (cm_text2date_detail(text, &fmt_text, NULL, &detail, OG_TYPE_DATE) != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (!cm_check_valid_zero_time(&detail)) {
return OG_ERROR;
}
*date = cm_encode_date(&detail);
if (!CM_IS_VALID_TIMESTAMP(*date)) {
OG_THROW_ERROR(ERR_TYPE_OVERFLOW, "DATETIME");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_str2time(char *date, const text_t *fmt, time_t *time_stamp)
{
text_t date_text;
date_t date_stamp;
if (strlen(date) == 0) {
OG_THROW_ERROR(ERR_TEXT_FORMAT_ERROR, "date");
return OG_ERROR;
}
cm_str2text(date, &date_text);
OG_RETURN_IFERR(cm_text2date(&date_text, fmt, &date_stamp));
*time_stamp = cm_date2time(date_stamp);
return OG_SUCCESS;
}
static void cm_text2date_fixed_init(date_detail_t *datetime)
{
og_timer_t *now = g_timer();
datetime->year = now->detail.year;
datetime->mon = now->detail.mon;
datetime->day = 1;
datetime->hour = 0;
datetime->min = 0;
datetime->sec = 0;
datetime->millisec = 0;
datetime->microsec = 0;
datetime->nanosec = 0;
datetime->tz_offset = TIMEZONE_OFFSET_ZERO;
}
status_t static cm_is_time_valid(date_detail_t *detail)
{
OG_RETVALUE_IFTRUE(detail == NULL, OG_ERROR);
if (!CM_IS_VALID_HOUR(detail->hour)) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "HOUR", 0, 23);
return OG_ERROR;
}
if (!CM_IS_VALID_MINUTE(detail->min)) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "MINUTE", 0, 59);
return OG_ERROR;
}
if (!CM_IS_VALID_SECOND(detail->sec)) {
OG_THROW_ERROR(ERR_ILLEGAL_TIME, "SECOND", 0, 59);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_text2date_fixed(const text_t *text, const text_t *fmt, date_t *date,
timezone_info_t *tz_offset, bool32 is_date_fmt)
{
date_detail_t detail;
CM_POINTER2(text, fmt);
cm_text2date_fixed_init(&detail);
if (cm_text2date_detail(text, fmt, NULL, &detail, OG_TYPE_DATE) != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (!cm_check_valid_zero_time(&detail)) {
return OG_ERROR;
}
OG_RETURN_IFERR(cm_is_time_valid(&detail));
*date = cm_encode_date(&detail);
if (is_date_fmt) {
*date = cm_adjust_date(*date);
}
if (!CM_IS_VALID_TIMESTAMP(*date)) {
OG_THROW_ERROR(ERR_TYPE_OVERFLOW, "DATETIME");
return OG_ERROR;
}
*tz_offset = detail.tz_offset;
return OG_SUCCESS;
}
status_t cm_text2date_fixed_nls(const date_parse_params_t *params, date_t *date,
timezone_info_t *tz_offset)
{
date_detail_t detail;
CM_POINTER2(params, date);
date_nls_params_t nls_params;
bool32 has_nls = (params->nls != NULL && params->nls->len > 0);
if (has_nls) {
cm_init_nls_params(&nls_params);
if (cm_parse_nls_params(params->nls, &nls_params) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "invalid NLS parameter format");
return OG_ERROR;
}
}
cm_text2date_fixed_init(&detail);
if (cm_text2date_detail(params->text, params->fmt, has_nls ? &nls_params : NULL,
&detail, OG_TYPE_DATE) != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (!cm_check_valid_zero_time(&detail)) {
return OG_ERROR;
}
OG_RETURN_IFERR(cm_is_time_valid(&detail));
*date = cm_encode_date(&detail);
if (params->is_date_fmt) {
*date = cm_adjust_date(*date);
}
if (!CM_IS_VALID_TIMESTAMP(*date)) {
OG_THROW_ERROR(ERR_TYPE_OVERFLOW, "DATETIME");
return OG_ERROR;
}
*tz_offset = detail.tz_offset;
return OG_SUCCESS;
}
status_t cm_fetch_date_field(text_t *text, uint32 minval, uint32 maxval, char spilt_char, uint32 *field_val)
{
uint32 num_len;
int64 temp_field_val = 0;
cm_trim_text(text);
num_len = cm_get_num_len_in_str(text, text->len, OG_FALSE);
OG_RETVALUE_IFTRUE(num_len == 0, OG_ERROR);
OG_RETURN_IFERR(cm_check_number(text, num_len, minval, maxval, &temp_field_val));
*field_val = (uint32)temp_field_val;
text->str += num_len;
text->len -= num_len;
if (spilt_char != ' ') {
cm_ltrim_text(text);
}
if (spilt_char != '\0') {
if (text->len == num_len || *text->str != spilt_char) {
return OG_ERROR;
}
CM_REMOVE_FIRST(text);
cm_ltrim_text(text);
}
return OG_SUCCESS;
}
status_t cm_text2date_def(const text_t *text, date_t *date)
{
int32 ret = OG_ERROR;
uint32 field_val;
uint32 mon_days;
text_t date_text;
date_detail_t detail;
cm_text2date_init(&detail);
CM_POINTER2(text, date);
date_text = *text;
cm_trim_text(&date_text);
do {
OG_BREAK_IF_TRUE((date_text.len < 5));
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, CM_MIN_YEAR, CM_MAX_YEAR, '-', &field_val));
detail.year = (uint16)field_val;
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 1, 12, '-', &field_val));
detail.mon = (uint8)field_val;
mon_days = (uint32)g_month_days[IS_LEAP_YEAR(detail.year)][detail.mon - 1];
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 1, mon_days, '\0', &field_val));
detail.day = (uint8)field_val;
ret = (date_text.len == 0) ? OG_SUCCESS : OG_ERROR;
} while (0);
if (ret != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
(*date) = cm_encode_date(&detail);
return OG_SUCCESS;
}
status_t cm_text2timestamp_def(const text_t *text, date_t *date)
{
int32 ret = OG_ERROR;
char buf[8];
uint32 field_val;
uint32 mon_days;
text_t date_text;
date_detail_t detail;
cm_text2date_init(&detail);
CM_POINTER2(text, date);
date_text = *text;
cm_trim_text(&date_text);
do {
OG_BREAK_IF_TRUE((date_text.len < 11));
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, CM_MIN_YEAR, CM_MAX_YEAR, '-', &field_val));
detail.year = (uint16)field_val;
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 1, 12, '-', &field_val));
detail.mon = (uint8)field_val;
mon_days = (uint32)g_month_days[IS_LEAP_YEAR(detail.year)][detail.mon - 1];
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 1, mon_days, ' ', &field_val));
detail.day = (uint8)field_val;
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 0, 23, ':', &field_val));
detail.hour = (int16)field_val;
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 0, 59, ':', &field_val));
detail.min = (uint8)field_val;
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 0, 59, '\0', &field_val));
detail.sec = (uint8)field_val;
if (date_text.len == 0) {
ret = OG_SUCCESS;
break;
}
OG_BREAK_IF_TRUE(CM_TEXT_BEGIN(&date_text) != '.');
CM_REMOVE_FIRST(&date_text);
cm_ltrim_text(&date_text);
OG_BREAK_IF_TRUE((date_text.len == 0 || date_text.len > 6));
OG_RETURN_IFERR(cm_text2str(&date_text, buf, sizeof(buf)));
date_text.str = buf;
date_text.len = (uint32)strlen(buf);
while (date_text.len < 6) {
CM_TEXT_APPEND(&date_text, '0');
}
OG_BREAK_IF_ERROR(cm_fetch_date_field(&date_text, 0, 999999, '\0', &field_val));
detail.millisec = (uint16)(field_val / 1000);
detail.microsec = (uint16)(field_val % 1000);
ret = (date_text.len == 0) ? OG_SUCCESS : OG_ERROR;
} while (0);
if (ret != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
(*date) = cm_encode_date(&detail);
return OG_SUCCESS;
}
static status_t cm_numtext2date(const text_t *text, date_t *date)
{
status_t ret;
text_t date_fmt;
date_detail_t detail;
cm_text2date_init(&detail);
if (text->len == 8) {
date_fmt.str = (char *)"YYYYMMDD";
date_fmt.len = 8;
ret = cm_text2date_detail(text, &date_fmt, NULL, &detail, OG_TYPE_DATE);
} else if (text->len == 14) {
date_fmt.str = (char *)"YYYYMMDDHH24MISS";
date_fmt.len = 16;
ret = cm_text2date_detail(text, &date_fmt, NULL, &detail, OG_TYPE_DATE);
} else if (text->len > 14 && cm_char_in_text('.', text)) {
date_fmt.str = (char *)"YYYYMMDDHH24MISS.FF";
date_fmt.len = 19;
ret = cm_text2date_detail(text, &date_fmt, NULL, &detail, OG_TYPE_DATE);
} else {
ret = OG_ERROR;
}
if (ret != OG_SUCCESS) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (!cm_check_valid_zero_time(&detail)) {
return OG_ERROR;
}
(*date) = cm_encode_date(&detail);
return OG_SUCCESS;
}
status_t cm_text2date_flex(const text_t *text, date_t *date)
{
text_t date_text = *text;
cm_trim_text(&date_text);
if (cm_char_in_text('-', &date_text)) {
if (cm_char_in_text(':', &date_text)) {
return cm_text2timestamp_def(&date_text, date);
}
return cm_text2date_def(&date_text, date);
} else {
return cm_numtext2date(&date_text, date);
}
}
#ifdef WIN32
int cm_gettimeofday(struct timeval *tv)
{
if (tv == NULL) {
return 0;
}
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
uint64 temp = ((uint64)ft.dwLowDateTime | ((uint64)ft.dwHighDateTime << 32)) / 10;
temp -= OG_DELTA_EPOCH_IN_MICROSECS;
tv->tv_sec = (long)(temp / 1000000UL);
tv->tv_usec = (long)(temp % 1000000UL);
return 0;
}
#endif
static date_t cm_get_date_with_days(int32 total_days)
{
date_t date_tmp;
date_tmp = (int64)total_days * SECONDS_PER_DAY;
date_tmp = date_tmp * MILLISECS_PER_SECOND;
date_tmp = date_tmp * MICROSECS_PER_MILLISEC;
return date_tmp;
}
status_t cm_round_date(date_t date, text_t *fmt, date_t *result)
{
date_detail_t detail;
date_detail_ex_t detail_ex;
format_item_t *item = NULL;
text_t fmt_extra = { .str = NULL, .len = 0 };
int32 total_days;
uint8 current_w_day;
uint8 next_w_day;
uint16 *day_tab = NULL;
double double_day1;
double double_day2;
bool32 need_round = OG_FALSE;
cm_decode_date(date, &detail);
cm_get_detail_ex(&detail, &detail_ex);
OG_RETURN_IFERR(cm_fetch_format_item(fmt, &item, &fmt_extra, OG_FALSE));
switch (item->id) {
case FMT_CENTURY:
{
detail.year = (uint16)((detail.year / 100) * 100 + 1);
detail.mon = 1;
detail.day = 1;
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_DAY_OF_WEEK:
case FMT_DAY_NAME:
case FMT_DAY_ABBR_NAME:
{
total_days = total_days_before_date(&detail);
total_days = total_days - detail_ex.day_of_week;
if (detail_ex.day_of_week >= 3 && detail.hour >= 12) {
total_days += 7;
}
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_WEEK_OF_YEAR:
{
total_days = total_days_before_date(&detail);
total_days = total_days - detail_ex.day_of_week + 1;
if (detail_ex.day_of_week >= 4 && detail.hour >= 12) {
total_days += 7;
}
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_WEEK_OF_MONTH:
{
current_w_day = (uint8)(((detail.day - 1) / 7) * 7 + 1);
day_tab = (uint16 *)g_month_days[IS_LEAP_YEAR(detail.year)];
if (current_w_day + 7 > day_tab[detail.mon - 1]) {
next_w_day = current_w_day;
} else {
next_w_day = current_w_day + 7;
}
double_day1 = detail.day + ((detail.hour >= 12) ? 1 : 0);
double_day2 = (double)(current_w_day + next_w_day) / 2;
if (double_day1 > double_day2) {
detail.day = next_w_day;
} else {
detail.day = current_w_day;
}
total_days = total_days_before_date(&detail);
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_DAY_OF_MONTH:
case FMT_DAY_OF_YEAR:
{
if (detail.hour >= 12) {
total_days = total_days_before_date(&detail) + 1;
} else {
total_days = total_days_before_date(&detail);
}
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_MONTH:
case FMT_MONTH_RM:
case FMT_MONTH_ABBR_NAME:
case FMT_MONTH_NAME:
{
need_round = (detail.day >= 16);
detail.day = 1;
total_days = total_days_before_date(&detail);
if (need_round) {
day_tab = (uint16 *)g_month_days[IS_LEAP_YEAR(detail.year)];
total_days += (int32)day_tab[detail.mon - 1];
}
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_QUARTER:
{
if (detail.mon < 2 || (detail.mon == 2 && detail.day < 16)) {
detail.mon = 1;
} else if (detail.mon < 5 || (detail.mon == 5 && detail.day < 16)) {
detail.mon = 4;
} else if (detail.mon < 8 || (detail.mon == 8 && detail.day < 16)) {
detail.mon = 7;
} else if (detail.mon < 11 || (detail.mon == 11 && detail.day < 16)) {
detail.mon = 10;
} else {
detail.year += 1;
detail.mon = 1;
}
detail.day = 1;
total_days = total_days_before_date(&detail);
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_YEAR1:
case FMT_YEAR2:
case FMT_YEAR3:
case FMT_YEAR4:
{
if (detail.mon >= 7) {
detail.year += 1;
}
detail.mon = 1;
detail.day = 1;
total_days = total_days_before_date(&detail);
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_HOUR_OF_DAY12:
case FMT_HOUR_OF_DAY24:
{
detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_MINUTE:
{
detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_SECOND:
{
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
default:
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (fmt->len > 0) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t cm_trunc_date(date_t date, text_t *fmt, date_t *result)
{
date_detail_t detail;
date_detail_ex_t detail_ex;
format_item_t *item = NULL;
text_t fmt_extra = { .str = NULL, .len = 0 };
int32 total_days;
cm_decode_date(date, &detail);
cm_get_detail_ex(&detail, &detail_ex);
OG_RETURN_IFERR(cm_fetch_format_item(fmt, &item, &fmt_extra, OG_FALSE));
switch (item->id) {
case FMT_CENTURY:
{
detail.year = (uint16)((detail.year / 100) * 100 + 1);
detail.mon = 1;
detail.day = 1;
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_DAY_OF_WEEK:
case FMT_DAY_NAME:
case FMT_DAY_ABBR_NAME:
{
total_days = total_days_before_date(&detail);
total_days = total_days - detail_ex.day_of_week;
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_WEEK_OF_YEAR:
{
total_days = total_days_before_date(&detail);
total_days = total_days - detail_ex.day_of_week + 1;
*result = cm_get_date_with_days(total_days);
break;
}
case FMT_WEEK_OF_MONTH:
{
detail.day = (uint8)(((detail.day - 1) / 7) * 7 + 1);
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_DAY_OF_MONTH:
case FMT_DAY_OF_YEAR:
{
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_MONTH:
case FMT_MONTH_RM:
case FMT_MONTH_ABBR_NAME:
case FMT_MONTH_NAME:
{
detail.day = 1;
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_QUARTER:
{
detail.mon = (uint8)((detail_ex.quarter - 1) * 3 + 1);
detail.day = 1;
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_YEAR1:
case FMT_YEAR2:
case FMT_YEAR3:
case FMT_YEAR4:
{
detail.mon = 1;
detail.day = 1;
detail.hour = detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_HOUR_OF_DAY12:
case FMT_HOUR_OF_DAY24:
{
detail.min = detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_MINUTE:
{
detail.sec = 0;
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
case FMT_SECOND:
{
detail.millisec = detail.microsec = detail.nanosec = 0;
*result = cm_encode_date(&detail);
break;
}
default:
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
if (fmt->len > 0) {
OG_SET_DATETIME_FMT_ERROR;
return OG_ERROR;
}
return OG_SUCCESS;
}
int64 cm_get_unix_timestamp(timestamp_t ts, int64 time_zone_offset)
{
return ((int64)ts - time_zone_offset - (int64)CM_UNIX_EPOCH) / MICROSECS_PER_SECOND;
}
void cm_cnvrt_datetime_from_int_to_date_detail(int64 input, date_detail_t *detail)
{
int64 y_m_d;
int64 h_m_s;
int64 ymd_hms;
int64 y_m;
int64 time = input;
if (time < 0) {
time = -time;
}
detail->microsec = time % (1LL << DT_ENCODE_24);
ymd_hms = (uint64)time >> DT_ENCODE_24;
y_m_d = (uint64)ymd_hms >> DT_ENCODE_17;
y_m = (uint64)y_m_d >> DT_ENCODE_5;
h_m_s = ymd_hms % (1 << DT_ENCODE_17);
detail->day = (uint8)(y_m_d % (1 << DT_ENCODE_5));
detail->mon = (uint8)(y_m % DT_ENCODE_13);
detail->year = (uint16)(y_m / DT_ENCODE_13);
detail->sec = (uint8)(h_m_s % (1 << DT_ENCODE_6));
detail->min = (uint8)(((uint64)h_m_s >> DT_ENCODE_6) % (1 << DT_ENCODE_6));
detail->hour = (uint8)((uint64)h_m_s >> DT_ENCODE_12);
uint32 tmp = (uint32)(time % (1LL << DT_ENCODE_24));
detail->millisec = (uint16)(tmp / MICROSECS_PER_MILLISEC);
detail->microsec = (uint16)(tmp % MICROSECS_PER_MILLISEC);
}
void cm_cnvrt_time_from_int_to_date_detail(int64 input, date_detail_t *detail)
{
int64 h_m_s;
int64 time = input;
if (time < 0) {
time = -time;
}
h_m_s = (uint64)time >> DT_ENCODE_24;
detail->year = 0;
detail->mon = 0;
detail->day = 0;
detail->hour = (int32)((h_m_s >> DT_ENCODE_12) % (1 << DT_ENCODE_10));
detail->min = (uint8)((h_m_s >> DT_ENCODE_6) % (1 << DT_ENCODE_6));
detail->sec = (uint8)(h_m_s % (1 << DT_ENCODE_6));
uint32 tmp = (uint32)(time % (1LL << DT_ENCODE_24));
detail->millisec = (uint16)(tmp / MICROSECS_PER_MILLISEC);
detail->microsec = (uint16)(tmp % MICROSECS_PER_MILLISEC);
}
int32 cm_tstz_cmp(timestamp_tz_t *tstz1, timestamp_tz_t *tstz2)
{
timestamp_t ts1;
ts1 = cm_adjust_date_between_two_tzs(tstz1->tstamp, tstz1->tz_offset, tstz2->tz_offset);
return (ts1 < tstz2->tstamp) ? -1 : (ts1 > tstz2->tstamp) ? 1 : 0;
}
int64 cm_tstz_sub(timestamp_tz_t *tstz1, timestamp_tz_t *tstz2)
{
timestamp_t ts1;
ts1 = cm_adjust_date_between_two_tzs(tstz1->tstamp, tstz1->tz_offset, tstz2->tz_offset);
return (ts1 - tstz2->tstamp);
}
void cm_datetime_int_to_binary(int64 input, uchar *ptr, int32 precision)
{
CM_ASSERT(precision <= DATETIME_MAX_DECIMALS);
CM_ASSERT((cm_get_time_frac_part_from_int64(input) % (int)(powers_of_10[DATETIME_MAX_DECIMALS - precision])) == 0);
cm_int5_to_binary(ptr, cm_get_time_int_part_from_int64(input) + DATETIMEF_INT_OFS);
switch (precision) {
case CM_DATE_PRE_0:
cm_3_zero_ending(ptr);
break;
case CM_DATE_PRE_1:
case CM_DATE_PRE_2:
ptr[CM_BYTE_5] = (uchar)((char)(cm_get_time_frac_part_from_int64(input) / CM_4_POWER_OF_10));
cm_2_zero_ending(ptr);
break;
case CM_DATE_PRE_3:
case CM_DATE_PRE_4:
cm_int2_to_binary(ptr + CM_BYTE_5, cm_get_time_frac_part_from_int64(input) / CM_2_POWER_OF_10);
cm_1_zero_ending(ptr);
break;
case CM_DATE_PRE_5:
case CM_DATE_PRE_6:
cm_int3_to_binary(ptr + CM_BYTE_5, cm_get_time_frac_part_from_int64(input));
break;
default:
cm_3_zero_ending(ptr);
break;
}
}
void cm_time_int_to_binary(int64 input, uchar *ptr, int32 precision)
{
CM_ASSERT(precision <= DATETIME_MAX_DECIMALS);
CM_ASSERT((cm_get_time_frac_part_from_int64(input) % (int)(powers_of_10[DATETIME_MAX_DECIMALS - precision])) == 0);
switch (precision) {
case CM_DATE_PRE_0:
cm_int3_to_binary(ptr, TIMEF_INT_OFS + cm_get_time_int_part_from_int64(input));
cm_5_zero_ending(ptr);
break;
case CM_DATE_PRE_1:
case CM_DATE_PRE_2:
cm_int3_to_binary(ptr, TIMEF_INT_OFS + cm_get_time_int_part_from_int64(input));
ptr[CM_BYTE_3] = (uchar)((char)(cm_get_time_frac_part_from_int64(input) / CM_4_POWER_OF_10));
cm_4_zero_ending(ptr);
break;
case CM_DATE_PRE_3:
case CM_DATE_PRE_4:
cm_int3_to_binary(ptr, TIMEF_INT_OFS + cm_get_time_int_part_from_int64(input));
cm_int2_to_binary(ptr + CM_BYTE_3, cm_get_time_frac_part_from_int64(input) / CM_2_POWER_OF_10);
cm_3_zero_ending(ptr);
break;
case CM_DATE_PRE_5:
case CM_DATE_PRE_6:
cm_int6tobinary(ptr, input + TIMEF_OFS);
cm_2_zero_ending(ptr);
break;
default:
cm_int3_to_binary(ptr, TIMEF_INT_OFS + cm_get_time_int_part_from_int64(input));
cm_5_zero_ending(ptr);
break;
}
}
#ifdef __cplusplus
}
#endif