两个日期之间的天数 C++
Posted
技术标签:
【中文标题】两个日期之间的天数 C++【英文标题】:Number of days between two dates C++ 【发布时间】:2012-12-22 12:52:47 【问题描述】:我看到了 C#、Java 的示例,但对于 C++,我找不到计算两个日期之间的天数的解决方案。
例如在 2012-01-24 和 2013-01-08 之间
谢谢!
【问题讨论】:
到目前为止你有什么尝试?您使用什么数据类型来存储此日期?在我看来,它可以像(date1 - date2).to_days();
一样简单,甚至可以使用 C++11 和适当的代码 ("2012-01-24"_date - "2013-01-08"_date).to_days();
如果你打算使用这个算法来处理历史数据,要小心,因为过去是惊人的不连续。例如,1582/10/5 和 1582/10/14 之间有多少天?答:1 if you're in Spain, Portugal, or Italy.
【参考方案1】:
这是一种方式。
#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;
我的输出
Thu Jun 24 01:00:00 2004
Mon Jul 05 01:00:00 2004
difference = 11 days
Here is a ref to Original author post
【讨论】:
有一个 Ref 要发帖,我把它加粗 我看到了这个(否则我不会知道),但很难看到。 感谢您的提示,我会在下一个回复中考虑这一点 您还应该强调它不起作用。如果日期跨越您在夏季和冬季时间之间更改的日期,您可能会得到不一致的结果。 (暂时使用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;
这样的东西。
这种方法不考虑夏令时转换、闰秒或公历中的空缺。只要您始终考虑每天的午夜并四舍五入到最接近的天数,前两个陷阱就不会伤害您。只要您不使用跨越漏洞的日期范围(1582 之后的任何时间都是安全的),第三个陷阱也不会让您陷入困境。【参考方案2】:
将您的日期转换为表示自一个纪元以来的天数的整数,然后减去。在这个例子中我选择了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);
【讨论】:
(153*m - 457)/5 + d - 306
是什么意思?
@immiao,算法将二月移动到年底。 (153 * m - 457)/5
计算偏移月份的前几天数。从零年的 3 月 1 日到 12 月 31 日之间有 306 天。【参考方案3】:
旧问题的新答案:
使用这个C++11/C++14 header-only date library,你现在可以写:
#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_daysy - sys_daysx).count() << " days\n";
哪些输出:
2012-01-24
2013-01-08
difference = 350 days
如果您不想依赖此库,您可以编写自己的库,使用与上述日期库相同的日期算法。它们在本文中找到:chrono-Compatible Low-Level Date Algorithms。本例中使用的本文算法是这样的:
// 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;
请参阅chrono-Compatible Low-Level Date Algorithms,了解有关此算法如何工作、对其进行单元测试及其有效性范围的详细信息。
此算法模拟proleptic Gregorian calendar,它无限期地扩展公历,向前和向后。要建模其他日历(例如儒略历),您将需要其他算法,such as the ones shown here。一旦你设置了其他日历,并同步到同一个系列纪元(这些算法使用 1970-01-01 Gregorian,这也是 Unix time 纪元),你就可以轻松地计算出任何两个日期之间的天数,但也可以在您建模的任意两个日历之间。
这使您不必在从儒略到公历转换的日期中硬编码。您只需要知道您的输入数据是针对哪个日历引用的。
有时历史文档中可能不明确的日期会用Old Style / New Style 进行注释,以分别表示儒略历或公历。
如果您还关心日期的时间,这个same date library 与<chrono>
库无缝集成以使用hours
、minutes
、seconds
、milliseconds
、@987654342 @ 和nanoseconds
,并用system_clock::now()
获取当前日期和时间。
如果您关心时区,则在date library 之上写一个额外的(单独的)timezone library 以使用IANA timezone database 处理时区。如果需要,timezone library 还具有计算功能,包括 leap seconds。
【讨论】:
如果日期最初存储为std::string
怎么办?你如何将string
转换为sys_days()
可以使用的类型?
搜索“[c++] user:576911 parse”。【参考方案4】:
你可以试试boost date_time库
【讨论】:
【参考方案5】:为避免创建自己的函数,您可以使用 Boost 中的 date_time。
【讨论】:
以上是关于两个日期之间的天数 C++的主要内容,如果未能解决你的问题,请参考以下文章