mariadb/storage/mroonga/lib/mrn_time_converter.cpp

260 lines
8.6 KiB
C++

/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2010-2013 Kentoku SHIBA
Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "mrn_time_converter.hpp"
#ifdef min
# undef min
#endif
#ifdef max
# undef max
#endif
#include <limits>
// for debug
#define MRN_CLASS_NAME "mrn::TimeConverter"
namespace mrn {
TimeConverter::TimeConverter() {
}
TimeConverter::~TimeConverter() {
}
time_t TimeConverter::tm_to_time_gm(struct tm *time, bool *truncated) {
MRN_DBUG_ENTER_METHOD();
*truncated = true;
struct tm gmdate;
time->tm_yday = -1;
time->tm_isdst = -1;
time_t sec_t = mktime(time);
if (time->tm_yday == -1) {
DBUG_RETURN(-1);
}
if (!gmtime_r(&sec_t, &gmdate)) {
DBUG_RETURN(-1);
}
int32 mrn_utc_diff_in_seconds =
(
time->tm_mday > 25 && gmdate.tm_mday == 1 ? -1 :
time->tm_mday == 1 && gmdate.tm_mday > 25 ? 1 :
time->tm_mday - gmdate.tm_mday
) * 24 * 60 * 60 +
(time->tm_hour - gmdate.tm_hour) * 60 * 60 +
(time->tm_min - gmdate.tm_min) * 60 +
(time->tm_sec - gmdate.tm_sec);
DBUG_PRINT("info", ("mroonga: time->tm_year=%d", time->tm_year));
DBUG_PRINT("info", ("mroonga: time->tm_mon=%d", time->tm_mon));
DBUG_PRINT("info", ("mroonga: time->tm_mday=%d", time->tm_mday));
DBUG_PRINT("info", ("mroonga: time->tm_hour=%d", time->tm_hour));
DBUG_PRINT("info", ("mroonga: time->tm_min=%d", time->tm_min));
DBUG_PRINT("info", ("mroonga: time->tm_sec=%d", time->tm_sec));
DBUG_PRINT("info", ("mroonga: mrn_utc_diff_in_seconds=%d",
mrn_utc_diff_in_seconds));
if (mrn_utc_diff_in_seconds > 0) {
if (sec_t > std::numeric_limits<time_t>::max() - mrn_utc_diff_in_seconds) {
DBUG_RETURN(-1);
}
} else {
if (sec_t < std::numeric_limits<time_t>::min() - mrn_utc_diff_in_seconds) {
DBUG_RETURN(-1);
}
}
*truncated = false;
DBUG_RETURN(sec_t + mrn_utc_diff_in_seconds);
}
long long int TimeConverter::tm_to_grn_time(struct tm *time, int usec,
bool *truncated) {
MRN_DBUG_ENTER_METHOD();
long long int sec = tm_to_time_gm(time, truncated);
DBUG_PRINT("info", ("mroonga: sec=%lld", sec));
DBUG_PRINT("info", ("mroonga: usec=%d", usec));
long long int grn_time = *truncated ? 0 : GRN_TIME_PACK(sec, usec);
DBUG_RETURN(grn_time);
}
long long int TimeConverter::mysql_time_to_grn_time(MYSQL_TIME *mysql_time,
bool *truncated) {
MRN_DBUG_ENTER_METHOD();
int usec = mysql_time->second_part;
long long int grn_time = 0;
*truncated = false;
switch (mysql_time->time_type) {
case MYSQL_TIMESTAMP_DATE:
{
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATE"));
struct tm date;
memset(&date, 0, sizeof(struct tm));
date.tm_year = mysql_time->year - TM_YEAR_BASE;
if (mysql_time->month > 0) {
date.tm_mon = mysql_time->month - 1;
} else {
date.tm_mon = 0;
*truncated = true;
}
if (mysql_time->day > 0) {
date.tm_mday = mysql_time->day;
} else {
date.tm_mday = 1;
*truncated = true;
}
DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
bool tm_truncated = false;
grn_time = tm_to_grn_time(&date, usec, &tm_truncated);
if (tm_truncated) {
*truncated = true;
}
}
break;
case MYSQL_TIMESTAMP_DATETIME:
{
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATETIME"));
struct tm datetime;
memset(&datetime, 0, sizeof(struct tm));
datetime.tm_year = mysql_time->year - TM_YEAR_BASE;
if (mysql_time->month > 0) {
datetime.tm_mon = mysql_time->month - 1;
} else {
datetime.tm_mon = 0;
*truncated = true;
}
if (mysql_time->day > 0) {
datetime.tm_mday = mysql_time->day;
} else {
datetime.tm_mday = 1;
*truncated = true;
}
datetime.tm_hour = mysql_time->hour;
datetime.tm_min = mysql_time->minute;
datetime.tm_sec = mysql_time->second;
DBUG_PRINT("info", ("mroonga: tm_year=%d", datetime.tm_year));
DBUG_PRINT("info", ("mroonga: tm_mon=%d", datetime.tm_mon));
DBUG_PRINT("info", ("mroonga: tm_mday=%d", datetime.tm_mday));
DBUG_PRINT("info", ("mroonga: tm_hour=%d", datetime.tm_hour));
DBUG_PRINT("info", ("mroonga: tm_min=%d", datetime.tm_min));
DBUG_PRINT("info", ("mroonga: tm_sec=%d", datetime.tm_sec));
bool tm_truncated = false;
grn_time = tm_to_grn_time(&datetime, usec, &tm_truncated);
if (tm_truncated) {
*truncated = true;
}
}
break;
case MYSQL_TIMESTAMP_TIME:
{
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_TIME"));
int sec =
mysql_time->hour * 60 * 60 +
mysql_time->minute * 60 +
mysql_time->second;
DBUG_PRINT("info", ("mroonga: sec=%d", sec));
grn_time = GRN_TIME_PACK(sec, usec);
if (mysql_time->neg) {
grn_time = -grn_time;
}
}
break;
default:
DBUG_PRINT("info", ("mroonga: default"));
grn_time = 0;
break;
}
DBUG_RETURN(grn_time);
}
void TimeConverter::grn_time_to_mysql_time(long long int grn_time,
MYSQL_TIME *mysql_time) {
MRN_DBUG_ENTER_METHOD();
long long int sec;
int usec;
GRN_TIME_UNPACK(grn_time, sec, usec);
DBUG_PRINT("info", ("mroonga: sec=%lld", sec));
DBUG_PRINT("info", ("mroonga: usec=%d", usec));
switch (mysql_time->time_type) {
case MYSQL_TIMESTAMP_DATE:
{
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATE"));
struct tm date;
time_t sec_t = sec;
// TODO: Add error check
gmtime_r(&sec_t, &date);
DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
mysql_time->year = date.tm_year + TM_YEAR_BASE;
DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
mysql_time->month = date.tm_mon + 1;
DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
mysql_time->day = date.tm_mday;
}
break;
case MYSQL_TIMESTAMP_DATETIME:
{
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATETIME"));
struct tm date;
time_t sec_t = sec;
// TODO: Add error check
gmtime_r(&sec_t, &date);
DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
mysql_time->year = date.tm_year + TM_YEAR_BASE;
DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
mysql_time->month = date.tm_mon + 1;
DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
mysql_time->day = date.tm_mday;
DBUG_PRINT("info", ("mroonga: tm_hour=%d", date.tm_hour));
mysql_time->hour = date.tm_hour;
DBUG_PRINT("info", ("mroonga: tm_min=%d", date.tm_min));
mysql_time->minute = date.tm_min;
DBUG_PRINT("info", ("mroonga: tm_sec=%d", date.tm_sec));
mysql_time->second = date.tm_sec;
mysql_time->second_part = usec;
}
break;
case MYSQL_TIMESTAMP_TIME:
DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_TIME"));
if (sec < 0) {
mysql_time->neg = true;
sec = -sec;
}
mysql_time->hour = static_cast<unsigned int>(sec / 60 / 60);
mysql_time->minute = sec / 60 % 60;
mysql_time->second = sec % 60;
mysql_time->second_part = usec;
break;
default:
DBUG_PRINT("info", ("mroonga: default"));
break;
}
DBUG_VOID_RETURN;
}
}