【问题标题】:year duration algorithm in c++C ++中的年持续时间算法
【发布时间】:2012-06-08 08:04:27
【问题描述】:

我正在制作一个需要一年持续时间(time_t)的程序。

在其他方面,time_t of DD/MM/YYYY + 持续时间 = time_t of DD/MM/YYYY+1

因此它可能并不总是 365 天(29/02/2012 将变为 28/02/2013)

这是我自带的算法:

if YEAR is leap than
    if we are before the 29th feb' than return 365+1 days
    else if we are the 29th feb' than return 365-1 days
    else return 365 days
else if YEAR+1 is leap than
    if we are before or the 28th feb' than return 365 days
    else return 365+1 days
else return 365 days

在这里,一天是 60 * 60 * 24 秒

这个算法似乎有效。但我想知道是否有另一种方法可以在没有所有这些条件且只有 2 个可能的返回值的情况下执行此操作,或者只是一些“技巧”来优化事情。

我试图像这样从struct tm 增加tm_year

// t is the input time_t
struct tm Tm (*localtime(&t));
if (Tm.tm_mon == 2 && Tm.tm_mday == 29) --Tm.tm_mday;
++Tm.tm_year;
return mktime(&Tm) - t;

但结果不是我想要的,我得到了 -1 小时,或者 -25...

我猜是因为一年不完全是 365 * 24 * 60 * 60。

【问题讨论】:

  • 闰秒将天的长度改变了 1 秒,但这并不能解释 3600 秒。

标签: c++ algorithm duration


【解决方案1】:

我会为此使用Boost,因为它已经实现了您正在寻找的内容:

#include <iostream>
#include <boost/date_time/gregorian/gregorian_types.hpp>
namespace date = boost::gregorian;

int main() {
   date::date_period dp(date::date(2012, 6, 4), date::date(2013, 6, 4));
   long days = dp.length().days();
   std::cout << "Days between dates: " << days << std::endl;

}

如果您想要更精确,那么您也可以使用来自 Boost 的posix_time

namespace ptime = boost::posix_time;

...

ptime::ptime t1(date::date(2012, 6, 4), ptime::hours(0));
ptime::ptime t2(date::date(2013, 6, 4), ptime::hours(0));

ptime::time_duration td = t2 - t1;
std::cout << "Milliseconds: " << td.total_milliseconds() << std::endl;

通常time_t 以秒为单位。因此,您只需调用td.total_seconds() 即可获取您要查找的值。

【讨论】:

  • Boost 将是一个不错的选择,但我不确定我是否会为了一个功能而包含这个相当大的库......
  • @perelo 向您的项目添加新的依赖项是您必须仔细考虑的事情。话虽这么说,但不知何故,我已经将 Boost 视为 C++ 的一部分,因为它确实简化了 C++ 中的许多编程。此外,如果您在 Linux 中编程并且不需要 to_string/from_string 函数,那么 boost::date_time 只是一个头文件库(即,您不需要将您的程序与 Boost 链接,只需包含一些头文件)。
  • @perelo 实际上,它也是 Windows 中的仅头文件依赖项(除非您使用 Visual C++ 6.x 或 Borland 编译器)。更多信息here.
  • @perelo 您可以查看this question,了解使用 Boost 的优缺点。
  • 谢谢你是对的,boost/date_time 只包含 .hpp 文件,所以我可以包含它们 :)
【解决方案2】:
if YEAR is leap than
    if we are before the 29th feb' than return 365+1 days
    else if we are the 29th feb' than return 365-1 days
    else return 365 days
else if YEAR+1 is leap than
    if we are before or the 28th feb' than return 365 days
    else return 365+1 days
else return 365 days

简化为:

if (YEAR is leap)
    if (< 29th Feb) return 365+1
    if (= 29th Feb) return 365-1
else if (YEAR+1 is leap)
    if (> 29th Feb) return 365+1

return 365

但是你为什么要这样做呢?拥有可读的代码比“技巧”优化要好得多。

正如@betabandido 所建议的那样,date(year+1, mon, day) - date(year, mon, day) 之类的东西会更简单、更易读,并且能够处理闰年、闰秒和September missing 11 days

【讨论】:

  • 是的,但使用 struct tm 效果不佳,虽然我正在测试 boost atm
【解决方案3】:

一个太阳年的长度不是一个固定的数字。 Gregorian calendar 发明了一种不完全精确的闰年补偿方法。这就是“如果一年能被 4 整除,则为闰年,除非它能被 100 整除,但如果能被 400 整除,则又是闰年。

我们在伊朗有一个more precise calendar,其中岁月改变了第二个地球围绕太阳转了一圈。在同一链接中,您可以看到平均太阳年为 365.2422 天,春分之间的平均间隔为 365.2424 天。

this link 以秒为单位提供了有关太阳年(热带年)长度的更多详细信息。

【讨论】:

  • 是的,我知道一年比 365 天多一点,但我实际上并不想找到绕太阳运行的地球轨道的秒数的绝对值,感谢您的精确度不过。
  • @perelo,你到底想要什么?一年有多少“天”?好吧,如果闰年是 366,如果不是闰年,那就是 365。您无需检查今天是否是 2 月 29 日!
  • 我需要得到今天和一年后同一日期之间的秒数,所以可能不是一整年
  • @Perelo,我明白了。您的mktime 解决方案应该有效,您确定您的测试是否正确?它没有意义返回过去的时间,增加了年份!
  • 似乎当我将 struct tm 初始化为 2 月 29 日之前的日期时,mktime 减去了一个小时!
猜你喜欢
  • 2018-04-25
  • 1970-01-01
  • 2012-11-04
  • 2018-05-06
  • 1970-01-01
  • 2016-09-10
  • 2022-11-17
  • 2011-07-30
  • 1970-01-01
相关资源
最近更新 更多