Using cctz library [#CLICKHOUSE-2].

This commit is contained in:
Alexey Milovidov 2017-01-21 05:32:02 +03:00
parent ed60f63e26
commit 8de0740291
2 changed files with 36 additions and 124 deletions

View File

@ -4,6 +4,8 @@ SET(CONFIG_VERSION ${CMAKE_CURRENT_BINARY_DIR}/include/common/config_version.h)
SET(CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/include/common/config_common.h) SET(CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/include/common/config_common.h)
include_directories (include) include_directories (include)
include_directories (BEFORE ${CMAKE_SOURCE_DIR}/contrib/libcctz/include)
include(${CMAKE_SOURCE_DIR}/cmake/dbms_include.cmake) include(${CMAKE_SOURCE_DIR}/cmake/dbms_include.cmake)
if (APPLE) if (APPLE)
@ -77,16 +79,14 @@ else ()
message (STATUS "Disabling libtcmalloc for valgrind better analysis") message (STATUS "Disabling libtcmalloc for valgrind better analysis")
endif () endif ()
include (${ClickHouse_SOURCE_DIR}/cmake/find_glib.cmake)
find_package (Threads) find_package (Threads)
target_link_libraries ( target_link_libraries (
common common
pocoext pocoext
cctz
${MALLOC_LIBRARIES} ${MALLOC_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${GLIB_LIBS}
${ICU_LIBS} ${ICU_LIBS}
${RT_LIBRARIES}) ${RT_LIBRARIES})

View File

@ -1,121 +1,35 @@
#pragma GCC diagnostic push #include <civil_time.h>
#pragma GCC diagnostic ignored "-Wold-style-cast" #include <time_zone.h>
#if __clang__
#pragma GCC diagnostic ignored "-Wdeprecated-register"
#endif
#include <glib.h>
#pragma GCC diagnostic pop
#include <common/DateLUTImpl.h> #include <common/DateLUTImpl.h>
#include <Poco/Exception.h> #include <Poco/Exception.h>
#include <memory> #include <memory>
#include <chrono>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
namespace details
{
namespace namespace
{ {
struct GTimeZoneUnref UInt8 getDayOfWeek(const cctz::civil_day & date)
{ {
void operator()(GTimeZone * tz) const cctz::weekday day_of_week = cctz::get_weekday(date);
switch (day_of_week)
{ {
g_time_zone_unref(tz); case cctz::weekday::monday: return 1;
case cctz::weekday::tuesday: return 2;
case cctz::weekday::wednesday: return 3;
case cctz::weekday::thursday: return 4;
case cctz::weekday::friday: return 5;
case cctz::weekday::saturday: return 6;
case cctz::weekday::sunday: return 7;
default:
throw Poco::Exception("Logical error: incorrect week day.");
} }
};
using GTimeZonePtr = std::unique_ptr<GTimeZone, GTimeZoneUnref>;
struct GDateTimeUnref
{
void operator()(GDateTime * dt) const
{
g_date_time_unref(dt);
}
};
using GDateTimePtr = std::unique_ptr<GDateTime, GDateTimeUnref>;
GTimeZonePtr createGTimeZone(const std::string & description)
{
GTimeZone * tz = g_time_zone_new(description.c_str());
if (tz == nullptr)
throw Poco::Exception("Failed to create GTimeZone object.");
return GTimeZonePtr(tz);
} }
GDateTimePtr createGDateTimeUTC(time_t timestamp)
{
GDateTime * dt = g_date_time_new_from_unix_utc(timestamp);
if (dt == nullptr)
throw Poco::Exception("Failed to create GDateTime object.");
return GDateTimePtr(dt);
}
/// Create GDateTime object, interpreting passed unix timestamp in passed timezone.
GDateTimePtr createGDateTimeLocal(const GTimeZonePtr & p_tz, time_t timestamp)
{
GDateTimePtr utc = createGDateTimeUTC(timestamp);
GDateTime * local = g_date_time_to_timezone(utc.get(), p_tz.get());
if (local == nullptr)
throw Poco::Exception("Failed to create GDateTime object.");
return GDateTimePtr(local);
}
/// Create GDateTime object, at beginning of same day in passed time zone.
GDateTimePtr createSameDayInDifferentTimeZone(const GTimeZonePtr & p_tz, const GDateTimePtr & p_dt)
{
GDateTime * dt = p_dt.get();
gint year;
gint month;
gint day;
g_date_time_get_ymd(dt, &year, &month, &day);
GDateTime * local_dt = g_date_time_new(p_tz.get(), year, month, day, 0, 0, 0);
if (local_dt == nullptr)
throw Poco::Exception("Failed to create GDateTime object.");
return GDateTimePtr(local_dt);
}
GDateTimePtr toNextDay(const GTimeZonePtr & p_tz, const GDateTimePtr & p_dt)
{
GDateTime * dt = p_dt.get();
if (dt == nullptr)
throw Poco::Exception("Null pointer.");
dt = g_date_time_add_days(dt, 1);
if (dt == nullptr)
throw Poco::Exception("Failed to create GDateTime object.");
GDateTimePtr p_next_dt = GDateTimePtr(dt);
GDateTime * next_dt = p_next_dt.get();
gint year;
gint month;
gint day;
g_date_time_get_ymd(next_dt, &year, &month, &day);
dt = g_date_time_new(p_tz.get(), year, month, day, 0, 0, 0);
if (dt == nullptr)
throw Poco::Exception("Failed to create GDateTime object.");
return GDateTimePtr(dt);
}
}
} }
@ -125,28 +39,29 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
size_t i = 0; size_t i = 0;
time_t start_of_day = DATE_LUT_MIN; time_t start_of_day = DATE_LUT_MIN;
details::GTimeZonePtr p_tz = details::createGTimeZone(time_zone); cctz::time_zone cctz_time_zone;
details::GDateTimePtr p_dt = details::createSameDayInDifferentTimeZone(p_tz, details::createGDateTimeUTC(start_of_day)); if (!cctz::load_time_zone(time_zone.data(), &cctz_time_zone))
throw Poco::Exception("Cannot load time zone " + time_zone_);
cctz::time_zone::absolute_lookup start_of_epoch_lookup = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(start_of_day));
cctz::civil_day date{start_of_epoch_lookup.cs};
offset_at_start_of_epoch = start_of_epoch_lookup.offset;
do do
{ {
if (i > DATE_LUT_MAX_DAY_NUM) if (i > DATE_LUT_MAX_DAY_NUM)
throw Poco::Exception("Cannot create DateLUTImpl: i > DATE_LUT_MAX_DAY_NUM."); throw Poco::Exception("Cannot create DateLUTImpl: i > DATE_LUT_MAX_DAY_NUM.");
GDateTime * dt = p_dt.get(); cctz::time_zone::civil_lookup lookup = cctz_time_zone.lookup(date);
start_of_day = g_date_time_to_unix(dt); start_of_day = std::chrono::system_clock::to_time_t(lookup.pre); /// Ambiguouty is possible.
gint year;
gint month;
gint day;
g_date_time_get_ymd(dt, &year, &month, &day);
Values & values = lut[i]; Values & values = lut[i];
values.year = year; values.year = date.year();
values.month = month; values.month = date.month();
values.day_of_month = day; values.day_of_month = date.day();
values.day_of_week = g_date_time_get_day_of_week(dt); values.day_of_week = getDayOfWeek(date);
values.date = start_of_day; values.date = start_of_day;
values.time_at_offset_change = 0; values.time_at_offset_change = 0;
@ -160,8 +75,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
{ {
lut[i - 1].amount_of_offset_change = amount_of_offset_change_at_prev_day; lut[i - 1].amount_of_offset_change = amount_of_offset_change_at_prev_day;
const auto utc_offset_at_beginning_of_day = g_date_time_get_utc_offset( const auto utc_offset_at_beginning_of_day = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(lut[i - 1].date)).offset;
details::createGDateTimeLocal(p_tz, lut[i - 1].date).get());
/// Find a time (timestamp offset from beginning of day), /// Find a time (timestamp offset from beginning of day),
/// when UTC offset was changed. Search is performed with 15-minute granularity, assuming it is enough. /// when UTC offset was changed. Search is performed with 15-minute granularity, assuming it is enough.
@ -169,8 +83,8 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
time_t time_at_offset_change = 900; time_t time_at_offset_change = 900;
while (time_at_offset_change < 65536) while (time_at_offset_change < 65536)
{ {
auto utc_offset_at_current_time = g_date_time_get_utc_offset( auto utc_offset_at_current_time = cctz_time_zone.lookup(std::chrono::system_clock::from_time_t(
details::createGDateTimeLocal(p_tz, lut[i - 1].date + time_at_offset_change).get()); lut[i - 1].date + time_at_offset_change)).offset;
if (utc_offset_at_current_time != utc_offset_at_beginning_of_day) if (utc_offset_at_current_time != utc_offset_at_beginning_of_day)
break; break;
@ -186,7 +100,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
} }
/// Going to next day. /// Going to next day.
p_dt = details::toNextDay(p_tz, p_dt); ++date;
++i; ++i;
} }
while (start_of_day <= DATE_LUT_MAX); while (start_of_day <= DATE_LUT_MAX);
@ -198,6 +112,4 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
if (lut[day].month == 1 && lut[day].day_of_month == 1) if (lut[day].month == 1 && lut[day].day_of_month == 1)
years_lut[lut[day].year - DATE_LUT_MIN_YEAR] = day; years_lut[lut[day].year - DATE_LUT_MIN_YEAR] = day;
} }
offset_at_start_of_epoch = g_time_zone_get_offset(p_tz.get(), g_time_zone_find_interval(p_tz.get(), G_TIME_TYPE_UNIVERSAL, 0));
} }