提升 local_date_time 数学错误?
Posted
技术标签:
【中文标题】提升 local_date_time 数学错误?【英文标题】:boost local_date_time math wrong? 【发布时间】:2010-02-11 15:26:34 【问题描述】:我在我的项目中使用Boost's datetime library。当我发现它具有小时、天、月、年等的持续时间类型时,我感到非常高兴,并且它们会根据您添加的内容来更改它们的值(即在日期的月份部分增加 1 个月,它不只是增加 30 天或类似的时间)。我认为这个属性是为 days 类型保留的,但我决定在将其投入生产之前对其进行测试......
local_date_time t1(date(2010, 3, 14), hours(1), easternTime, false); // 1am on DST transition date
CPPUNIT_ASSERT_EQUAL(greg_year(2010), t1.local_time().date().year());
CPPUNIT_ASSERT_EQUAL(greg_month(3), t1.local_time().date().month());
CPPUNIT_ASSERT_EQUAL(greg_day(14), t1.local_time().date().day());
CPPUNIT_ASSERT_EQUAL(1L, t1.local_time().time_of_day().hours());
CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().minutes());
CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().seconds());
t1 += days(1); // the time in EST should now be 1am on the 15th
CPPUNIT_ASSERT_EQUAL(greg_year(2010), t1.local_time().date().year());
CPPUNIT_ASSERT_EQUAL(greg_month(3), t1.local_time().date().month());
CPPUNIT_ASSERT_EQUAL(greg_day(15), t1.local_time().date().day());
CPPUNIT_ASSERT_EQUAL(1L, t1.local_time().time_of_day().hours()); // fails, returns 2
CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().minutes());
CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().seconds());
您将在上方看到我的 CPPUNIT 单元测试。它在指示的行以 2 失败,如果 days() 仅添加 24 小时而不是 1 个逻辑天(因为 DST 转换导致 2010-03-14 在 EST 中为 23 小时),这是我所期望的。
我做错了吗?这是一个错误吗?我是不是完全误解了图书馆在这种数学方面的设计目标?
【问题讨论】:
这是一个很好的例子,说明了为什么我们都应该编写测试工具代码 - 将预期值与实际值进行比较 【参考方案1】:我认为问题在于提问者对一天是什么的概念。他希望这里是一个“约会”日,而不是 24 小时,但这不是一个合理的要求。
如果在当地时间工作,一定会遇到奇特的效果。例如,如果在将时钟从凌晨 1 点提前到凌晨 2 点的时区,如果您的本地时间“添加日期日期”计算应将(不存在)设置为相关周日早上的凌晨 1.30,您预计会发生什么?
时间计算得到向前推进 24 小时 - 它必须在基础 UTC 时间上运行。
要按照所述进行“跳转一天”计算,请使用 Boost 的日期类型,并且只添加一天中的时间作为最终操作。
能够提前一个月的业务是完全不同的,因为与一天不同,日历月作为持续时间没有特定含义。它也带来了麻烦:如果你从 1 月 31 日开始提前一个日历月,然后再返回一个日历月,你最终会得到什么日期?
【讨论】:
对此表示赞同。 OP 的核心问题是,当不存在这样的事情时,他期望本地时间的数学稳定。 OP 关于 30 天月份的评论很有趣,因为有各种金融领域明确使用 30/360 或变体来简化某些事情。 Boost 的 Month 和 Year 类型的行为与我描述的一样,并解决了 willw 和 sdg 正在谈论的问题:boost.org/doc/libs/1_40_0/doc/html/date_time/…。我只是期望日型相同。时间计算不必在 UTC 时间上进行......虽然这就是它提供 ptime(对于 UTC)和 local_date_time(对于本地时间)计算的原因。这并不意味着您错了,但在您将自己的误解与 Boost 文档相提并论之前,我不会接受您的回答。 Boost 的 Month 和 Year 类型,引用文档来说,是天跨度的逻辑表示——它们与 gregorian::date 类型相关联。在您的示例中,您的类型是 local_date_time。从语义上讲,您是在声明对时间的连续流动感兴趣,而不是一天一次的日期粒度。因此,当您将一天添加到日期时间变量时,它会从日期持续时间转换为持续时间 - 从 1 天转换为 24 小时。其他一切都由此而来。很抱歉,但我认为误解是你的,以及 WAD 的课程。【参考方案2】:您应该创建一个 boost::posix_time::time_duration 对象并将其添加到本地时间,而不是添加 date_duration 对象,如下所示: boost::posix_time::time_duration td ( 24 , 0 , 0 , 0 ) ; //24小时,0分,秒,纳米 boost::local_time::local_date_time 稍后 = 现在 + td ; //假设现在是你的开始 //local_date_time , 2010-3-14 //稍后现在将是一个完全考虑 DST 的本地 date_time 对象!
【讨论】:
这并不能解决 OP 的问题。将t1 += days(1);
替换为 t1 += time_duration(24, 0, 0, 0);
会得到相同的结果。以上是关于提升 local_date_time 数学错误?的主要内容,如果未能解决你的问题,请参考以下文章