aboutsummaryrefslogtreecommitdiff
path: root/contrib/native
diff options
context:
space:
mode:
authorXiao Meng <xiaom.cs@gmail.com>2014-05-30 11:31:44 -0700
committerJacques Nadeau <jacques@apache.org>2014-06-19 20:30:36 -0700
commitb90956e3afc96df3968d2e7882b449c506ea0924 (patch)
tree178bb8b82ad32be65665d3154ce8e70f94f9531e /contrib/native
parentaaa4db74b215e03ad0e1334cfc18964972d93a3b (diff)
DRILL-748: C++ Client. Support timestamp/date before unix time and handle y2028 problem.
Diffstat (limited to 'contrib/native')
-rw-r--r--contrib/native/client/CMakeLists.txt9
-rw-r--r--contrib/native/client/src/clientlib/CMakeLists.txt2
-rw-r--r--contrib/native/client/src/clientlib/recordBatch.cpp80
-rw-r--r--contrib/native/client/src/clientlib/y2038/CMakeLists.txt40
-rw-r--r--contrib/native/client/src/clientlib/y2038/time64.c830
-rw-r--r--contrib/native/client/src/clientlib/y2038/time64.h110
-rw-r--r--contrib/native/client/src/clientlib/y2038/time64_config.h107
-rw-r--r--contrib/native/client/src/clientlib/y2038/time64_limits.h124
-rw-r--r--contrib/native/client/src/include/drill/drillc.hpp2
-rw-r--r--contrib/native/client/src/include/drill/recordBatch.hpp23
10 files changed, 1292 insertions, 35 deletions
diff --git a/contrib/native/client/CMakeLists.txt b/contrib/native/client/CMakeLists.txt
index 9ac705b8c..31ac47278 100644
--- a/contrib/native/client/CMakeLists.txt
+++ b/contrib/native/client/CMakeLists.txt
@@ -56,9 +56,12 @@ add_subdirectory("${CMAKE_SOURCE_DIR}/src/protobuf")
include_directories(${ProtoHeadersDir})
include_directories(${ProtoIncludesDir})
+# Y2038 library
+add_subdirectory("${CMAKE_SOURCE_DIR}/src/clientlib/y2038")
+
# Build the Client Library as a shared library
add_subdirectory("${CMAKE_SOURCE_DIR}/src/clientlib")
-include_directories(${CMAKE_SOURCE_DIR}/src/include ${Zookeeper_INCLUDE_DIRS} )
+include_directories(${CMAKE_SOURCE_DIR}/src/include ${Zookeeper_INCLUDE_DIRS})
# add a DEBUG preprocessor macro
set_property(
@@ -71,6 +74,4 @@ link_directories(/usr/local/lib)
add_executable(querySubmitter example/querySubmitter.cpp )
-target_link_libraries(querySubmitter ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY} drillClient protomsgs )
-
-
+target_link_libraries(querySubmitter ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY} drillClient protomsgs y2038)
diff --git a/contrib/native/client/src/clientlib/CMakeLists.txt b/contrib/native/client/src/clientlib/CMakeLists.txt
index 7cd5dfba8..37f473477 100644
--- a/contrib/native/client/src/clientlib/CMakeLists.txt
+++ b/contrib/native/client/src/clientlib/CMakeLists.txt
@@ -41,4 +41,4 @@ set_property(
)
add_library(drillClient SHARED ${CLIENTLIB_SRC_FILES} )
-target_link_libraries(drillClient ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY} ${Zookeeper_LIBRARIES} protomsgs)
+target_link_libraries(drillClient ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY} ${Zookeeper_LIBRARIES} protomsgs y2038)
diff --git a/contrib/native/client/src/clientlib/recordBatch.cpp b/contrib/native/client/src/clientlib/recordBatch.cpp
index 27a592d63..90fe11a41 100644
--- a/contrib/native/client/src/clientlib/recordBatch.cpp
+++ b/contrib/native/client/src/clientlib/recordBatch.cpp
@@ -24,6 +24,10 @@ const uint32_t YEARS_TO_MONTHS=12;
const uint32_t HOURS_TO_MILLIS=60*60*1000;
const uint32_t MINUTES_TO_MILLIS=60*1000;
const uint32_t SECONDS_TO_MILLIS=1000;
+extern "C"
+{
+ #include "y2038/time64.h"
+}
namespace Drill{
@@ -196,9 +200,9 @@ ValueVectorBase* ValueVectorFactory::allocateValueVector(const Drill::FieldMetad
case common::DECIMAL38SPARSE:
return new ValueVectorDecimal38Sparse(b,f.getValueCount(), f.getScale());
case common::DATE:
- return new ValueVectorTyped<DateHolder, uint64_t>(b,f.getValueCount());
+ return new ValueVectorTyped<DateHolder, int64_t>(b,f.getValueCount());
case common::TIMESTAMP:
- return new ValueVectorTyped<DateTimeHolder, uint64_t>(b,f.getValueCount());
+ return new ValueVectorTyped<DateTimeHolder, int64_t>(b,f.getValueCount());
case common::TIME:
return new ValueVectorTyped<TimeHolder, uint32_t>(b,f.getValueCount());
case common::TIMESTAMPTZ:
@@ -235,10 +239,10 @@ ValueVectorBase* ValueVectorFactory::allocateValueVector(const Drill::FieldMetad
return new NullableValueVectorFixed<double>(b,f.getValueCount());
case common::DATE:
return new NullableValueVectorTyped<DateHolder,
- ValueVectorTyped<DateHolder, uint64_t> >(b,f.getValueCount());
+ ValueVectorTyped<DateHolder, int64_t> >(b,f.getValueCount());
case common::TIMESTAMP:
return new NullableValueVectorTyped<DateTimeHolder,
- ValueVectorTyped<DateTimeHolder, uint64_t> >(b,f.getValueCount());
+ ValueVectorTyped<DateTimeHolder, int64_t> >(b,f.getValueCount());
case common::TIME:
return new NullableValueVectorTyped<TimeHolder,
ValueVectorTyped<TimeHolder, uint32_t> >(b,f.getValueCount());
@@ -357,12 +361,48 @@ void DateHolder::load(){
m_year=1970;
m_month=1;
m_day=1;
-
- time_t t= m_datetime/1000; // number of seconds since beginning of the Unix Epoch.
- struct tm * tm = gmtime(&t);
- m_year=tm->tm_year+1900;
- m_month=tm->tm_mon+1;
- m_day=tm->tm_mday;
+ const Time64_T t= m_datetime/1000; // number of seconds since beginning of the Unix Epoch.
+ /*
+ TL;DR
+
+ The gmttime in standard libray on windows platform cannot represent the date before Unix Epoch.
+ http://msdn.microsoft.com/en-us/library/0z9czt0w(v=vs.100).aspx
+
+ """
+ Both the 32-bit and 64-bit versions of gmtime, mktime, mkgmtime, and localtime all use one tm structure per thread for the conversion.
+ Each call to one of these functions destroys the result of any previous call.
+ If timer represents a date before midnight, January 1, 1970, gmtime returns NULL. There is no error return.
+
+ _gmtime64, which uses the __time64_t structure, enables dates to be expressed up through 23:59:59, December 31, 3000, UTC,
+ whereas _gmtime32 only represent dates through 03:14:07 January 19, 2038, UTC.
+ Midnight, January 1, 1970, is the lower bound of the date range for both of these functions.
+
+ gmtime is an inline function that evaluates to _gmtime64 and time_t is equivalent to __time64_t unless _USE_32BIT_TIME_T is defined.
+ """
+
+ An alternative could be boost date_time libraray.
+
+ ```
+ #include <boost/date_time/posix_time/posix_time.hpp>
+ using namespace boost::posix_time;
+ ptime pt = from_time_t(t);
+ struct tm d = to_tm(pt);
+ ```
+
+ Howerver, boost date_time library still has year 2038 problem which is still not fixed.
+ https://svn.boost.org/trac/boost/ticket/4543
+ One reason is that the library converts the 64-bit`time_t t` into `seconds` type to get posix time.
+ But boost uses `long` to represent `seconds`, which is 4 bytes on windows platform,
+ http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
+
+ We eventually choose the third-party MIT-licensed library written with ANSI C.
+ https://github.com/schwern/y2038
+ */
+ struct TM d;
+ gmtime64_r(&t,&d);
+ m_year=1900 + static_cast<int32_t>(d.tm_year);
+ m_month=d.tm_mon + 1;
+ m_day=d.tm_mday;
}
std::string DateHolder::toString(){
@@ -400,15 +440,19 @@ void DateTimeHolder::load(){
m_sec=0;
m_msec=0;
- time_t t= m_datetime/1000; // number of seconds since beginning of the Unix Epoch.
- struct tm * tm = gmtime(&t);
- m_year=tm->tm_year+1900;
- m_month=tm->tm_mon+1;
- m_day=tm->tm_mday;
- m_hr=tm->tm_hour;
- m_min=tm->tm_min;
- m_sec=tm->tm_sec;
+ const Time64_T t=m_datetime/1000; // number of seconds since beginning of the Unix Epoch.
+
+ struct TM dt;
+ gmtime64_r(&t,&dt);
+
+ m_year=1900 + dt.tm_year;
+ m_month=dt.tm_mon + 1;
+ m_day=dt.tm_mday;
+ m_hr=dt.tm_hour;
+ m_min=dt.tm_min;
+ m_sec=dt.tm_sec;
m_msec=m_datetime%1000;
+
}
std::string DateTimeHolder::toString(){
diff --git a/contrib/native/client/src/clientlib/y2038/CMakeLists.txt b/contrib/native/client/src/clientlib/y2038/CMakeLists.txt
new file mode 100644
index 000000000..1cb4d7222
--- /dev/null
+++ b/contrib/native/client/src/clientlib/y2038/CMakeLists.txt
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Y2038 library
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_CXX_FLAGS "-fPIC")
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(CMAKE_C_FLAGS "-fPIC")
+endif()
+
+set (Y2038_SRC_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/time64.c
+ )
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../include )
+
+set_property(
+ DIRECTORY
+ PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG DEBUG=1 THREADED
+ )
+
+add_library(y2038 STATIC ${Y2038_SRC_FILES} )
diff --git a/contrib/native/client/src/clientlib/y2038/time64.c b/contrib/native/client/src/clientlib/y2038/time64.c
new file mode 100644
index 000000000..e0d61c851
--- /dev/null
+++ b/contrib/native/client/src/clientlib/y2038/time64.c
@@ -0,0 +1,830 @@
+/*
+
+Copyright (c) 2007-2010 Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+/*
+
+Programmers who have available to them 64-bit time values as a 'long
+long' type can use localtime64_r() and gmtime64_r() which correctly
+converts the time even on 32-bit systems. Whether you have 64-bit time
+values will depend on the operating system.
+
+localtime64_r() is a 64-bit equivalent of localtime_r().
+
+gmtime64_r() is a 64-bit equivalent of gmtime_r().
+
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include "time64.h"
+#include "time64_limits.h"
+
+
+/* Spec says except for stftime() and the _r() functions, these
+ all return static memory. Stabbings! */
+static struct TM Static_Return_Date;
+static char Static_Return_String[35];
+
+static const char days_in_month[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 const short julian_days_by_month[2][12] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
+};
+
+static char wday_name[7][4] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static char mon_name[12][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const short length_of_year[2] = { 365, 366 };
+
+/* Some numbers relating to the gregorian cycle */
+static const Year years_in_gregorian_cycle = 400;
+#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
+static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
+
+/* Year range we can trust the time funcitons with */
+#define MAX_SAFE_YEAR 2037
+#define MIN_SAFE_YEAR 1971
+
+/* 28 year Julian calendar cycle */
+#define SOLAR_CYCLE_LENGTH 28
+
+/* Year cycle from MAX_SAFE_YEAR down. */
+static const short safe_years_high[SOLAR_CYCLE_LENGTH] = {
+ 2016, 2017, 2018, 2019,
+ 2020, 2021, 2022, 2023,
+ 2024, 2025, 2026, 2027,
+ 2028, 2029, 2030, 2031,
+ 2032, 2033, 2034, 2035,
+ 2036, 2037, 2010, 2011,
+ 2012, 2013, 2014, 2015
+};
+
+/* Year cycle from MIN_SAFE_YEAR up */
+static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
+ 1996, 1997, 1998, 1971,
+ 1972, 1973, 1974, 1975,
+ 1976, 1977, 1978, 1979,
+ 1980, 1981, 1982, 1983,
+ 1984, 1985, 1986, 1987,
+ 1988, 1989, 1990, 1991,
+ 1992, 1993, 1994, 1995,
+};
+
+/* This isn't used, but it's handy to look at */
+static const char dow_year_start[SOLAR_CYCLE_LENGTH] = {
+ 5, 0, 1, 2, /* 0 2016 - 2019 */
+ 3, 5, 6, 0, /* 4 */
+ 1, 3, 4, 5, /* 8 1996 - 1998, 1971*/
+ 6, 1, 2, 3, /* 12 1972 - 1975 */
+ 4, 6, 0, 1, /* 16 */
+ 2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
+ 0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
+};
+
+/* Let's assume people are going to be looking for dates in the future.
+ Let's provide some cheats so you can skip ahead.
+ This has a 4x speed boost when near 2008.
+*/
+/* Number of days since epoch on Jan 1st, 2008 GMT */
+#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
+#define CHEAT_YEARS 108
+
+#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
+#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
+
+#ifdef USE_SYSTEM_LOCALTIME
+# define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
+ (a) <= SYSTEM_LOCALTIME_MAX && \
+ (a) >= SYSTEM_LOCALTIME_MIN \
+)
+#else
+# define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
+#endif
+
+#ifdef USE_SYSTEM_GMTIME
+# define SHOULD_USE_SYSTEM_GMTIME(a) ( \
+ (a) <= SYSTEM_GMTIME_MAX && \
+ (a) >= SYSTEM_GMTIME_MIN \
+)
+#else
+# define SHOULD_USE_SYSTEM_GMTIME(a) (0)
+#endif
+
+/* Multi varadic macros are a C99 thing, alas */
+#ifdef TIME_64_DEBUG
+# define TIME64_TRACE(format) (fprintf(stderr, format))
+# define TIME64_TRACE1(format, var1) (fprintf(stderr, format, var1))
+# define TIME64_TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
+# define TIME64_TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
+#else
+# define TIME64_TRACE(format) ((void)0)
+# define TIME64_TRACE1(format, var1) ((void)0)
+# define TIME64_TRACE2(format, var1, var2) ((void)0)
+# define TIME64_TRACE3(format, var1, var2, var3) ((void)0)
+#endif
+
+
+static int is_exception_century(Year year)
+{
+ int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
+ TIME64_TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
+
+ return(is_exception);
+}
+
+
+/* Compare two dates.
+ The result is like cmp.
+ Ignores things like gmtoffset and dst
+*/
+int cmp_date( const struct TM* left, const struct tm* right ) {
+ if( left->tm_year > right->tm_year )
+ return 1;
+ else if( left->tm_year < right->tm_year )
+ return -1;
+
+ if( left->tm_mon > right->tm_mon )
+ return 1;
+ else if( left->tm_mon < right->tm_mon )
+ return -1;
+
+ if( left->tm_mday > right->tm_mday )
+ return 1;
+ else if( left->tm_mday < right->tm_mday )
+ return -1;
+
+ if( left->tm_hour > right->tm_hour )
+ return 1;
+ else if( left->tm_hour < right->tm_hour )
+ return -1;
+
+ if( left->tm_min > right->tm_min )
+ return 1;
+ else if( left->tm_min < right->tm_min )
+ return -1;
+
+ if( left->tm_sec > right->tm_sec )
+ return 1;
+ else if( left->tm_sec < right->tm_sec )
+ return -1;
+
+ return 0;
+}
+
+
+/* Check if a date is safely inside a range.
+ The intention is to check if its a few days inside.
+*/
+int date_in_safe_range( const struct TM* date, const struct tm* min, const struct tm* max ) {
+ if( cmp_date(date, min) == -1 )
+ return 0;
+
+ if( cmp_date(date, max) == 1 )
+ return 0;
+
+ return 1;
+}
+
+
+/* timegm() is not in the C or POSIX spec, but it is such a useful
+ extension I would be remiss in leaving it out. Also I need it
+ for localtime64()
+*/
+Time64_T timegm64(const struct TM *date) {
+ Time64_T days = 0;
+ Time64_T seconds = 0;
+ Year year;
+ Year orig_year = (Year)date->tm_year;
+ int cycles = 0;
+
+ if( orig_year > 100 ) {
+ cycles = (orig_year - 100) / 400;
+ orig_year -= cycles * 400;
+ days += (Time64_T)cycles * days_in_gregorian_cycle;
+ }
+ else if( orig_year < -300 ) {
+ cycles = (orig_year - 100) / 400;
+ orig_year -= cycles * 400;
+ days += (Time64_T)cycles * days_in_gregorian_cycle;
+ }
+ TIME64_TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
+
+ if( orig_year > 70 ) {
+ year = 70;
+ while( year < orig_year ) {
+ days += length_of_year[IS_LEAP(year)];
+ year++;
+ }
+ }
+ else if ( orig_year < 70 ) {
+ year = 69;
+ do {
+ days -= length_of_year[IS_LEAP(year)];
+ year--;
+ } while( year >= orig_year );
+ }
+
+ days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
+ days += date->tm_mday - 1;
+
+ seconds = days * 60 * 60 * 24;
+
+ seconds += date->tm_hour * 60 * 60;
+ seconds += date->tm_min * 60;
+ seconds += date->tm_sec;
+
+ return(seconds);
+}
+
+
+static int check_tm(struct TM *tm)
+{
+ /* Don't forget leap seconds */
+ assert(tm->tm_sec >= 0);
+ assert(tm->tm_sec <= 61);
+
+ assert(tm->tm_min >= 0);
+ assert(tm->tm_min <= 59);
+
+ assert(tm->tm_hour >= 0);
+ assert(tm->tm_hour <= 23);
+
+ assert(tm->tm_mday >= 1);
+ assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
+
+ assert(tm->tm_mon >= 0);
+ assert(tm->tm_mon <= 11);
+
+ assert(tm->tm_wday >= 0);
+ assert(tm->tm_wday <= 6);
+
+ assert(tm->tm_yday >= 0);
+ assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
+
+#ifdef HAS_TM_TM_GMTOFF
+ assert(tm->tm_gmtoff >= -24 * 60 * 60);
+ assert(tm->tm_gmtoff <= 24 * 60 * 60);
+#endif
+
+ return 1;
+}
+
+
+/* The exceptional centuries without leap years cause the cycle to
+ shift by 16
+*/
+static Year cycle_offset(Year year)
+{
+ const Year start_year = 2000;
+ Year year_diff = year - start_year;
+ Year exceptions;
+
+ if( year > start_year )
+ year_diff--;
+
+ exceptions = year_diff / 100;
+ exceptions -= year_diff / 400;
+
+ TIME64_TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
+ year, exceptions, year_diff);
+
+ return exceptions * 16;
+}
+
+/* For a given year after 2038, pick the latest possible matching
+ year in the 28 year calendar cycle.
+
+ A matching year...
+ 1) Starts on the same day of the week.
+ 2) Has the same leap year status.
+
+ This is so the calendars match up.
+
+ Also the previous year must match. When doing Jan 1st you might
+ wind up on Dec 31st the previous year when doing a -UTC time zone.
+
+ Finally, the next year must have the same start day of week. This
+ is for Dec 31st with a +UTC time zone.
+ It doesn't need the same leap year status since we only care about
+ January 1st.
+*/
+static int safe_year(const Year year)
+{
+ int safe_year;
+ Year year_cycle;
+
+ if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
+ return (int)year;
+ }
+
+ year_cycle = year + cycle_offset(year);
+
+ /* safe_years_low is off from safe_years_high by 8 years */
+ if( year < MIN_SAFE_YEAR )
+ year_cycle -= 8;
+
+ /* Change non-leap xx00 years to an equivalent */
+ if( is_exception_century(year) )
+ year_cycle += 11;
+
+ /* Also xx01 years, since the previous year will be wrong */
+ if( is_exception_century(year - 1) )
+ year_cycle += 17;
+
+ year_cycle %= SOLAR_CYCLE_LENGTH;
+ if( year_cycle < 0 )
+ year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
+
+ assert( year_cycle >= 0 );
+ assert( year_cycle < SOLAR_CYCLE_LENGTH );
+ if( year < MIN_SAFE_YEAR )
+ safe_year = safe_years_low[year_cycle];
+ else if( year > MAX_SAFE_YEAR )
+ safe_year = safe_years_high[year_cycle];
+ else
+ assert(0);
+
+ TIME64_TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
+ year, year_cycle, safe_year);
+
+ assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
+
+ return safe_year;
+}
+
+
+void copy_tm_to_TM64(const struct tm *src, struct TM *dest) {
+ if( src == NULL ) {
+ memset(dest, 0, sizeof(*dest));
+ }
+ else {
+# ifdef USE_TM64
+ dest->tm_sec = src->tm_sec;
+ dest->tm_min = src->tm_min;
+ dest->tm_hour = src->tm_hour;
+ dest->tm_mday = src->tm_mday;
+ dest->tm_mon = src->tm_mon;
+ dest->tm_year = (Year)src->tm_year;
+ dest->tm_wday = src->tm_wday;
+ dest->tm_yday = src->tm_yday;
+ dest->tm_isdst = src->tm_isdst;
+
+# ifdef HAS_TM_TM_GMTOFF
+ dest->tm_gmtoff = src->tm_gmtoff;
+# endif
+
+# ifdef HAS_TM_TM_ZONE
+ dest->tm_zone = src->tm_zone;
+# endif
+
+# else
+ /* They're the same type */
+ memcpy(dest, src, sizeof(*dest));
+# endif
+ }
+}
+
+
+void copy_TM64_to_tm(const struct TM *src, struct tm *dest) {
+ if( src == NULL ) {
+ memset(dest, 0, sizeof(*dest));
+ }
+ else {
+# ifdef USE_TM64
+ dest->tm_sec = src->tm_sec;
+ dest->tm_min = src->tm_min;
+ dest->tm_hour = src->tm_hour;
+ dest->tm_mday = src->tm_mday;
+ dest->tm_mon = src->tm_mon;
+ dest->tm_year = (int)src->tm_year;
+ dest->tm_wday = src->tm_wday;
+ dest->tm_yday = src->tm_yday;
+ dest->tm_isdst = src->tm_isdst;
+
+# ifdef HAS_TM_TM_GMTOFF
+ dest->tm_gmtoff = src->tm_gmtoff;
+# endif
+
+# ifdef HAS_TM_TM_ZONE
+ dest->tm_zone = src->tm_zone;
+# endif
+
+# else
+ /* They're the same type */
+ memcpy(dest, src, sizeof(*dest));
+# endif
+ }
+}
+
+
+/* Simulate localtime_r() to the best of our ability */
+struct tm * fake_localtime_r(const time_t *time, struct tm *result) {
+ const struct tm *static_result = localtime(time);
+
+ assert(result != NULL);
+
+ if( static_result == NULL ) {
+ memset(result, 0, sizeof(*result));
+ return NULL;
+ }
+ else {
+ memcpy(result, static_result, sizeof(*result));
+ return result;
+ }
+}
+
+
+/* Simulate gmtime_r() to the best of our ability */
+struct tm * fake_gmtime_r(const time_t *time, struct tm *result) {
+ const struct tm *static_result = gmtime(time);
+
+ assert(result != NULL);
+
+ if( static_result == NULL ) {
+ memset(result, 0, sizeof(*result));
+ return NULL;
+ }
+ else {
+ memcpy(result, static_result, sizeof(*result));
+ return result;
+ }
+}
+
+
+static Time64_T seconds_between_years(Year left_year, Year right_year) {
+ int increment = (left_year > right_year) ? 1 : -1;
+ Time64_T seconds = 0;
+ int cycles;
+
+ if( left_year > 2400 ) {
+ cycles = (left_year - 2400) / 400;
+ left_year -= cycles * 400;
+ seconds += cycles * seconds_in_gregorian_cycle;
+ }
+ else if( left_year < 1600 ) {
+ cycles = (left_year - 1600) / 400;
+ left_year += cycles * 400;
+ seconds += cycles * seconds_in_gregorian_cycle;
+ }
+
+ while( left_year != right_year ) {
+ seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
+ right_year += increment;
+ }
+
+ return seconds * increment;
+}
+
+
+Time64_T mktime64(struct TM *input_date) {
+ struct tm safe_date;
+ struct TM date;
+ Time64_T time;
+ Year year = input_date->tm_year + 1900;
+
+ if( date_in_safe_range(input_date, &SYSTEM_MKTIME_MIN, &SYSTEM_MKTIME_MAX) )
+ {
+ copy_TM64_to_tm(input_date, &safe_date);
+ time = (Time64_T)mktime(&safe_date);
+
+ /* Correct the possibly out of bound input date */
+ copy_tm_to_TM64(&safe_date, input_date);
+ return time;
+ }
+
+ /* Have to make the year safe in date else it won't fit in safe_date */
+ date = *input_date;
+ date.tm_year = safe_year(year) - 1900;
+ copy_TM64_to_tm(&date, &safe_date);
+
+ time = (Time64_T)mktime(&safe_date);
+
+ /* Correct the user's possibly out of bound input date */
+ copy_tm_to_TM64(&safe_date, input_date);
+
+ time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
+
+ return time;
+}
+
+
+/* Because I think mktime() is a crappy name */
+Time64_T timelocal64(struct TM *date) {
+ return mktime64(date);
+}
+
+
+struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
+{
+ int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
+ Time64_T v_tm_tday;
+ int leap;
+ Time64_T m;
+ Time64_T time = *in_time;
+ Year year = 70;
+ int cycles = 0;
+
+ assert(p != NULL);
+
+ /* Use the system gmtime() if time_t is small enough */
+ if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
+ time_t safe_time = (time_t)*in_time;
+ struct tm safe_date;
+ GMTIME_R(&safe_time, &safe_date);
+
+ copy_tm_to_TM64(&safe_date, p);
+ assert(check_tm(p));
+
+ return p;
+ }
+
+#ifdef HAS_TM_TM_GMTOFF
+ p->tm_gmtoff = 0;
+#endif
+ p->tm_isdst = 0;
+
+#ifdef HAS_TM_TM_ZONE
+ p->tm_zone = "UTC";
+#endif
+
+ v_tm_sec = (int)(time % 60);
+ time /= 60;
+ v_tm_min = (int)(time % 60);
+ time /= 60;
+ v_tm_hour = (int)(time % 24);
+ time /= 24;
+ v_tm_tday = time;
+
+ WRAP (v_tm_sec, v_tm_min, 60);
+ WRAP (v_tm_min, v_tm_hour, 60);
+ WRAP (v_tm_hour, v_tm_tday, 24);
+
+ v_tm_wday = (int)((v_tm_tday + 4) % 7);
+ if (v_tm_wday < 0)
+ v_tm_wday += 7;
+ m = v_tm_tday;
+
+ if (m >= CHEAT_DAYS) {
+ year = CHEAT_YEARS;
+ m -= CHEAT_DAYS;
+ }
+
+ if (m >= 0) {
+ /* Gregorian cycles, this is huge optimization for distant times */
+ cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
+ if( cycles ) {
+ m -= (cycles * (Time64_T) days_in_gregorian_cycle);
+ year += (cycles * years_in_gregorian_cycle);
+ }
+
+ /* Years */
+ leap = IS_LEAP (year);
+ while (m >= (Time64_T) length_of_year[leap]) {
+ m -= (Time64_T) length_of_year[leap];
+ year++;
+ leap = IS_LEAP (year);
+ }
+
+ /* Months */
+ v_tm_mon = 0;
+ while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
+ m -= (Time64_T) days_in_month[leap][v_tm_mon];
+ v_tm_mon++;
+ }
+ } else {
+ year--;
+
+ /* Gregorian cycles */
+ cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
+ if( cycles ) {
+ m -= (cycles * (Time64_T) days_in_gregorian_cycle);
+ year += (cycles * years_in_gregorian_cycle);
+ }
+
+ /* Years */
+ leap = IS_LEAP (year);
+ while (m < (Time64_T) -length_of_year[leap]) {
+ m += (Time64_T) length_of_year[leap];
+ year--;
+ leap = IS_LEAP (year);
+ }
+
+ /* Months */
+ v_tm_mon = 11;
+ while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
+ m += (Time64_T) days_in_month[leap][v_tm_mon];
+ v_tm_mon--;
+ }
+ m += (Time64_T) days_in_month[leap][v_tm_mon];
+ }
+
+ p->tm_year = year;
+ if( p->tm_year != year ) {
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#endif
+ return NULL;
+ }
+
+ /* At this point m is less than a year so casting to an int is safe */
+ p->tm_mday = (int) m + 1;
+ p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
+ p->tm_sec = v_tm_sec;
+ p->tm_min = v_tm_min;
+ p->tm_hour = v_tm_hour;
+ p->tm_mon = v_tm_mon;
+ p->tm_wday = v_tm_wday;
+
+ assert(check_tm(p));
+
+ return p;
+}
+
+
+struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
+{
+ time_t safe_time;
+ struct tm safe_date;
+ struct TM gm_tm;
+ Year orig_year;
+ int month_diff;
+
+ assert(local_tm != NULL);
+
+ /* Use the system localtime() if time_t is small enough */
+ if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
+ safe_time = (time_t)*time;
+
+ TIME64_TRACE1("Using system localtime for %lld\n", *time);
+
+ LOCALTIME_R(&safe_time, &safe_date);
+
+ copy_tm_to_TM64(&safe_date, local_tm);
+ assert(check_tm(local_tm));
+
+ return local_tm;
+ }
+
+ if( gmtime64_r(time, &gm_tm) == NULL ) {
+ TIME64_TRACE1("gmtime64_r returned null for %lld\n", *time);
+ return NULL;
+ }
+
+ orig_year = gm_tm.tm_year;
+
+ if (gm_tm.tm_year > (2037 - 1900) ||
+ gm_tm.tm_year < (1970 - 1900)
+ )
+ {
+ TIME64_TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
+ gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
+ }
+
+ safe_time = (time_t)timegm64(&gm_tm);
+ if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
+ TIME64_TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
+ return NULL;
+ }
+
+ copy_tm_to_TM64(&safe_date, local_tm);
+
+ local_tm->tm_year = orig_year;
+ if( local_tm->tm_year != orig_year ) {
+ TIME64_TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
+ (Year)local_tm->tm_year, (Year)orig_year);
+
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#endif
+ return NULL;
+ }
+
+
+ month_diff = local_tm->tm_mon - gm_tm.tm_mon;
+
+ /* When localtime is Dec 31st previous year and
+ gmtime is Jan 1st next year.
+ */
+ if( month_diff == 11 ) {
+ local_tm->tm_year--;
+ }
+
+ /* When localtime is Jan 1st, next year and
+ gmtime is Dec 31st, previous year.
+ */
+ if( month_diff == -11 ) {
+ local_tm->tm_year++;
+ }
+
+ /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
+ in a non-leap xx00. There is one point in the cycle
+ we can't account for which the safe xx00 year is a leap
+ year. So we need to correct for Dec 31st comming out as
+ the 366th day of the year.
+ */
+ if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
+ local_tm->tm_yday--;
+
+ assert(check_tm(local_tm));
+
+ return local_tm;
+}
+
+
+int valid_tm_wday( const struct TM* date ) {
+ if( 0 <= date->tm_wday && date->tm_wday <= 6 )
+ return 1;
+ else
+ return 0;
+}
+
+int valid_tm_mon( const struct TM* date ) {
+ if( 0 <= date->tm_mon && date->tm_mon <= 11 )
+ return 1;
+ else
+ return 0;
+}
+
+
+char *asctime64_r( const struct TM* date, char *result ) {
+ /* I figure everything else can be displayed, even hour 25, but if
+ these are out of range we walk off the name arrays */
+ if( !valid_tm_wday(date) || !valid_tm_mon(date) )
+ return NULL;
+
+ sprintf(result, TM64_ASCTIME_FORMAT,
+ wday_name[date->tm_wday],
+ mon_name[date->tm_mon],
+ date->tm_mday, date->tm_hour,
+ date->tm_min, date->tm_sec,
+ 1900 + date->tm_year);
+
+ return result;
+}
+
+
+char *ctime64_r( const Time64_T* time, char* result ) {
+ struct TM date;
+
+ localtime64_r( time, &date );
+ return asctime64_r( &date, result );
+}
+
+
+/* Non-thread safe versions of the above */
+struct TM *localtime64(const Time64_T *time) {
+ tzset();
+ return localtime64_r(time, &Static_Return_Date);
+}
+
+struct TM *gmtime64(const Time64_T *time) {
+ return gmtime64_r(time, &Static_Return_Date);
+}
+
+char *asctime64( const struct TM* date ) {
+ return asctime64_r( date, Static_Return_String );
+}
+
+char *ctime64( const Time64_T* time ) {
+ tzset();
+ return asctime64(localtime64(time));
+}
diff --git a/contrib/native/client/src/clientlib/y2038/time64.h b/contrib/native/client/src/clientlib/y2038/time64.h
new file mode 100644
index 000000000..89fbd7ce9
--- /dev/null
+++ b/contrib/native/client/src/clientlib/y2038/time64.h
@@ -0,0 +1,110 @@
+/*
+
+Copyright (c) 2007-2010 Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+
+#ifndef TIME64_H
+# define TIME64_H
+
+#include <time.h>
+#include "time64_config.h"
+
+/* Set our custom types */
+typedef INT_64_T Int64;
+typedef Int64 Time64_T;
+typedef Int64 Year;
+
+
+/* A copy of the tm struct but with a 64 bit year */
+struct TM64 {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ Year tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+
+#ifdef HAS_TM_TM_GMTOFF
+ long tm_gmtoff;
+#endif
+
+#ifdef HAS_TM_TM_ZONE
+ char *tm_zone;
+#endif
+};
+
+
+/* Decide which tm struct to use */
+#ifdef USE_TM64
+#define TM TM64
+#else
+#define TM tm
+#endif
+
+
+/* Declare public functions */
+struct TM *gmtime64_r (const Time64_T *, struct TM *);
+struct TM *localtime64_r (const Time64_T *, struct TM *);
+struct TM *gmtime64 (const Time64_T *);
+struct TM *localtime64 (const Time64_T *);
+
+char *asctime64 (const struct TM *);
+char *asctime64_r (const struct TM *, char *);
+
+char *ctime64 (const Time64_T*);
+char *ctime64_r (const Time64_T*, char*);
+
+Time64_T timegm64 (const struct TM *);
+Time64_T mktime64 (struct TM *);
+Time64_T timelocal64 (struct TM *);
+
+
+/* Not everyone has gm/localtime_r(), provide a replacement */
+#ifdef HAS_LOCALTIME_R
+# define LOCALTIME_R(clock, result) localtime_r(clock, result)
+#else
+# define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
+#endif
+#ifdef HAS_GMTIME_R
+# define GMTIME_R(clock, result) gmtime_r(clock, result)
+#else
+# define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
+#endif
+
+
+/* Use a different asctime format depending on how big the year is */
+#ifdef USE_TM64
+ #define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %lld\n"
+#else
+ #define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n"
+#endif
+
+
+#endif
diff --git a/contrib/native/client/src/clientlib/y2038/time64_config.h b/contrib/native/client/src/clientlib/y2038/time64_config.h
new file mode 100644
index 000000000..8f68bef68
--- /dev/null
+++ b/contrib/native/client/src/clientlib/y2038/time64_config.h
@@ -0,0 +1,107 @@
+/*
+
+Copyright (c) 2007-2010 Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+
+/* Configuration
+ -------------
+ Define as appropriate for your system.
+ Sensible defaults provided.
+*/
+
+
+#ifndef TIME64_CONFIG_H
+# define TIME64_CONFIG_H
+
+/* Debugging
+ TIME_64_DEBUG
+ Define if you want debugging messages
+*/
+/* #define TIME_64_DEBUG */
+
+
+/* INT_64_T
+ A 64 bit integer type to use to store time and others.
+ Must be defined.
+*/
+#define INT_64_T long long
+
+
+/* USE_TM64
+ Should we use a 64 bit safe replacement for tm? This will
+ let you go past year 2 billion but the struct will be incompatible
+ with tm. Conversion functions will be provided.
+*/
+/* #define USE_TM64 */
+
+
+/* Availability of system functions.
+
+ HAS_GMTIME_R
+ Define if your system has gmtime_r()
+
+ HAS_LOCALTIME_R
+ Define if your system has localtime_r()
+
+ HAS_TIMEGM
+ Define if your system has timegm(), a GNU extension.
+*/
+#ifndef _WIN32
+#define HAS_GMTIME_R
+#define HAS_LOCALTIME_R
+#endif
+/* #define HAS_TIMEGM */
+
+
+/* Details of non-standard tm struct elements.
+
+ HAS_TM_TM_GMTOFF
+ True if your tm struct has a "tm_gmtoff" element.
+ A BSD extension.
+
+ HAS_TM_TM_ZONE
+ True if your tm struct has a "tm_zone" element.
+ A BSD extension.
+*/
+/* #define HAS_TM_TM_GMTOFF */
+/* #define HAS_TM_TM_ZONE */
+
+
+/* USE_SYSTEM_LOCALTIME
+ USE_SYSTEM_GMTIME
+ USE_SYSTEM_MKTIME
+ USE_SYSTEM_TIMEGM
+ Should we use the system functions if the time is inside their range?
+ Your system localtime() is probably more accurate, but our gmtime() is
+ fast and safe.
+*/
+#define USE_SYSTEM_LOCALTIME
+/* #define USE_SYSTEM_GMTIME */
+#define USE_SYSTEM_MKTIME
+/* #define USE_SYSTEM_TIMEGM */
+
+#endif /* TIME64_CONFIG_H */
diff --git a/contrib/native/client/src/clientlib/y2038/time64_limits.h b/contrib/native/client/src/clientlib/y2038/time64_limits.h
new file mode 100644
index 000000000..e640cae9a
--- /dev/null
+++ b/contrib/native/client/src/clientlib/y2038/time64_limits.h
@@ -0,0 +1,124 @@
+/*
+
+Copyright (c) 2007-2010 Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+
+/*
+ Maximum and minimum inputs your system's respective time functions
+ can correctly handle. time64.h will use your system functions if
+ the input falls inside these ranges and corresponding USE_SYSTEM_*
+ constant is defined.
+*/
+
+#ifndef TIME64_LIMITS_H
+#define TIME64_LIMITS_H
+
+/* Max/min for localtime() */
+#define SYSTEM_LOCALTIME_MAX 2147483647
+#define SYSTEM_LOCALTIME_MIN -2147483647-1
+
+/* Max/min for gmtime() */
+#define SYSTEM_GMTIME_MAX 2147483647
+#define SYSTEM_GMTIME_MIN -2147483647-1
+
+/* Max/min for mktime() */
+static const struct tm SYSTEM_MKTIME_MAX = {
+ 7,
+ 14,
+ 19,
+ 18,
+ 0,
+ 138,
+ 1,
+ 17,
+ 0
+#ifdef HAS_TM_TM_GMTOFF
+ ,-28800
+#endif
+#ifdef HAS_TM_TM_ZONE
+ ,"PST"
+#endif
+};
+
+static const struct tm SYSTEM_MKTIME_MIN = {
+ 52,
+ 45,
+ 12,
+ 13,
+ 11,
+ 1,
+ 5,
+ 346,
+ 0
+#ifdef HAS_TM_TM_GMTOFF
+ ,-28800
+#endif
+#ifdef HAS_TM_TM_ZONE
+ ,"PST"
+#endif
+};
+
+/* Max/min for timegm() */
+#ifdef HAS_TIMEGM
+static const struct tm SYSTEM_TIMEGM_MAX = {
+ 7,
+ 14,
+ 3,
+ 19,
+ 0,
+ 138,
+ 2,
+ 18,
+ 0
+ #ifdef HAS_TM_TM_GMTOFF
+ ,0
+ #endif
+ #ifdef HAS_TM_TM_ZONE
+ ,"UTC"
+ #endif
+};
+
+static const struct tm SYSTEM_TIMEGM_MIN = {
+ 52,
+ 45,
+ 20,
+ 13,
+ 11,
+ 1,
+ 5,
+ 346,
+ 0
+ #ifdef HAS_TM_TM_GMTOFF
+ ,0
+ #endif
+ #ifdef HAS_TM_TM_ZONE
+ ,"UTC"
+ #endif
+};
+#endif /* HAS_TIMEGM */
+
+#endif /* TIME64_LIMITS_H */
diff --git a/contrib/native/client/src/include/drill/drillc.hpp b/contrib/native/client/src/include/drill/drillc.hpp
index e5a0d33de..817b680d2 100644
--- a/contrib/native/client/src/include/drill/drillc.hpp
+++ b/contrib/native/client/src/include/drill/drillc.hpp
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-#ifndef DRILL_CLIENT__ALL_H
+#ifndef DRILL_CLIENT_ALL_H
#define DRILL_CLIENT_ALL_H
#include "drill/common.hpp"
diff --git a/contrib/native/client/src/include/drill/recordBatch.hpp b/contrib/native/client/src/include/drill/recordBatch.hpp
index 4ed1e3139..dab8b9b6b 100644
--- a/contrib/native/client/src/include/drill/recordBatch.hpp
+++ b/contrib/native/client/src/include/drill/recordBatch.hpp
@@ -403,19 +403,20 @@ template <typename VALUE_TYPE>
// more complex and start doing dynamic allocations in these classes.
struct DateTimeBase{
- DateTimeBase(){m_datetime=0;}
+ DateTimeBase():m_datetime(0){}
virtual ~DateTimeBase(){}
- uint64_t m_datetime;
+ int64_t m_datetime;
+ int64_t getMillis() const { return m_datetime; }
virtual void load() =0;
virtual std::string toString()=0;
};
struct DateHolder: public virtual DateTimeBase{
DateHolder(){};
- DateHolder(uint64_t d){m_datetime=d; load();}
- uint32_t m_year;
- uint32_t m_month;
- uint32_t m_day;
+ DateHolder(int64_t d){m_datetime=d; load();}
+ int32_t m_year;
+ int32_t m_month;
+ int32_t m_day;
void load();
std::string toString();
};
@@ -433,21 +434,21 @@ struct TimeHolder: public virtual DateTimeBase{
struct DateTimeHolder: public DateHolder, public TimeHolder{
DateTimeHolder(){};
- DateTimeHolder(uint64_t d){m_datetime=d; load();}
+ DateTimeHolder(int64_t d){m_datetime=d; load();}
void load();
std::string toString();
};
struct DateTimeTZHolder: public DateTimeHolder{
DateTimeTZHolder(ByteBuf_t b){
- m_datetime=*(uint64_t*)b;
+ m_datetime=*(int64_t*)b;
m_tzIndex=*(uint32_t*)(b+sizeof(uint64_t));
load();
}
void load();
std::string toString();
int32_t m_tzIndex;
- static uint32_t size(){ return sizeof(uint64_t)+sizeof(uint32_t); }
+ static uint32_t size(){ return sizeof(int64_t)+sizeof(uint32_t); }
};
@@ -703,8 +704,8 @@ typedef NullableValueVectorTyped<DecimalValue , ValueVectorDecimal38Dense> Nulla
typedef NullableValueVectorTyped<DecimalValue , ValueVectorDecimal28Sparse> NullableValueVectorDecimal28Sparse;
typedef NullableValueVectorTyped<DecimalValue , ValueVectorDecimal38Sparse> NullableValueVectorDecimal38Sparse;
-typedef ValueVectorTyped<DateHolder, uint64_t> ValueVectorDate;
-typedef ValueVectorTyped<DateTimeHolder, uint64_t> ValueVectorTimestamp;
+typedef ValueVectorTyped<DateHolder, int64_t> ValueVectorDate;
+typedef ValueVectorTyped<DateTimeHolder, int64_t> ValueVectorTimestamp;
typedef ValueVectorTyped<TimeHolder, uint32_t> ValueVectorTime;
typedef ValueVectorTypedComposite<DateTimeTZHolder> ValueVectorTimestampTZ;
typedef ValueVectorTypedComposite<IntervalHolder> ValueVectorInterval;