diff options
Diffstat (limited to 'storage/mroonga/lib/mrn_time_converter.cpp')
-rw-r--r-- | storage/mroonga/lib/mrn_time_converter.cpp | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/storage/mroonga/lib/mrn_time_converter.cpp b/storage/mroonga/lib/mrn_time_converter.cpp new file mode 100644 index 00000000..7d7555bb --- /dev/null +++ b/storage/mroonga/lib/mrn_time_converter.cpp @@ -0,0 +1,293 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2010-2013 Kentoku SHIBA + Copyright(C) 2011-2015 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-1335 USA +*/ + +#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() = default; + + TimeConverter::~TimeConverter() = default; + + 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; + } + + long long int TimeConverter::mysql_datetime_to_grn_time(long long int mysql_datetime, + bool *truncated) { + MRN_DBUG_ENTER_METHOD(); + + MYSQL_TIME mysql_time; + mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME; + mysql_time.neg = 0; + mysql_time.second_part = 0; + mysql_time.second = (mysql_datetime % 100); + mysql_time.minute = (mysql_datetime / 100 % 100); + mysql_time.hour = (mysql_datetime / 10000 % 100); + mysql_time.day = (mysql_datetime / 1000000 % 100); + mysql_time.month = (mysql_datetime / 100000000 % 100); + mysql_time.year = (mysql_datetime / 10000000000LL % 10000); + + long long int grn_time = mysql_time_to_grn_time(&mysql_time, truncated); + + DBUG_RETURN(grn_time); + } + + long long int TimeConverter::grn_time_to_mysql_datetime(long long int grn_time) { + MRN_DBUG_ENTER_METHOD(); + + MYSQL_TIME mysql_time; + mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME; + + grn_time_to_mysql_time(grn_time, &mysql_time); + + long long int mysql_datetime = + (mysql_time.second * 1) + + (mysql_time.minute * 100) + + (mysql_time.hour * 10000) + + (mysql_time.day * 1000000) + + (mysql_time.month * 100000000) + + (mysql_time.year * 10000000000LL); + + DBUG_RETURN(mysql_datetime); + } +} |