草庐IT

c++ - C++向chrono::system_clock::time_point添加月份

coder 2024-02-17 原文

如何将chrono::system_clock::time_point值加数月?

谢谢!

最佳答案

概述

这是一个非常有趣的问题,有几个答案。 “正确”的答案是您必须针对特定应用程序决定的。

使用月份,您可以选择按时间顺序进行计算或进行日历计算。按时间顺序的计算处理时间点和持续时间的常规单位,例如小时,分钟和秒。日历计算处理不规则的日历,该日历主要用来给日子起令人难忘的名字。

年表计算

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

  • 婴儿要在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>>;
    

    最后monthsyears的1/12:
    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
    

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

    日历计算-现在带有时区

    最后,您可能希望在特定时区执行日历计算。以前的计算是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进行此计算。这是前面提到的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
    

    因为我保留了本地时间(上午11:17),所以时间是一个小时之后(UTC),但是计算是从夏时制开始的,并在标准时间结束,因此UTC等效时间晚了1个小时。

    我使用current_zone()来获取当前位置,但是我也可以使用特定的时区(例如"Asia/Tokyo")。

    C++ 20更新

    在我撰写此更新时,C++ 20的技术工作已经停止,并且看起来我们将在今年晚些时候制定新的C++标准(仅剩下要做的行政工作来完成C++ 20)。

    此答案中的建议可以很好地转换为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,您可以开始使用。
  • 关于c++ - C++向chrono::system_clock::time_point添加月份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43010362/

    有关c++ - C++向chrono::system_clock::time_point添加月份的更多相关文章

    1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

      当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

    2. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

      我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

    3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

      我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

    5. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

      当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

    6. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

      我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

    7. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

      我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

    8. ruby - 我如何添加二进制数据来遏制 POST - 2

      我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

    9. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    10. ruby-on-rails - 在 Ruby on Rails 中添加 boolean 列值 - 2

      我正在开发一个创建网络博客的RubyonRails项目。我希望将一个名为featured的boolean数据库字段添加到Post模型中。该字段应该可以通过我添加的事件管理界面进行编辑。我使用了以下代码,但我什至没有在网站上显示另一列。$railsgeneratemigrationaddFeaturedfeatured:boolean$rakedb:migrate我是RubyonRails的新手,非常感谢任何帮助。我的index.html.erb文件中的相关代码(views):FeaturedPost架构.rb:ActiveRecord::Schema.define(:version=>

    随机推荐