Q我如何给日期加上 N 天?我如何找出两个日期之间的差值?
AANSI/ISO 标准 Cmktime和difftime函数为这两个问题提供了一些(有限的)支持。mktime接受非标准化的日期,因此很容易填写一个struct tm,加减tm_mday字段,然后调用mktime来标准化年、月、日字段(并顺便转换为time_t值)。difftime计算两个time_t值之间的差值(以秒为单位);mktime可用于计算要减去的两个日期的time_t值。
然而,这些解决方案只能保证在可表示的范围内的日期上正确工作time_t的 [脚注] 。tm_mday字段是int,因此超过 32,736 天的日偏移量可能会导致溢出。(关于没有这些限制的替代解决方案,请参见下文。)另请注意,在夏令时转换期间,本地日不是 24 小时,因此如果您尝试除以 86,400 秒/天,请小心。
这是一个计算 1994 年 10 月 24 日之后 90 天日期的代码片段
#include <stdio.h> #include <time.h> tm1.tm_mon = 10 - 1; tm1.tm_mday = 24; tm1.tm_year = 1994 - 1900; tm1.tm_hour = tm1.tm_min = tm1.tm_sec = 0; tm1.tm_isdst = -1; tm1.tm_mday += 90; if(mktime(&tm1) == -1) fprintf(stderr, "mktime failed\n"); else printf("%d/%d/%d\n", tm1.tm_mon+1, tm1.tm_mday, tm1.tm_year+1900);(设置tm_isdst为 -1 有助于防止夏令时异常;设置tm_hour为 12 也有此作用。)
这是一段代码,用于计算 2000 年 2 月 28 日和 3 月 1 日之间的天数差
struct tm tm1, tm2; time_t t1, t2; tm1.tm_mon = 2 - 1; tm1.tm_mday = 28; tm1.tm_year = 2000 - 1900; tm1.tm_hour = tm1.tm_min = tm1.tm_sec = 0; tm1.tm_isdst = -1; tm2.tm_mon = 3 - 1; tm2.tm_mday = 1; tm2.tm_year = 2000 - 1900; tm2.tm_hour = tm2.tm_min = tm2.tm_sec = 0; tm2.tm_isdst = -1; t1 = mktime(&tm1); t2 = mktime(&tm2); if(t1 == -1 || t2 == -1) fprintf(stderr, "mktime failed\n"); else { long d = (difftime(t2, t1) + 86400L/2) / 86400L; printf("%ld\n", d); }(加上86400L/2会将差值四舍五入到最接近的天;另请参见问题 14.6。)
另一种处理这两个问题的方法是使用“儒略日编号”。儒略日编号是从公元前 4013 年 1 月 1 日开始计算的天数。 [脚注] 。使用ToJul和FromJul例程声明如下:
/* returns Julian for month, day, year */ long ToJul(int month, int day, int year); /* returns month, day, year for jul */ void FromJul(long jul, int *monthp, int *dayp, int *yearp);将n天添加到日期可以实现为
int n = 90; int month, day, year; FromJul(ToJul(10, 24, 1994) + n, &month, &day, &year);,两个日期之间的天数是
ToJul(3, 1, 2000) - ToJul(2, 28, 2000)处理儒略日编号的代码可以在 Snippets 集合(参见问题 18.15c)、Simtel/Oakland 档案(文件 JULCAL10.ZIP,参见问题 18.16)以及参考文献中提到的“日期转换”文章中找到。
额外链接
Mark Brader 的进一步解释
Branko Radovanovic 的日期差和星期几计算的更多代码
参考文献:K&R2 Sec. B10 p. 256
ISO Secs. 7.12.2.2,7.12.2.3
H&S Secs. 18.4,18.5 pp. 401-2
David Burki,“日期转换”