C++ 给定日期和今天日期之间的天数

3
我有一个名为int differenceDatesInDays(string& date)的函数。这个函数应该接收一个日期字符串(YYYY-MM-DD)并与今天的日期进行比较。
我不知道STL中是否已经有类似的算法,我找不到匹配的算法。我只发现boost有一个解决方案,但我不想使用boost。
所以,这是我的代码:
int differenceDatesInDays(string& date) {
    string year = date.substr(0, 4);
    string month = date.substr(5,2);
    string day = date.substr(8, string::npos);

    int y = stoi(year);
    int m = stoi(month);
    int d = stoi(day);

    time_t time_now = time(0);
    tm* now = localtime(&time_now);

    int diffY = y - (now->tm_year + 1900);
    int diffM = m - (now->tm_mon + 1);
    int diffD = d - (now->tm_mday);

    int difference = (diffY * 365) + (diffM * 30) + diffD;

    return difference;
}

我不知道如何判断一个月有30天、31天还是28天。


只有12个月,因此您可以设置一个包含每个月天数的常量数组。按月份索引它。对于通常有28天的二月份,您将不得不确定它是否是闰年,如果是,则有29天。 - Anon Mail
3个回答

7

如果你有两个整数三元组:{y1,m1,d1}{y0,m0,d0},计算它们之间的差异最有效的方法是使用公共领域函数days_from_civil来计算每个三元组的序列日计数,并将它们相减:

diff = days_from_civil(y1, m1, d1) - days_from_civil(y0, m0, d0);

这里是days_from_civil的重复部分:

// 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;
}

这将比您通常基于tm的代码具有更广泛的有效性,并且速度更快。您不必强制处理一天中的时间。如果所有信息都是编译时常量,并且您使用的是C++14,则可以在编译时获取答案。

哈哈哈。这完全是小菜一碟 :) 我喜欢它。当我不能使用“标准”库实现时,我会用到它的。 - sehe
@Walter一直在为标准库和其他地方编写日期/时间操作库。他链接到了最初为此编写的“库” :) 出于这个原因,您可以相信这段代码! - sehe
@sehe 我知道,但他仍然上瘾(你也是;) - Walter
1
回复:琐碎的事情:将一个序列计数映射到y/m/d三元组的方式要复杂得多。许多实现将在其解决方案中进行迭代。但是civil_from_days不会。 - Howard Hinnant
顺便说一下,在同一个时代中,每个月的第13天更容易是星期五,而不是其他工作日。 - Walter
显示剩余4条评论

4

既然您使用了Boost标签,为什么不利用它并免费获取所有的东西:

Live On Coliru

#include <boost/date_time/gregorian/gregorian.hpp>

int differenceDatesInDays(std::string const& s) {
    using namespace boost::gregorian;
    return (day_clock::local_day() - from_string(s)).days();
}

int main() {
    return differenceDatesInDays("2015-01-01");
}

打印

317

这比被接受的答案更有用;遗憾的是,楼主不想使用boost(尽管有标签)。 - Walter

2

可能是以下类似的内容:

int differenceDatesInDays(string& date) {
    // Parse `date` as in your code
    int y = ...;
    int m = ...;
    int d = ...;

    tm then = {0};
    then.tm_year = y - 1900;
    then.tm_mon = m - 1;
    then.tm_day = d;
    time_t then_secs = mktime(&then);

    time_t time_now = time(0);
    tm* now = localtime(&time_now);
    tm today = {0};
    today.tm_year = now->tm_year;
    today.tm_mon = now->tm_mon;
    today.tm_day = now->tm_day;
    time_t today_secs = mktime(&today);

    return (today_secs - then_secs) / (24*60*60);
}

你的代码是否查询月份有30天、31天或28天? - user3653164
是的,在某种意义上,通过调用 mktime - Igor Tandetnik
当然,最简单的答案是最快的 :) 我更喜欢使用Boost工具,因为问题已经标记了它... - sehe
1
这段代码根本无法编译。需要添加 #includeusing 指令。请加上,以便该答案对社区有用。 - Walter
@sehe 问楼主:“但我不想使用boost。” - Igor Tandetnik
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接