【问题标题】:Calculating the date, given amount of days after a custom Epoc计算日期,自定义 Epoc 后的给定天数
【发布时间】:2015-11-12 14:09:27
【问题描述】:

我有一个自定义的 Epoc 日期,它不同于 STL 中的硬编码 Epoc。我想找出特定天数之后的新日期。

std::string ReturnDateTimeAsString(long double NumberOfDaysSinceEpoc)
{
    std::istringstream iss("1200-01-01.00:00:00");  // My custom Epoc
    std::tm Time;
    iss >> std::get_time(&Time, "%Y-%m-%d.%H:%M:%S");
    std::chrono::system_clock::time_point MyEpoc = std::chrono::system_clock::from_time_t(std::mktime(&Time));
    std::chrono::duration<long double, std::ratio<86400, 1>> Days(NumberOfDaysSinceEpoc);   // 86400: Seconds in a day
    std::chrono::system_clock::time_point DateTime = MyEpoc + Days; // I get the error here!
    std::time_t TimeType = std::chrono::system_clock::to_time_t(DateTime);
    return std::string(std::ctime(&TimeType));
}

函数参数可以是十进制。例如,如果我将4.25 传递给此函数,我想从中获取字符串"1200-01-05.06:00:00"(Epoc 后4 天6 小时)。

我在尝试添加 Epoc 和 Days 变量的行中收到以下错误消息。

Cannot convert from 'std::chrono::time_point<std::chrono::system_clock,std::chrono::duration<long double,std::ratio<0x01,0x0989680>>>'
to
'std::chrono::time_point<std::chrono::system_clock,std::chrono::system_clock::duration>'

No suitable user-defined conversion from
"std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long double, std::ratio<1i64, 10000000i64>>>"
to
"std::chrono::system_clock::time_point"

如何修复此代码?

【问题讨论】:

    标签: c++ datetime chrono


    【解决方案1】:

    忽略命名空间,MyEpoc 的类型为 system_clock::time_pointDays 的类型为 duration&lt;long double, ratio&lt;86400&gt;&gt;。这两种类型的总和将具有类型:

    time_point<system_clock, duration<long double, system_clock::period>>
    

    您正在尝试将该类型分配给:

    system_clock::time_point
    

    与以下内容相同:

    time_point<system_clock, system_clock::duration>
    

    system_clock::duration 被指定为某种有符号整数类型(通常为long long)。所以整个问题在于尝试将基于long doubletime_point 转换为基于整数的time_point。这可以通过time_point_cast 来完成:

    std::chrono::system_clock::time_point DateTime = 
      std::chrono::time_point_cast<std::chrono::system_clock::duration>(MyEpoc + Days);
    

    这是否使您的功能正确是另一回事。但这会让类型系统正常工作。


    使用这个date library,我可以很容易地看到,至少在我的系统上,你的时代不是你想要的:

    #include "date.h"
    
    std::string
    ReturnDateTimeAsString(long double NumberOfDaysSinceEpoc)
    {
        using namespace std;
        using namespace std::chrono;
    
        istringstream iss("1200-01-01.00:00:00");  // My custom Epoc
        tm Time;
        iss >> get_time(&Time, "%Y-%m-%d.%H:%M:%S");
        system_clock::time_point MyEpoc = system_clock::from_time_t(mktime(&Time));
        {
            using namespace date;
            std::cout << MyEpoc << '\n';
        }
        duration<long double, ratio<86400, 1>> Days(NumberOfDaysSinceEpoc);   // 86400: Seconds in a day
        system_clock::time_point DateTime = time_point_cast<system_clock::duration>(MyEpoc + Days); // I get the error here!
        time_t TimeType = system_clock::to_time_t(DateTime);
        return string(ctime(&TimeType));
    }
    

    这个时期的输出:

    1969-12-31 23:59:59.000000
    

    mtkime,至少在我的系统上,可能无效回 1200-01-01。

    事实证明,在我的系统上,此操作受到numeric_limits&lt;int32_t&gt;::min() 秒(-2'147'483'648s)的限制。 sys_days{1970_y/1/1} - 2'147'483'648s 是 1901-12-13 20:45:52。尝试将纪元设置得比这更早,我的系统 (OS X) 就会崩溃。

    使用这个date library,我已经简化了你的函数,并且它正在正确测试,假设你打算在UTC时区使用你的纪元(如果不是,很容易改变它):

    #include "date.h"
    
    using days_ld = std::chrono::duration<long double, std::ratio<86400>>;
    
    std::string
    ReturnDateTimeAsString(days_ld Days)
    {
        using namespace std;
        using namespace std::chrono;
        using namespace date;
    
        constexpr auto MyEpoc = sys_days{1200_y/1/1};
        auto DateTime = round<seconds>(MyEpoc + Days);
        ostringstream out;
        out << DateTime;
        return out.str();
    }
    
    int
    main()
    {
        std::cout << ReturnDateTimeAsString(days_ld{4.25}) << '\n';
    }
    

    这个输出:

    1200-01-05 06:00:00
    

    我冒昧地将您的long double 输入四舍五入到最接近的seconds。如果您想要更好的东西,比如milliseconds,这是一个简单的更改:

        auto DateTime = round<milliseconds>(MyEpoc + Days);
    

    将输出更改为:

    1200-01-05 06:00:00.000
    

    或者:

    auto DateTime = round<minutes>(MyEpoc + Days);
    

    将输出更改为:

    1200-01-05 06:00
    

    通过将函数的参数更改为所需的持续时间类型 (days_ld),您的函数现在使用起来更安全、更灵活。例如您的客户现在也可以输入std::chrono::hours

        using namespace std::chrono_literals;
        std::cout << ReturnDateTimeAsString(102h) << '\n';
    

    并获得相同的输出。

    如果您希望输出字符串采用其他格式,那也很容易。更多详细信息请参见以下链接:

    http://howardhinnant.github.io/date/date.html

    https://github.com/HowardHinnant/date/wiki

    【讨论】:

      猜你喜欢
      • 2020-09-28
      • 2018-05-11
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      • 2011-04-05
      • 2019-12-21
      • 2012-04-06
      • 1970-01-01
      相关资源
      最近更新 更多