【问题标题】:Adding over 30 days to 1900-01-01添加超过 30 天到 1900-01-01
【发布时间】:2021-11-01 19:24:02
【问题描述】:

如何在 C++ 中将超过 30 天的时间添加到大约 1900-01-01 日期。超过 1000 天,然后在添加后格式化 time_t 以获得完整的日期。

这是我迄今为止尝试过的:

int tmp = 1000;
struct std::tm tm;
std::istringstream ss("1900-01-01");
ss >> std::get_time(&tm, "%Y-%m-%d");
tm.tm_mday = tm.tm_mday + tmp;
return mktime(&tm);

【问题讨论】:

  • 您可以使用Julian day
  • 您能更具体地说明您想要做什么吗?因为这个问题我现在看了好几遍了,还是没看懂。
  • 好的,我已经分享了我的第一次尝试
  • 一开始你讲了time_t,它是一个数字类型,你可以加上days * 86400。这是C。你用的是C++,然后用std::chrono::days或者std:: chrono::duration> C++20 之前的版本。

标签: c++ visual-c++


【解决方案1】:

如果您使用的是最新的 Visual Studio 2019,那么您有 C++20 <chrono> 可以解决此问题,而不会出现与 Ted Lyngmo's answser 中演示的 mktime/localtime 技术相关的错误。

#include <chrono>
#include <iostream>
#include <sstream>

int
main()
{
    // Hold the amount to add in the type std::chrono::days (a chrono duration)
    std::chrono::days days{1000};
    // std::chrono::sys_days is a Unix Time chrono::time_point with precision days
    std::chrono::sys_days tp;
    std::istringstream ss("1900-01-01");

    if(ss >> std::chrono::parse("%F", tp)) {
        // No need to involve time zones.
        // Just add and print out
        std::cout << tp + days << '\n';  // 1902-09-28
    }
}

该程序具有与Ted's answser 相同的行为和输出。但是,如果不需要从流中读取“常量”1900-01-01,那么我们可以做得更好。 C++20 可以使 1900-01-01 成为编译时常量:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono_literals;
    std::chrono::days days{1000};
    constexpr std::chrono::sys_days tp = 1900y/01/01;  // Compile-time date literal
    // Just add and print out
    std::cout << tp + days << '\n';  // 1902-09-28
}

这些解决方案根本不涉及时区。它只是在日期上添加天数。简单性有助于提高代码效率,并减少与复杂性增加相关的错误机会。

如果您没有最新的 Visual Studio 2019,或者无法访问 C++20,则可以使用 Joseph's answer 中提到的 Howard's free, open-source, header-only "date.h" C++20 chrono preview library,其语法几乎相同。

#include "date/date.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date::literals;
    date::days days{1000};
    constexpr date::sys_days tp = 1900_y/01/01;  // Compile-time date literal
    // Just add and print out
    using date::operator<<;
    std::cout << tp + days << '\n';  // 1902-09-28
}
  • C++20 chrono 新增功能位于 namespace date 而不是 namespace std::chrono
  • year 文字拼写为 _y 而不是 y
  • time_point 流操作符不会被 ADL 找到,必须在 namespace date 中手动公开。

【讨论】:

    【解决方案2】:

    除了Joseph Larson 非常好的建议查看 日期/时间库以供使用之外,我将展示如何进一步利用你当前的想法。

    你现在在std::chrono 也有很多支持,所以也阅读一下。

    您尝试将错误域中的日期添加到std::tm。相反,将 std::tm 转换为 time_t 并将日期添加到其中 - 然后将结果转换回 std::tm

    例子:

    #include <ctime>
    #include <iomanip>
    #include <iostream>
    #include <sstream>
    
    int main() {
        int days = 1000;
    
        std::tm tm{};
        std::istringstream ss("1900-01-01");
    
        if(ss >> std::get_time(&tm, "%Y-%m-%d")) {
            tm.tm_isdst = -1; // let mktime "guess" if DST is effect
    
            // convert to time_t and add 1000 days. 1 day = 24*60*60 seconds
            std::time_t result = std::mktime(&tm) + days * 60*60*24;
     
            // back to std::tm
            tm = *std::localtime(&result);
    
            // print result
            std::cout << std::put_time(&tm, "%Y-%m-%d") << '\n';
        }
    }
    

    注意:这种技术有时会得到错误的答案。如果对于计算机的本地时区,UTC 偏移量在 1900-01-01 大于它在 1900-01-01 + 天,那么结果将比它应该的少一天。这发生在(例如)IANA 时区美国/安克雷奇,天数 == 232。它再次发生在非洲/开罗,天数 == 273。

    显然,更好的选择是使用 chrono 或 Howard Hinnant 的 date 库中的设施作为 demonstrated by Howard

    【讨论】:

    • 这种技术有时会得到错误的答案。如果对于计算机的本地时区,UTC 偏移量在 1900-01-01 大于它在 1900-01-01 + 天,那么结果将比它应该的少一天。这发生在(例如)IANA 时区美国/安克雷奇,天数 == 232。它再次发生在非洲/开罗,天数 == 273。
    • @HowardHinnant Oups。这是可以挽救的(没有太多的模糊)还是我应该建议 OP 不接受以便我可以删除答案?
    • 我还没有想出一个办法来挽救它,而且诚然没有投入太多时间。我以前见过这种技术,但今天是我第一次测试它,并意识到它可能会出错。为了证明偷偷摸摸的缺陷,您的答案可能更有价值,而不是删除。而且我也不知道问题结束后还能做多少。
    • @HowardHinnant 好点,感谢您查看。我将您的谨慎添加到答案中,并保留它。
    【解决方案3】:

    C++ 中的日期/时间处理既尴尬又尴尬。 Howard Hinnant 有一个很棒的图书馆,您可能想看看:

    https://github.com/HowardHinnant/date

    问题很复杂。如果您使用本地日期,由于夏令时和闰秒,您无法添加固定的时间量。您可以使用 GMT,但仍会受到闰秒的影响。

    但霍华德的图书馆让您更容易做到这一点。我来看看。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 1970-01-01
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多