C++ 将月份添加到 chrono::system_clock::time_point
C++ Add months to chrono::system_clock::time_point
如何将月份添加到 chrono::system_clock::time_point 值?
谢谢!
概览
这是一个非常有趣的问题,有几个答案。 "correct" 答案是您必须根据具体应用决定的。
对于月份,您可以选择进行时间计算或日历计算。按时间顺序计算处理时间点和持续时间的规则单位,例如小时、分钟和秒。日历计算处理不规则日历,主要用于给日子起个好记的名字。
年代计算
如果问题是关于未来月份的一些物理过程,物理学不关心不同月份的长度不同,因此按时间顺序计算就足够了:
宝宝还有9个月预产期
6 个月后这里的天气会怎样?
为了对这些东西进行建模,按平均个月计算可能就足够了。可以创建一个 std::chrono::duration
具有 精确 平均公历(民用)月的长度。最简单的方法是定义一系列以 days
:
开头的持续时间
days
是 24 小时:
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
years
为 365.2425 days
,或 146097/400 days
:
using years = std::chrono::duration
<int, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;
最后months
是1/12 of years
:
using months = std::chrono::duration
<int, std::ratio_divide<years::period, std::ratio<12>>>;
现在您可以轻松计算从现在起的 8 个月:
auto t = system_clock::now() + months{8};
重要说明:此计算不会保留一天中的时间,甚至一个月中的某一天。
历法计算
也可以在保留一天中的时间和一个月中的第几天的同时添加月份。此类计算是 日历计算,而不是 时间计算。
选择日历后(例如公历(民用)日历、儒略历,或者可能是伊斯兰历、科普特历或埃塞俄比亚历——它们都有月份,但并非都是相同的月份),过程是:
将system_clock::time_point
转换为日历。
在日历系统中执行月份计算。
将新日历时间转换回system_clock::time_point
。
您可以使用 Howard Hinnant's free, open-source date/time library 对一些日历执行此操作。这是民用日历的样子:
#include "date.h"
int
main()
{
using namespace date;
using namespace std::chrono;
// Get the current time
auto now = system_clock::now();
// Get a days-precision chrono::time_point
auto sd = floor<days>(now);
// Record the time of day
auto time_of_day = now - sd;
// Convert to a y/m/d calendar data structure
year_month_day ymd = sd;
// Add the months
ymd += months{8};
// Add some policy for overflowing the day-of-month if desired
if (!ymd.ok())
ymd = ymd.year()/ymd.month()/last;
// Convert back to system_clock::time_point
system_clock::time_point later = sys_days{ymd} + time_of_day;
}
为了笑我只是 运行 这个,并将它与 now + months{8}
比较并得到:
now is 2017-03-25 15:17:14.467080
later is 2017-11-25 15:17:14.467080 // calendrical computation
now + months{8} is 2017-11-24 03:10:02.467080 // chronological computation
这粗略地 "feel" 说明了日历计算与时间计算的不同之处。后者平均来说是完全准确的;它只是与日历有几天的偏差。有时更简单的(后一种)解决方案足够接近,有时则不然。只有你可以回答那个问题。
日历计算 — 现在有时区
最后,您可能希望在特定时区执行日历计算。之前的计算是 UTC。
Side note: system_clock
is not specified to be UTC, but the de facto standard is that it is Unix Time which is a very close approximation to UTC.
您可以使用 Howard Hinnant's free, open-source timezone library to do this computation. This is an extension of the previously mentioned datetime library.
代码非常相似,你只需要从 UTC 转换为本地时间,然后转换为本地日历,进行计算然后返回本地时间,最后返回 system_clock::time_point
(UTC):
#include "tz.h"
int
main()
{
using namespace date;
using namespace std::chrono;
// Get the current local time
auto lt = make_zoned(current_zone(), system_clock::now());
// Get a days-precision chrono::time_point
auto ld = floor<days>(lt.get_local_time());
// Record the local time of day
auto time_of_day = lt.get_local_time() - ld;
// Convert to a y/m/d calendar data structure
year_month_day ymd{ld};
// Add the months
ymd += months{8};
// Add some policy for overflowing the day-of-month if desired
if (!ymd.ok())
ymd = ymd.year()/ymd.month()/last;
// Convert back to local time
lt = local_days{ymd} + time_of_day;
// Convert back to system_clock::time_point
auto later = lt.get_sys_time();
}
更新我们的结果我得到:
now is 2017-03-25 15:17:14.467080
later is 2017-11-25 15:17:14.467080 // calendrical: UTC
later is 2017-11-25 16:17:14.467080 // calendrical: America/New_York
now + months{8} is 2017-11-24 03:10:02.467080 // chronological computation
时间晚了一个小时(UTC),因为我保留了当地时间(上午 11:17),但计算以夏令时开始,以标准时间结束,因此 UTC 等效时间晚了 1 小时.
我使用 current_zone()
获取我当前的位置,但我也可以使用特定时区(例如 "Asia/Tokyo"
)。
C++20 更新
在我撰写此更新时,C++20 的技术工作已经停止,看起来我们将在今年晚些时候推出新的 C++ 标准(只剩下完成 C++20 的管理工作)。
此答案中的建议 t运行 适合 C++20:
对于时间顺序计算,std::chrono::months
由 <chrono>
提供,因此您不必自己计算。
对于 UTC 日历计算,松开 #include "date.h"
并使用 #include <chrono>
,然后删除 using namespace date
,事情就会正常进行。
对于时区敏感的日历计算,松开 #include "tz.h"
并使用 #include <chrono>
,删除 using namespace date
,并将 make_zoned
替换为 zoned_time
,你可以开始了。
如何将月份添加到 chrono::system_clock::time_point 值?
谢谢!
概览
这是一个非常有趣的问题,有几个答案。 "correct" 答案是您必须根据具体应用决定的。
对于月份,您可以选择进行时间计算或日历计算。按时间顺序计算处理时间点和持续时间的规则单位,例如小时、分钟和秒。日历计算处理不规则日历,主要用于给日子起个好记的名字。
年代计算
如果问题是关于未来月份的一些物理过程,物理学不关心不同月份的长度不同,因此按时间顺序计算就足够了:
宝宝还有9个月预产期
6 个月后这里的天气会怎样?
为了对这些东西进行建模,按平均个月计算可能就足够了。可以创建一个 std::chrono::duration
具有 精确 平均公历(民用)月的长度。最简单的方法是定义一系列以 days
:
days
是 24 小时:
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
years
为 365.2425 days
,或 146097/400 days
:
using years = std::chrono::duration
<int, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;
最后months
是1/12 of years
:
using months = std::chrono::duration
<int, std::ratio_divide<years::period, std::ratio<12>>>;
现在您可以轻松计算从现在起的 8 个月:
auto t = system_clock::now() + months{8};
重要说明:此计算不会保留一天中的时间,甚至一个月中的某一天。
历法计算
也可以在保留一天中的时间和一个月中的第几天的同时添加月份。此类计算是 日历计算,而不是 时间计算。
选择日历后(例如公历(民用)日历、儒略历,或者可能是伊斯兰历、科普特历或埃塞俄比亚历——它们都有月份,但并非都是相同的月份),过程是:
将
system_clock::time_point
转换为日历。在日历系统中执行月份计算。
将新日历时间转换回
system_clock::time_point
。
您可以使用 Howard Hinnant's free, open-source date/time library 对一些日历执行此操作。这是民用日历的样子:
#include "date.h"
int
main()
{
using namespace date;
using namespace std::chrono;
// Get the current time
auto now = system_clock::now();
// Get a days-precision chrono::time_point
auto sd = floor<days>(now);
// Record the time of day
auto time_of_day = now - sd;
// Convert to a y/m/d calendar data structure
year_month_day ymd = sd;
// Add the months
ymd += months{8};
// Add some policy for overflowing the day-of-month if desired
if (!ymd.ok())
ymd = ymd.year()/ymd.month()/last;
// Convert back to system_clock::time_point
system_clock::time_point later = sys_days{ymd} + time_of_day;
}
为了笑我只是 运行 这个,并将它与 now + months{8}
比较并得到:
now is 2017-03-25 15:17:14.467080
later is 2017-11-25 15:17:14.467080 // calendrical computation
now + months{8} is 2017-11-24 03:10:02.467080 // chronological computation
这粗略地 "feel" 说明了日历计算与时间计算的不同之处。后者平均来说是完全准确的;它只是与日历有几天的偏差。有时更简单的(后一种)解决方案足够接近,有时则不然。只有你可以回答那个问题。
日历计算 — 现在有时区
最后,您可能希望在特定时区执行日历计算。之前的计算是 UTC。
Side note:
system_clock
is not specified to be UTC, but the de facto standard is that it is Unix Time which is a very close approximation to UTC.
您可以使用 Howard Hinnant's free, open-source timezone library to do this computation. This is an extension of the previously mentioned datetime library.
代码非常相似,你只需要从 UTC 转换为本地时间,然后转换为本地日历,进行计算然后返回本地时间,最后返回 system_clock::time_point
(UTC):
#include "tz.h"
int
main()
{
using namespace date;
using namespace std::chrono;
// Get the current local time
auto lt = make_zoned(current_zone(), system_clock::now());
// Get a days-precision chrono::time_point
auto ld = floor<days>(lt.get_local_time());
// Record the local time of day
auto time_of_day = lt.get_local_time() - ld;
// Convert to a y/m/d calendar data structure
year_month_day ymd{ld};
// Add the months
ymd += months{8};
// Add some policy for overflowing the day-of-month if desired
if (!ymd.ok())
ymd = ymd.year()/ymd.month()/last;
// Convert back to local time
lt = local_days{ymd} + time_of_day;
// Convert back to system_clock::time_point
auto later = lt.get_sys_time();
}
更新我们的结果我得到:
now is 2017-03-25 15:17:14.467080
later is 2017-11-25 15:17:14.467080 // calendrical: UTC
later is 2017-11-25 16:17:14.467080 // calendrical: America/New_York
now + months{8} is 2017-11-24 03:10:02.467080 // chronological computation
时间晚了一个小时(UTC),因为我保留了当地时间(上午 11:17),但计算以夏令时开始,以标准时间结束,因此 UTC 等效时间晚了 1 小时.
我使用 current_zone()
获取我当前的位置,但我也可以使用特定时区(例如 "Asia/Tokyo"
)。
C++20 更新
在我撰写此更新时,C++20 的技术工作已经停止,看起来我们将在今年晚些时候推出新的 C++ 标准(只剩下完成 C++20 的管理工作)。
此答案中的建议 t运行 适合 C++20:
对于时间顺序计算,
std::chrono::months
由<chrono>
提供,因此您不必自己计算。对于 UTC 日历计算,松开
#include "date.h"
并使用#include <chrono>
,然后删除using namespace date
,事情就会正常进行。对于时区敏感的日历计算,松开
#include "tz.h"
并使用#include <chrono>
,删除using namespace date
,并将make_zoned
替换为zoned_time
,你可以开始了。