我不想使用time_t因为2038年的问题,但是我在互联网上发现的所有例子都使用它来将time_point转换为tm.
有没有一个简单的方法来从time_point转换为tm(最好不用提升)?
像libc这样的timesub的实现将是我最后的手段:
http://www.opensource.apple.com/source/Libc/Libc-262/stdtime/localtime.c
编辑:阅读建议的链接并进行更多的研究后,我得出以下结论.
>使用time_t,它是64位长的是(大多数目的).
>使用Boost.Date_Time进行便携式代码.
值得注意的是,Boost.Date_Time可以是一个只有标题的库.资源:
http://www.boost.org/doc/libs/1_53_0/more/getting_started/unix-variants.html#header-only-libraries
解决方法
I would like to print or extract year/month/day values.
Is there a simple way to convert from time_point to tm (preferably
without boost)?
首先要注意的是,std :: chrono :: time_point不仅在持续时间,而且在时钟上进行模板化.时钟意味着一个时代.不同的时钟可以有不同的时代.
例如,在我的系统上,std :: chrono :: high_resolution_clock和std :: chrono :: stable_clock有一个时代:每当计算机启动.如果您不知道计算机何时启动,则无法将该time_point转换为任何日历系统.
话虽如此,你可能正在谈论std :: chrono :: system_clock :: time_point,因为这个time_point,只有这个time_point需要与民用(gregorian)日历确定性的关系.
事实证明,我所知道的std :: chrono :: system_clock的每个实现都是使用unix time.这有一个1970年的新纪元忽略了闰秒.
标准不能保证.但是,如果要使用以下公式,可以利用这一事实:
07001
首先,警告,我使用最新的C 1y草案,其中包括伟大的新的constexpr工具.如果您需要退出编译器的某些constexpr属性,那么这样做.
给定上述链接中的算法,您可以转换std :: chrono :: time_point< std :: chrono :: system_clock,Duration>到std :: tm,而不使用带有以下功能的time_t:
template <class Duration> std::tm make_utc_tm(std::chrono::time_point<std::chrono::system_clock,Duration> tp) { using namespace std; using namespace std::chrono; typedef duration<int,ratio_multiply<hours::period,ratio<24>>> days; // t is time duration since 1970-01-01 Duration t = tp.time_since_epoch(); // d is days since 1970-01-01 days d = round_down<days>(t); // t is now time duration since midnight of day d t -= d; // break d down into year/month/day int year; unsigned month; unsigned day; std::tie(year,month,day) = civil_from_days(d.count()); // start filling in the tm with calendar info std::tm tm = {0}; tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_wday = weekday_from_days(d.count()); tm.tm_yday = d.count() - days_from_civil(year,1,1); // Fill in the time tm.tm_hour = duration_cast<hours>(t).count(); t -= hours(tm.tm_hour); tm.tm_min = duration_cast<minutes>(t).count(); t -= minutes(tm.tm_min); tm.tm_sec = duration_cast<seconds>(t).count(); return tm; }
另请注意,所有现有实现的std :: chrono :: system_clock :: time_point是UTC(忽略闰秒)时区的持续时间.如果要使用另一个时区转换time_point,则需要将时区偏移量添加/减去std :: chrono :: system_clock :: time_point,然后将其转换为天数精度.而且如果您进一步想要考虑到闰秒,则在截断之前使用this table调整适当的秒数,并了解unix时间与UTC的对应关系.
此功能可以通过以下方式验证:
#include <iostream> #include <iomanip> void print_tm(const std::tm& tm) { using namespace std; cout << tm.tm_year+1900; char fill = cout.fill(); cout << setfill('0'); cout << '-' << setw(2) << tm.tm_mon+1; cout << '-' << setw(2) << tm.tm_mday; cout << ' '; switch (tm.tm_wday) { case 0: cout << "Sun"; break; case 1: cout << "Mon"; break; case 2: cout << "Tue"; break; case 3: cout << "Wed"; break; case 4: cout << "Thu"; break; case 5: cout << "Fri"; break; case 6: cout << "Sat"; break; } cout << ' '; cout << ' ' << setw(2) << tm.tm_hour; cout << ':' << setw(2) << tm.tm_min; cout << ':' << setw(2) << tm.tm_sec << " UTC."; cout << setfill(fill); cout << " This is " << tm.tm_yday << " days since Jan 1\n"; } int main() { print_tm(make_utc_tm(std::chrono::system_clock::now())); }
我目前打印出来的
2013-09-15 Sun 18:16:50 UTC. This is 257 days since Jan 1
如果chrono-Compatible Low-Level Date Algorithms脱机或被移动,这里是make_utc_tm中使用的算法.在上述链接中对这些算法进行了深入的解释.它们经过了很好的测试,具有非常大的有效性.
// Returns number of days since civil 1970-01-01. Negative values indicate // days prior to 1970-01-01. // Preconditions: y-m-d represents a date in the civil (Gregorian) calendar // m is in [1,12] // d is in [1,last_day_of_month(y,m)] // y is "approximately" in // [numeric_limits<Int>::min()/366,numeric_limits<Int>::max()/366] // Exact range of validity is: // [civil_from_days(numeric_limits<Int>::min()),// civil_from_days(numeric_limits<Int>::max()-719468)] template <class Int> constexpr Int days_from_civil(Int y,unsigned m,unsigned d) noexcept { static_assert(std::numeric_limits<unsigned>::digits >= 18,"This algorithm has not been ported to a 16 bit unsigned integer"); static_assert(std::numeric_limits<Int>::digits >= 20,"This algorithm has not been ported to a 16 bit signed integer"); y -= m <= 2; const Int era = (y >= 0 ? y : y-399) / 400; const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0,399] const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0,365] const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0,146096] return era * 146097 + static_cast<Int>(doe) - 719468; } // Returns year/month/day triple in civil calendar // Preconditions: z is number of days since 1970-01-01 and is in the range: // [numeric_limits<Int>::min(),numeric_limits<Int>::max()-719468]. template <class Int> constexpr std::tuple<Int,unsigned,unsigned> civil_from_days(Int z) noexcept { static_assert(std::numeric_limits<unsigned>::digits >= 18,"This algorithm has not been ported to a 16 bit signed integer"); z += 719468; const Int era = (z >= 0 ? z : z - 146096) / 146097; const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0,146096] const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0,399] const Int y = static_cast<Int>(yoe) + era * 400; const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0,365] const unsigned mp = (5*doy + 2)/153; // [0,11] const unsigned d = doy - (153*mp+2)/5 + 1; // [1,31] const unsigned m = mp + (mp < 10 ? 3 : -9); // [1,12] return std::tuple<Int,unsigned>(y + (m <= 2),m,d); } template <class Int> constexpr unsigned weekday_from_days(Int z) noexcept { return static_cast<unsigned>(z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6); } template <class To,class Rep,class Period> To round_down(const std::chrono::duration<Rep,Period>& d) { To t = std::chrono::duration_cast<To>(d); if (t > d) --t; return t; }
更新
最近我把上面的算法包装成一个可以免费使用的日期/时间库documented and available here.这个库可以很容易地从std :: system_clock :: time_point提取一个年/月/日,甚至是几个小时:分钟:秒:分数秒.所有没有经过time_t.
这是一个使用上述标题库的简单程序,以打印UTC时区中的当前日期和时间,以及system_clock :: time_point提供的精度(在这种情况下为微秒):
#include "date.h" #include <iostream> int main() { using namespace date; using namespace std; using namespace std::chrono; auto const now = system_clock::now(); auto const dp = time_point_cast<days>(now); auto const date = year_month_day(dp); auto const time = make_time(now-dp); cout << date << ' ' << time << " UTC\n"; }
哪个只是为我输出:
2015-05-19 15:03:47.754002 UTC
该库有效地将std :: chrono :: system_clock :: time_point转换成易于使用的日期时间类型.