c++使用date. h添加年和日

nbnkbykc  于 2023-01-18  发布在  其他
关注(0)|答案(3)|浏览(200)

使用date.h和std::chrono处理日历持续时间算法,但得到意外结果。
示例代码为:

#include "date.h"

#include <string>
#include <chrono>
#include <iostream>

int main() {
    date::sys_seconds calendarDate = {};
    calendarDate = std::chrono::years(30) + date::sys_seconds(std::chrono::days(10));
    std::string stringDate = date::format("%Y-%m-%d %H:%M:%S", calendarDate);
    std::cout << "{} + 30 years + 10 days = " << stringDate << "\n";
    return 0;
}

实际产量:{} +30年+10天= 2000年1月11日06时36分
预期输出:{} +30年+10天= 2000年1月11日00:00:00
使用Ubuntu 22.04;g++ 11.3.0
编制单位:gcc -g -标准品=c++20主要成分cpp-最低标准品dc ++
从此处使用date. h:https://raw.githubusercontent.com/HowardHinnant/date/master/include/date/date.h
你对额外的6小时36分钟增加了什么有什么见解吗?

v9tzhpje

v9tzhpje1#

这是因为闰年的缘故。
在定义std::chrono::years时考虑了这一点,将其定义为duration type with Period std::ratio<31556952>(60 * 60 * 24 * 365.2425 = 31556952)。
但是,如果将此值与一年的非闰年持续时间(60 * 60 * 24 * 365 = 31536000)进行比较,则会得到20952秒或5小时49分12秒的差值。如果将该差值乘以30,则会得到:
7天6小时36分零秒--而且至少后面的部分你应该看起来很熟悉。
但是那7天呢?事实证明在1970年到2000年之间:1972年、1976年、1980年、1984年、1988年、1992年和1996年是闰年--如果你算上闰年,那就是7年,这就是日子的流逝。
您可以通过更改代码并查看输出来检查这一点:
calendarDate += std::chrono::seconds(60 * 60 * 24 * 365 * 30);-“1999年12月25日00:00:00”
calendarDate += std::chrono::seconds(60 * 60 * 24 * 365 * 30) + day(7);-“2000年1月1日00:00:00”
顺便说一下,问题是std::chrono::years提供的是一个 * 平均 * 年的长度,而date.h库知道(并关心)具体的年份:它知道1970年不是闰年(60 * 60 * 24 * 365 = 31536000秒),但1972年是闰年(60 * 60 * 24 * 366 = 31622400秒)。
如果你增加了31年,那么你会从平均年增加5:49:12的偏差,但然后删除1天,因为2000年也是闰年-所以它将打印的时间仍然是2000年,但大约12小时前的新年2001年。

0aydgbwb

0aydgbwb2#

除了Frodyne's good answer(我投了赞成票),我想补充的是,您可以使用date.h执行 chronological 算术或 calendrical 算术。
您已经完成了 chronological 运算,其中years被认为是一个统一的单位,等于平均民用年。
日历算术遵循日历的不规则性,这也是你所期望的。下面是你将如何实现这一点:

#include "date/date.h"

#include <string>
#include <chrono>
#include <iostream>

int main() {
    auto chronologicalDateTime = date::sys_seconds(date::days(10));
    auto chronologicalDate     = date::floor<date::days>( chronologicalDateTime);
    date::year_month_day calendarDate =  chronologicalDate;
    auto timeOfDay =  chronologicalDateTime -  chronologicalDate;
    calendarDate += date::years{30};
    chronologicalDateTime = date::sys_days{calendarDate} + timeOfDay;

    std::string stringDate = date::format("%Y-%m-%d %H:%M:%S",  chronologicalDateTime);
    std::cout << "{} + 30 years + 10 days = " << stringDate << "\n";
    return 0;
}

首先将时间转换为日历日期,并将years添加到日历日期中,然后再将其转换回时间。

{} + 30 years + 10 days = 2000-01-11 00:00:00

下面是另一个SO答案,它遵循了同样的原则,只是使用了月份:https://stackoverflow.com/a/43018120/576911

vmdwslir

vmdwslir3#

Linux将日期存储为UTC。我猜您的机器位于中央时区(CT),距离UTC +6小时。

相关问题