C ++向chrono :: system_clock :: time_point添加月份 [英] C++ Add months to chrono::system_clock::time_point

查看:71
本文介绍了C ++向chrono :: system_clock :: time_point添加月份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何向chrono :: system_clock :: time_point值添加月份?

How can I add months to a chrono::system_clock::time_point value?

谢谢!

推荐答案

概述



这是一个非常有趣的问题,有多个答案。对于您的特定应用,必须确定正确的答案。

Overview

This is a very interesting question with several answers. The "correct" answer is something you must decide for your specific application.

有了几个月的时间,您可以选择进行按时间顺序计算日历计算。按时间顺序的计算处理时间点和持续时间的常规单位,例如小时,分钟和秒。日历计算处理不规则的日历,主要用于给人难忘的日子。

With months, you can choose to do either chronological computations or calendrical computations. A chronological computation deals with regular units of time points and time durations, such as hours, minutes and seconds. A calendrical computation deals with irregular calendars that mainly serve to give days memorable names.

如果问题是关于未来几个月的物理过程,物理学不在乎不同的月份有不同的长度,因此按时间顺序计算就足够了:

If the question is about some physical process months in the future, physics doesn't care that different months have different lengths, and so a chronological computation is sufficient:


  • 婴儿要在9个月内到期。

  • The baby is due in 9 months.

从现在开始的6个月后这里的天气如何?

What will the weather be like here 6 months from now?

为了对这些事物建模,以平均月为单位进行工作可能就足够了。可以创建一个 std :: chrono :: duration ,它具有精确的平均公历月长度。最简单的方法是定义一系列以开始的持续时间:

In order to model these things, it may be sufficient to work in terms of the average month. One can create a std::chrono::duration that has precisely the length of an average Gregorian (civil) month. It is easiest to do this by defining a series of durations starting with days:

是24小时:

using days = std::chrono::duration
    <int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;

是365.2425 ,或 146097 / 400

years is 365.2425 days, or 146097/400 days:

using years = std::chrono::duration
    <int, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;

最后个月 1 / 12 of

And finally months is 1/12 of years:

using months = std::chrono::duration
    <int, std::ratio_divide<years::period, std::ratio<12>>>;

现在您可以轻松计算从现在开始的8个月:

Now you can easily compute 8 months from now:

auto t = system_clock::now() + months{8};

重要说明:此计算没有保留一天中的某个时间,甚至是一个月中的某天。

Important note: This computation does not preserve the time of day, or even the day of the month.

可以在保留一天中的时间一天中的一天的同时添加月份。这样的计算是日历计算,而不是年代计算

It is also possible to add months while preserving time of day and day of month. Such computations are calendrical computations as opposed to chronological computations.

选择日历后(例如公历(民用日历,儒略历或伊斯兰,科普特或埃塞俄比亚历-都具有几个月的时间,但并非都相同),流程为:

After choosing a calendar (such as the Gregorian (civil) calendar, the Julian calendar, or perhaps the Islamic, Coptic or Ethiopic calendars — they all have months, but they are not all the same months), the process is:


  1. system_clock :: time_point 转换为日历。

在日历系统中执行月份计算。

Perform the months computation in the calendrical system.

将新的日历时间转换回 system_clock :: time_point

Convert the new calendar time back into system_clock::time_point.

您可以使用霍华德·辛南特(Howard Hinnant)的免费开放源日期/时间库,可用于一些日历。这是民用日历的样子:

You can use Howard Hinnant's free, open-source date/time library to do this for a few calendars. Here is what it looks like for the civil calendar:

#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;
}

对于咧嘴笑,我只是运行它,并将其与现在+个月{8} 并得到:

For grins I just ran this, and compared it with now + months{8} and got:

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

对于日历计算与时间计算的区别,这给出了一个粗略的感觉。后者平均而言非常准确;它仅与日历相差几天。有时,更简单(较晚)的解决方案是足够接近,有时却没有。只有可以回答那个问题。

This gives a rough "feel" for how the calendrical computation differs from the chronological computation. The latter is perfectly accurate on average; it just has a deviation from the calendrical on the order of a few days. And sometimes the simpler (latter) solution is close enough, and sometimes it is not. Only you can answer that question.

日历计算—现在有了时区

最后,您可能希望在特定时区执行日历计算。以前的计算是UTC。

Finally, you might want to perform your calendrical computation in a specific timezone. The previous computation was UTC.


侧面说明: system_clock 未指定为UTC,但事实上的标准是它是 Unix时间,它非常接近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)的免费开放源时区库来进行此计算。这是前面提到的日期时间库的扩展。

You can use 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):

The code is very similar, you just need to convert to local time from UTC, then to a local calendar, do the computation then back to local time, and finally back to 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个小时。

The time is an hour later (UTC) because I preserved the local time (11:17am) but the computation started in daylight saving time, and ended in standard time, and so the UTC equivalent is later by 1 hour.

我使用了 current_zone()可以选择我的当前位置,但是我也可以使用特定时区(例如亚洲/东京 )。

I used current_zone() to pick up my current location, but I could have also used a specific time zone (e.g. "Asia/Tokyo").

在我撰写此更新时,C ++ 20的技术工作已停止,并且看起来我们将今年晚些时候将发布新的C ++标准(仅剩下要做的管理工作) o完整的C ++ 20)。

As I write this update, technical work has ceased on C++20, and it looks like we will have a new C++ standard later this year (just administrative work left to do to complete C++20).

此答案中的建议很好地转换为C ++ 20:

The advice in this answer translates well to C++20:


  1. 对于时间顺序计算, std :: chrono :: months < chrono> ,因此您不必自己计算。

  1. For the chronological computation, std::chrono::months is supplied by <chrono> so you don't have to compute it yourself.

对于UTC日历计算,请松散 #include date.h 并改为使用 #include< chrono> ,并使用命名空间日期 $ c>,事情就可以使用。

For the UTC calendrical computation, loose #include "date.h" and use instead #include <chrono>, and drop using namespace date, and things will just work.

对于时区敏感的日历计算,请松散 #include tz.h 并改用 #include< chrono> ,使用命名空间日期删除 并替换 make_zoned zoned_time ,您一切顺利。

For the time zone sensitive calendrical computation, loose #include "tz.h" and use instead #include <chrono>, drop using namespace date, and replace make_zoned with zoned_time, and you're good to go.

这篇关于C ++向chrono :: system_clock :: time_point添加月份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆