两个日期之间的天数C++

Bre*_*own 18 c++ date date-arithmetic

我看到了C#,Java的例子,但是对于C++我找不到解决方案来计算两个日期之间的天数.

例如2012-01-24和2013-01-08之间

谢谢!

sha*_*fri 20

这是一种方式.

#include <iostream>
#include <ctime>

int main()
{
    struct std::tm a = {0,0,0,24,5,104}; /* June 24, 2004 */
    struct std::tm b = {0,0,0,5,6,104}; /* July 5, 2004 */
    std::time_t x = std::mktime(&a);
    std::time_t y = std::mktime(&b);
    if ( x != (std::time_t)(-1) && y != (std::time_t)(-1) )
    {
        double difference = std::difftime(y, x) / (60 * 60 * 24);
        std::cout << std::ctime(&x);
        std::cout << std::ctime(&y);
        std::cout << "difference = " << difference << " days" << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的输出

Thu Jun 24 01:00:00 2004
Mon Jul 05 01:00:00 2004
difference = 11 days
Run Code Online (Sandbox Code Playgroud)

这是一篇原作者帖子的参考

  • 你还应该强调它不起作用.如果日期跨越夏季和冬季之间的变化日期,则可能会得到不一致的结果.(当时使用`12:0:0`,_not_`0:0:0`.)当然,没有指定`struct tm`中元素的顺序; 你需要像`std :: tm a; a.tm_year = 104; a.tm_mon = 5; a.tm_mday = 24; a.tm_hour = 12;`. (6认同)
  • 此方法没有考虑夏令时变化、闰秒或公历中的漏洞。只要您始终考虑每天的午夜并四舍五入到最接近的天数,前两个陷阱就不会伤害您。只要您不使用跨越漏洞的日期范围(1582 年之后的任何时间都是安全的),第三个陷阱也不会让您陷入困境。 (2认同)

cha*_*sen 16

将日期转换为整数,表示自纪元以来的天数,然后减去.在这个例子中,我选择了Rata Die,该算法的解释可以在< http://mysite.verizon.net/aesir_research/date/rata.htm > 找到.

int
rdn(int y, int m, int d) { /* Rata Die day one is 0001-01-01 */
    if (m < 3)
        y--, m += 12;
    return 365*y + y/4 - y/100 + y/400 + (153*m - 457)/5 + d - 306;
}

int days = rdn(2013, 1, 8) - rdn(2012, 1, 24);
Run Code Online (Sandbox Code Playgroud)

  • 它使代码简单并且正常工作. (2认同)

How*_*ant 12

旧问题的新答案:

使用此C++ 11/C++ 14仅限标头的日期库,您现在可以编写:

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

int
main()
{
    using namespace date;
    using namespace std;
    auto x = 2012_y/1/24;
    auto y = 2013_y/1/8;
    cout << x << '\n';
    cout << y << '\n';
    cout << "difference = " << (sys_days{y} - sys_days{x}).count() << " days\n";
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

2012-01-24
2013-01-08
difference = 350 days
Run Code Online (Sandbox Code Playgroud)

如果您不想依赖此库,则可以使用上述日期库使用的相同日期算法编写自己的库.它们在本文中找到:时间兼容的低级数据算法.本例中正在运用的算法是这样的:

// Returns number of days since civil 1970-01-01.  Negative values indicate
//    days prior to 1970-01-01.
// Preconditions:  y-m-d represents a date in the civil (Gregorian) calendar
//                 m is in [1, 12]
//                 d is in [1, last_day_of_month(y, m)]
//                 y is "approximately" in
//                   [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
//                 Exact range of validity is:
//                 [civil_from_days(numeric_limits<Int>::min()),
//                  civil_from_days(numeric_limits<Int>::max()-719468)]
template <class Int>
constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
    static_assert(std::numeric_limits<unsigned>::digits >= 18,
             "This algorithm has not been ported to a 16 bit unsigned integer");
    static_assert(std::numeric_limits<Int>::digits >= 20,
             "This algorithm has not been ported to a 16 bit signed integer");
    y -= m <= 2;
    const Int era = (y >= 0 ? y : y-399) / 400;
    const unsigned yoe = static_cast<unsigned>(y - era * 400);      // [0, 399]
    const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
    const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
    return era * 146097 + static_cast<Int>(doe) - 719468;
}
Run Code Online (Sandbox Code Playgroud)

有关此算法的工作原理,单元测试及其有效范围的详细信息,请参阅时间兼容的低级别日期算法.

该算法模拟了公历格里高利历,它无限地向前和向后延伸格里高利历.要为其他日历(例如Julian日历)建模,您将需要其他算法,例如此处显示的算法.一旦你设置了其他日历,并同步到相同的串行纪元(这些算法使用1970-01-01格里高利,这也是Unix时间纪元),你可以轻松计算不仅在任何两个日期之间的天数,但也在你建模的任何两个日历之间.

这使您可以自由地在从Julian到Gregorian的转换日期中进行硬编码.您只需要知道引用输入数据的日历.

有时,历史文档中可能含糊不清的日期将使用旧样式/新样式进行注释,以分别指示Julian或Gregorian日历.

如果你也关心天与您的日期时间,这同日库无缝集成的<chrono>使用的图书馆hours,minutes,seconds,milliseconds,microsecondsnanoseconds,并与system_clock::now()获得的当前日期和时间.

如果您担心时区,则会在日期库之上编写一个附加(单独)时区库,以使用IANA时区数据库处理时区.如果需要,时区库还具有包含闰秒的计算工具.


小智 6

你可以试试boost date_time