Commit 969f35f0 authored by captainwong's avatar captainwong

timezone

parent 169d0250
...@@ -197,7 +197,7 @@ static const char* strerror_t(int savedErrno) { ...@@ -197,7 +197,7 @@ static const char* strerror_t(int savedErrno) {
/******** Logger::Impl *********/ /******** Logger::Impl *********/
Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line) Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line)
: time_(Timestamp::now()) : time_(nowTimestamp())
, stream_() , stream_()
, level_(level) , level_(level)
, line_(line) , line_(line)
......
...@@ -9,10 +9,23 @@ ...@@ -9,10 +9,23 @@
#ifdef JLIB_WINDOWS #ifdef JLIB_WINDOWS
# include <windows.h> # include <windows.h>
static inline struct tm* gmtime_r(const time_t* timep, struct tm* result) # include <iomanip> // for std::get_time
{
gmtime_s(result, timep); static inline struct tm* gmtime_r(const time_t* timep, struct tm* result) {
return result; gmtime_s(result, timep); return result;
}
// https://stackoverflow.com/a/29411795/2963736
static inline time_t timegm(tm* t) {
return _mkgmtime(t);
}
// https://stackoverflow.com/a/33542189/2963736
static inline char* strptime(const char* str, const char* format, struct tm* tm) {
std::istringstream input(str);
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
input >> std::get_time(tm, format);
return (!input.fail()) ? (char*)(str + (int)input.tellg()) : nullptr;
} }
#else #else
# include <sys/time.h> // gettimeofday # include <sys/time.h> // gettimeofday
...@@ -28,8 +41,38 @@ static constexpr int MICRO_SECONDS_PER_SECOND = 1000 * 1000; ...@@ -28,8 +41,38 @@ static constexpr int MICRO_SECONDS_PER_SECOND = 1000 * 1000;
static constexpr uint64_t EPOCH = 116444736000000000UL; static constexpr uint64_t EPOCH = 116444736000000000UL;
static inline int64_t gettimeofdayUsec()
{ /********** Windows & Linux *******/
//! make struct tm
static inline tm makeTm(int y, int m, int d, int h, int mm, int s) {
tm t = { 0 };
t.tm_year = y - 1900;
t.tm_mon = m - 1;
t.tm_mday = d;
t.tm_hour = h;
t.tm_min = mm;
t.tm_sec = s;
return t;
}
// make struct tm from time string
static inline tm makeTm(const char* s) {
tm t = { 0 }; strptime(s, "%Y-%m-%d %T", &t); return t;
}
//! make time_t
static inline time_t makeTime_t(int y, int m, int d, int h, int mm, int s) {
tm t = makeTm(y, m, d, h, mm, s); return timegm(&t);
}
//! make time_t from time string
static inline time_t makeTime_t(const char* s) {
tm t = makeTm(s); return timegm(&t);
}
//! gettimeofday
static inline int64_t gettimeofdayUsec() {
#ifdef JLIB_WINDOWS #ifdef JLIB_WINDOWS
FILETIME ft = { 0 }; FILETIME ft = { 0 };
...@@ -62,8 +105,7 @@ static inline int64_t gettimeofdayUsec() ...@@ -62,8 +105,7 @@ static inline int64_t gettimeofdayUsec()
#ifdef JLIB_WINDOWS #ifdef JLIB_WINDOWS
static inline tm systemTimeToTm(const SYSTEMTIME& st) static inline tm systemTimeToTm(const SYSTEMTIME& st) {
{
tm tm; tm tm;
tm.tm_year = st.wYear - 1900; tm.tm_year = st.wYear - 1900;
tm.tm_mon = st.wMonth - 1; tm.tm_mon = st.wMonth - 1;
...@@ -75,8 +117,7 @@ static inline tm systemTimeToTm(const SYSTEMTIME& st) ...@@ -75,8 +117,7 @@ static inline tm systemTimeToTm(const SYSTEMTIME& st)
return tm; return tm;
} }
static inline SYSTEMTIME tmToSystemTime(const tm& tm) static inline SYSTEMTIME tmToSystemTime(const tm& tm) {
{
SYSTEMTIME st = { 0 }; SYSTEMTIME st = { 0 };
st.wYear = tm.tm_year + 1900; st.wYear = tm.tm_year + 1900;
st.wMonth = tm.tm_mon + 1; st.wMonth = tm.tm_mon + 1;
...@@ -88,24 +129,21 @@ static inline SYSTEMTIME tmToSystemTime(const tm& tm) ...@@ -88,24 +129,21 @@ static inline SYSTEMTIME tmToSystemTime(const tm& tm)
return st; return st;
} }
static inline time_t systemTimeToTime_t(const SYSTEMTIME& st) static inline time_t systemTimeToTime_t(const SYSTEMTIME& st) {
{ tm tm = systemTimeToTm(st); return mktime(&tm);
tm tm = systemTimeToTm(st);
return mktime(&tm);
} }
static inline SYSTEMTIME time_tToSystemTime(time_t t) static inline SYSTEMTIME time_tToSystemTime(time_t t) {
{ tm tm; gmtime_s(&tm, &t); return tmToSystemTime(tm);
tm tm; gmtime_s(&tm, &t);
return tmToSystemTime(tm);
} }
static inline SYSTEMTIME time_tToSystemTimeLocal(time_t t) static inline SYSTEMTIME time_tToSystemTimeLocal(time_t t) {
{ tm tm; localtime_s(&tm, &t); return tmToSystemTime(tm);
tm tm; localtime_s(&tm, &t);
return tmToSystemTime(tm);
} }
#endif // JLIB_WINDOWS #endif // JLIB_WINDOWS
} }
#pragma once #pragma once
#include "config.h" #include "config.h"
#include "copyable.h" //
#include <time.h> //#include "copyable.h"
#include <memory> //#include <time.h>
#include <vector> //#include <memory>
#include <string> //#include <vector>
//#include <string>
#include "../3rdparty/date/include/date/tz.h"
namespace jlib
{
namespace detail
{
struct Transition
{
time_t gmtime_;
time_t localtime_;
int localTimeIdx_;
Transition(time_t gmt, time_t localt, int localIdx)
: gmtime_(gmt)
, localtime_(localt)
, localTimeIdx_(localIdx)
{}
};
struct Compare
{
bool compareGmt_ = true;
Compare(bool gmt)
: compareGmt_(gmt)
{}
bool operator()(const Transition& lhs, const Transition& rhs) const {
if (compareGmt_) {
return lhs.gmtime_ < rhs.gmtime_;
} else {
return lhs.localtime_ < rhs.localtime_;
}
}
bool equal(const Transition& lhs, const Transition& rhs) const {
if (compareGmt_) {
return lhs.gmtime_ == rhs.gmtime_;
} else {
return lhs.localtime_ == rhs.localtime_;
}
}
};
struct LocalTime
{
time_t gmtOffset;
bool isDst;
int abbrIdx;
LocalTime(time_t offset, bool dst, int abbr)
: gmtOffset(offset)
, isDst(dst)
, abbrIdx(abbr)
{}
};
} // namespace detail namespace jlib
static constexpr int SECONDS_PER_DAY = 24 * 60 * 60;
//! TimeZone for 1970~2030
class TimeZone : public copyable
{ {
public:
explicit TimeZone(const char* zonename) {
}
TimeZone(int bias, const char* tzname) {
}
TimeZone() = default; // invalid timezone
bool valid() const{
return static_cast<bool>(data_);
}
//struct tm toLocalTime(time_t secondsSinceEpoch) const {
//}
//time_t fromLocalTime(const struct tm& tm_time) const {
//}
//static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false);
//static time_t fromUtcTime(const struct tm& tm_time);
//
///**
//* @param year [1900, 2500]
//* @param month [1, 12]
//* @param day [1, 31]
//* @param hour [0, 23]
//* @param minute [0, 59]
//* @param seconds [0, 59]
//*/
//static time_t fromUtcTime(int year, int month, int day,
// int hour, int minute, int seconds) {
//}
struct Data {
std::vector<detail::Transition> transitions;
std::vector<detail::LocalTime> localtimes;
std::vector<std::string> names;
std::string abbreviation;
};
private: using namespace date;
std::shared_ptr<Data> data_ = {}; using TimeZone = date::time_zone;
};
//namespace detail
//{
//
//struct Transition
//{
// time_t gmtime_;
// time_t localtime_;
// int localTimeIdx_;
//
// Transition(time_t gmt, time_t localt, int localIdx)
// : gmtime_(gmt)
// , localtime_(localt)
// , localTimeIdx_(localIdx)
// {}
//};
//
//struct Compare
//{
// bool compareGmt_ = true;
//
// Compare(bool gmt)
// : compareGmt_(gmt)
// {}
//
// bool operator()(const Transition& lhs, const Transition& rhs) const {
// if (compareGmt_) {
// return lhs.gmtime_ < rhs.gmtime_;
// } else {
// return lhs.localtime_ < rhs.localtime_;
// }
// }
//
// bool equal(const Transition& lhs, const Transition& rhs) const {
// if (compareGmt_) {
// return lhs.gmtime_ == rhs.gmtime_;
// } else {
// return lhs.localtime_ == rhs.localtime_;
// }
// }
//};
//
//struct LocalTime
//{
// time_t gmtOffset;
// bool isDst;
// int abbrIdx;
//
// LocalTime(time_t offset, bool dst, int abbr)
// : gmtOffset(offset)
// , isDst(dst)
// , abbrIdx(abbr)
// {}
//};
//
//} // namespace detail
//
//
//static constexpr int SECONDS_PER_DAY = 24 * 60 * 60;
//
////! TimeZone for 1970~2030
//class TimeZone : public copyable
//{
//public:
// explicit TimeZone(const char* zonename) {
//
// }
//
// TimeZone(int bias, const char* tzname) {
//
// }
//
// TimeZone() = default; // invalid timezone
//
// bool valid() const{
// return static_cast<bool>(data_);
// }
//
// //struct tm toLocalTime(time_t secondsSinceEpoch) const {
//
// //}
//
// //time_t fromLocalTime(const struct tm& tm_time) const {
//
// //}
//
// //static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false);
// //static time_t fromUtcTime(const struct tm& tm_time);
// //
// ///**
// //* @param year [1900, 2500]
// //* @param month [1, 12]
// //* @param day [1, 31]
// //* @param hour [0, 23]
// //* @param minute [0, 59]
// //* @param seconds [0, 59]
// //*/
// //static time_t fromUtcTime(int year, int month, int day,
// // int hour, int minute, int seconds) {
//
// //}
//
// struct Data {
// std::vector<detail::Transition> transitions;
// std::vector<detail::LocalTime> localtimes;
// std::vector<std::string> names;
// std::string abbreviation;
// };
//
//private:
// std::shared_ptr<Data> data_ = {};
//};
} // namespace jlib } // namespace jlib
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
......
#include <Windows.h>
#include <stdio.h>
#include "../../jlib/base/timezone.h" #include "../../jlib/base/timezone.h"
#include "../../jlib/base/time.h"
#include <stdio.h>
#include <assert.h>
using namespace jlib;
struct TestCase {
const char* utc;
const char* local;
bool isdst;
};
void test(const TimeZone* tz, TestCase tc) {
time_t utc = makeTime_t(tc.utc);
{
auto localTime = make_zoned(tz, sys_seconds(std::chrono::seconds(utc)));
auto str = format("%F %T%z(%Z)", localTime);
if (str != tc.local) {
printf("WRONG: ");
}
printf("%s -> %s\n", tc.utc, str.c_str());
}
{
std::istringstream in(tc.local);
sys_time<std::chrono::seconds> result;
in >> parse("%F %T%z(%Z)", result);
auto str = format("%F %T", result);
if (str != tc.utc) {
printf("WRONG: ");
}
printf("%s -> %s\n", tc.local, str.c_str());
}
}
void testNewYork()
{
printf("testNewYork\n");
auto tz = locate_zone("America/New_York");
TestCase cases[] =
{
{"2006-03-07 00:00:00", "2006-03-06 19:00:00-0500(EST)", false},
{"2006-04-02 06:59:59", "2006-04-02 01:59:59-0500(EST)", false},
{"2006-04-02 07:00:00", "2006-04-02 03:00:00-0400(EDT)", true},
{"2006-05-01 00:00:00", "2006-04-30 20:00:00-0400(EDT)", true},
{"2006-05-02 01:00:00", "2006-05-01 21:00:00-0400(EDT)", true},
{"2006-10-21 05:00:00", "2006-10-21 01:00:00-0400(EDT)", true},
{"2006-10-29 05:59:59", "2006-10-29 01:59:59-0400(EDT)", true},
{"2006-10-29 06:00:00", "2006-10-29 01:00:00-0500(EST)", false},
{"2006-10-29 06:59:59", "2006-10-29 01:59:59-0500(EST)", false},
{"2006-12-31 06:00:00", "2006-12-31 01:00:00-0500(EST)", false},
{"2007-01-01 00:00:00", "2006-12-31 19:00:00-0500(EST)", false},
{"2007-03-07 00:00:00", "2007-03-06 19:00:00-0500(EST)", false},
{"2007-03-11 06:59:59", "2007-03-11 01:59:59-0500(EST)", false},
{"2007-03-11 07:00:00", "2007-03-11 03:00:00-0400(EDT)", true},
{"2007-05-01 00:00:00", "2007-04-30 20:00:00-0400(EDT)", true},
{"2007-05-02 01:00:00", "2007-05-01 21:00:00-0400(EDT)", true},
{"2007-10-31 05:00:00", "2007-10-31 01:00:00-0400(EDT)", true},
{"2007-11-04 05:59:59", "2007-11-04 01:59:59-0400(EDT)", true},
{"2007-11-04 06:00:00", "2007-11-04 01:00:00-0500(EST)", false},
{"2007-11-04 06:59:59", "2007-11-04 01:59:59-0500(EST)", false},
{"2007-12-31 06:00:00", "2007-12-31 01:00:00-0500(EST)", false},
{"2008-01-01 00:00:00", "2007-12-31 19:00:00-0500(EST)", false},
{"2009-03-07 00:00:00", "2009-03-06 19:00:00-0500(EST)", false},
{"2009-03-08 06:59:59", "2009-03-08 01:59:59-0500(EST)", false},
{"2009-03-08 07:00:00", "2009-03-08 03:00:00-0400(EDT)", true},
{"2009-05-01 00:00:00", "2009-04-30 20:00:00-0400(EDT)", true},
{"2009-05-02 01:00:00", "2009-05-01 21:00:00-0400(EDT)", true},
{"2009-10-31 05:00:00", "2009-10-31 01:00:00-0400(EDT)", true},
{"2009-11-01 05:59:59", "2009-11-01 01:59:59-0400(EDT)", true},
{"2009-11-01 06:00:00", "2009-11-01 01:00:00-0500(EST)", false},
{"2009-11-01 06:59:59", "2009-11-01 01:59:59-0500(EST)", false},
{"2009-12-31 06:00:00", "2009-12-31 01:00:00-0500(EST)", false},
{"2010-01-01 00:00:00", "2009-12-31 19:00:00-0500(EST)", false},
{"2010-03-13 00:00:00", "2010-03-12 19:00:00-0500(EST)", false},
{"2010-03-14 06:59:59", "2010-03-14 01:59:59-0500(EST)", false},
{"2010-03-14 07:00:00", "2010-03-14 03:00:00-0400(EDT)", true},
{"2010-05-01 00:00:00", "2010-04-30 20:00:00-0400(EDT)", true},
{"2010-05-02 01:00:00", "2010-05-01 21:00:00-0400(EDT)", true},
{"2010-11-06 05:00:00", "2010-11-06 01:00:00-0400(EDT)", true},
{"2010-11-07 05:59:59", "2010-11-07 01:59:59-0400(EDT)", true},
{"2010-11-07 06:00:00", "2010-11-07 01:00:00-0500(EST)", false},
{"2010-11-07 06:59:59", "2010-11-07 01:59:59-0500(EST)", false},
{"2010-12-31 06:00:00", "2010-12-31 01:00:00-0500(EST)", false},
{"2011-01-01 00:00:00", "2010-12-31 19:00:00-0500(EST)", false},
{"2011-03-01 00:00:00", "2011-02-28 19:00:00-0500(EST)", false},
{"2011-03-13 06:59:59", "2011-03-13 01:59:59-0500(EST)", false},
{"2011-03-13 07:00:00", "2011-03-13 03:00:00-0400(EDT)", true},
{"2011-05-01 00:00:00", "2011-04-30 20:00:00-0400(EDT)", true},
{"2011-05-02 01:00:00", "2011-05-01 21:00:00-0400(EDT)", true},
{"2011-11-06 05:59:59", "2011-11-06 01:59:59-0400(EDT)", true},
{"2011-11-06 06:00:00", "2011-11-06 01:00:00-0500(EST)", false},
{"2011-11-06 06:59:59", "2011-11-06 01:59:59-0500(EST)", false},
{"2011-12-31 06:00:00", "2011-12-31 01:00:00-0500(EST)", false},
{"2012-01-01 00:00:00", "2011-12-31 19:00:00-0500(EST)", false},
};
for (const auto& c : cases) {
test(tz, c);
}
}
void testLondon()
{
printf("testLondon\n");
auto tz = locate_zone("Europe/London");
TestCase cases[] =
{
{"2011-03-26 00:00:00", "2011-03-26 00:00:00+0000(GMT)", false},
{"2011-03-27 00:59:59", "2011-03-27 00:59:59+0000(GMT)", false},
{"2011-03-27 01:00:00", "2011-03-27 02:00:00+0100(BST)", true},
{"2011-10-30 00:59:59", "2011-10-30 01:59:59+0100(BST)", true},
{"2011-10-30 01:00:00", "2011-10-30 01:00:00+0000(GMT)", false},
{"2012-10-30 01:59:59", "2012-10-30 01:59:59+0000(GMT)", false},
{"2011-12-31 22:00:00", "2011-12-31 22:00:00+0000(GMT)", false},
{"2012-01-01 00:00:00", "2012-01-01 00:00:00+0000(GMT)", false},
{"2012-03-24 00:00:00", "2012-03-24 00:00:00+0000(GMT)", false},
{"2012-03-25 00:59:59", "2012-03-25 00:59:59+0000(GMT)", false},
{"2012-03-25 01:00:00", "2012-03-25 02:00:00+0100(BST)", true},
{"2012-10-28 00:59:59", "2012-10-28 01:59:59+0100(BST)", true},
{"2012-10-28 01:00:00", "2012-10-28 01:00:00+0000(GMT)", false},
{"2012-10-28 01:59:59", "2012-10-28 01:59:59+0000(GMT)", false},
{"2012-12-31 22:00:00", "2012-12-31 22:00:00+0000(GMT)", false},
{"2013-01-01 00:00:00", "2013-01-01 00:00:00+0000(GMT)", false},
};
for (const auto& c : cases) {
test(tz, c);
}
}
void testHongKong()
{
printf("testHongKong\n");
auto tz = locate_zone("Asia/Hong_Kong");
TestCase cases[] =
{
{"2011-04-03 00:00:00", "2011-04-03 08:00:00+0800(HKT)", false},
};
for (const auto& c : cases) {
test(tz, c);
}
}
void testSydney()
{
printf("testSydney\n");
auto tz = locate_zone("Australia/Sydney");
TestCase cases[] =
{
{"2011-01-01 00:00:00", "2011-01-01 11:00:00+1100(EST)", true},
{"2011-04-02 15:59:59", "2011-04-03 02:59:59+1100(EST)", true},
{"2011-04-02 16:00:00", "2011-04-03 02:00:00+1000(EST)", false},
{"2011-04-02 16:59:59", "2011-04-03 02:59:59+1000(EST)", false},
{"2011-05-02 01:00:00", "2011-05-02 11:00:00+1000(EST)", false},
{"2011-10-01 15:59:59", "2011-10-02 01:59:59+1000(EST)", false},
{"2011-10-01 16:00:00", "2011-10-02 03:00:00+1100(EST)", true},
{"2011-12-31 22:00:00", "2012-01-01 09:00:00+1100(EST)", true},
};
for (const auto& c : cases) {
test(tz, c);
}
}
//
//void testUtc()
//{
// const int kRange = 100 * 1000 * 1000;
// for (time_t t = -kRange; t <= kRange; t += 11) {
// struct tm* t1 = gmtime(&t);
// struct tm t2 = TimeZone::toUtcTime(t, true);
// char buf1[80], buf2[80];
// strftime(buf1, sizeof buf1, "%F %T %u %j", t1);
// strftime(buf2, sizeof buf2, "%F %T %u %j", &t2);
// if (strcmp(buf1, buf2) != 0) {
// printf("'%s' != '%s'\n", buf1, buf2);
// assert(0);
// }
// time_t t3 = TimeZone::fromUtcTime(t2);
// if (t != t3) {
// printf("%ld != %ld\n", static_cast<long>(t), static_cast<long>(t3));
// assert(0);
// }
// }
//}
//
//void testFixedTimezone()
//{
// TimeZone tz(8 * 3600, "CST");
// TestCase cases[] =
// {
//
// {"2014-04-03 00:00:00", "2014-04-03 08:00:00+0800(CST)", false},
//
// };
//
// for (const auto& c : cases) {
// test(tz, c);
// }
//}
int main() int main()
{ {
TIME_ZONE_INFORMATION info = { 0 }; /*TIME_ZONE_INFORMATION info = { 0 };
auto ret = GetTimeZoneInformation(&info); auto ret = GetTimeZoneInformation(&info);
printf("info.bias=%ld\n", info.Bias); printf("info.bias=%ld\n", info.Bias);*/
}
\ No newline at end of file
auto utc_now = floor<std::chrono::seconds>(std::chrono::system_clock::now());
auto cst_now = make_zoned(current_zone(), utc_now);
printf("utc: %s\n", format("%F %T%z(%Z)", utc_now).c_str());
printf("cst: %s\n", format("%F %T%z(%Z)", cst_now).c_str());
testNewYork();
testLondon();
testSydney();
testHongKong();
//testFixedTimezone();
//testUtc();
}
...@@ -87,9 +87,12 @@ ...@@ -87,9 +87,12 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<PreprocessorDefinitions>HAS_UNCAUGHT_EXCEPTIONS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<AdditionalDependencies>G:\dev_libs\date\build\Debug\tz.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment