所以我试图将格式为“2000-01-01”的日期转换为表示自任意来源(例如1900/01/01)以来的天数的整数,因此我可以将它们视为整数索引。为此,我编写了一个转换函数,可以在Windows XP下使用MinGW,但不能在Vista下使用。我添加了一些日志代码:
int dateStrToInt(string date) {
int ymd[3];
tm tm1, tm0;
istringstream iss(date);
string s;
for (int i = 3; i; --i) {
getline(iss, s, '-');
ymd[3-i] = str2<int>(s);
}
cout << ymd[0] << ' ' << ymd[1] << ' ' << ymd[2] << ' ' << endl;
tm1.tm_year = ymd[0] - 1900;
tm1.tm_mon = ymd[1] - 1;
tm1.tm_mday = ymd[2];
time_t t1 = mktime(&tm1);
tm0.tm_year = 0;
tm0.tm_mon = 0;
tm0.tm_mday = 0;
time_t t0 = mktime(&tm0);
//cout << "times: " << mktime(&origin) << ' ' << mktime(&time) << endl;
cout << "times: " << t0 << ' ' << t1 << endl;
cout << "difftime: " << difftime(t1, t0) << endl;
return difftime(mktime(&tm1), mktime(&tm0)) / (60*60*24);
}
int i = dateStrToInt("2000-01-01");
我得到的输出是
2000 1 1
times: -1 -1
difftime: 0
这似乎显然是错误的。我该怎么办?
编辑:正如下面的答案所说,在1970年之前的几年里似乎存在问题。为了避免这种情况,我已经处理了我自己的日计算功能:int dateStrToInt(string date) {
int ymd[3];
istringstream iss(date);
string s;
for (int i = 0; i < 3; ++i) {
getline(iss, s, '-');
ymd[i] = str2<int>(s);
}
const static int cum_m_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
int year = ymd[0]+10000, month = ymd[1], day = ymd[2];
int days = year*365 + cum_m_days[month-1] + day;
// handle leap years
if (month <= 2)
--year;
days = days + (year/4) - (year/100) + (year/400);
return days;
}
答案 0 :(得分:3)
将所有其他struct tm
字段保留为默认值(在本例中为随机值)并不一定是个好主意。
在调用mktime
之前,标准并未过分明确需要设置哪些字段,但它确实表示它根据其他字段设置tm_wday
和tm_yday
,并且其他字段不限于有效。
标准 显示的一件事是示例代码,它设置所有字段,除了上面提到的那两个字段,这就是我的目标。
尝试更改计算时间的细分:
tm1.tm_year = ymd[0] - 1900;
tm1.tm_mon = ymd[1] - 1;
tm1.tm_mday = ymd[2];
time_t t1 = mktime(&tm1);
tm0.tm_year = 0;
tm0.tm_mon = 0;
tm0.tm_mday = 0;
time_t t0 = mktime(&tm0);
类似于:
// Quick and dirty way to get decent values for all fields.
time_t filled_in;
time (&filled_in);
memcpy (&tm1, localtime ( &filled_in ), sizeof (tm1));
memcpy (&tm0, &tm1, sizeof (tm0));
// Now do the modifications to relevant fields, and calculations.
tm1.tm_year = ymd[0] - 1900;
tm1.tm_mon = ymd[1] - 1;
tm1.tm_mday = ymd[2];
time_t t1 = mktime(&tm1);
tm0.tm_year = 0;
tm0.tm_mon = 0;
tm0.tm_mday = 0;
time_t t0 = mktime(&tm0);
此外,在XP下对CygWin进行的一些实验导致mktime
似乎在struct tm
结构中返回-1,其中tm_year
小于2。这是否是一个真正的错误是值得怀疑的,因为我经常发现实现并不总是支持纪元(1970年1月1日)之前的日期。
某些UNIX确实允许您指定小于70的tm_year
值,并且他们通常可以使用time_t
的这些“负”值来访问1970年以来的数据。
但是,由于标准并没有真正涉及到它,所以留待实施。可以在7.23.1 / 4中找到C99标准的相关位(可能还有早期的迭代),它们可以用于C ++:
clock_t和time_t中可表示的时间范围和精度是实现定义的。
最安全的选择是使用纪元开始后的日期作为基线日期。这显示在以下代码中:
#include <iostream>
#include <sstream>
#include <string>
#include <ctime>
#include <cstring>
#include <cstdlib>
int dateStrToInt(std::string date) {
int ymd[3];
tm tm1, tm0;
std::istringstream iss(date);
std::string s;
// Test code.
ymd[0] = 2000; ymd[1] = 1; ymd[2] = 1;
std::cout << ymd[0] << ' ' << ymd[1] << ' ' << ymd[2] << ' ' << std::endl;
time_t filled_in;
time (&filled_in);
std::memcpy (&tm0, localtime ( &filled_in ), sizeof (tm0));
std::memcpy (&tm1, &tm0, sizeof (tm1));
tm1.tm_year = ymd[0] - 1900;
tm1.tm_mon = ymd[1] - 1;
tm1.tm_mday = ymd[2];
time_t t1 = mktime(&tm1);
tm0.tm_year = 1970 - 1900; // Use epoch as base date.
tm0.tm_mon = 0;
tm0.tm_mday = 1;
time_t t0 = mktime(&tm0);
std::cout << "times: " << t0 << ' ' << t1 << std::endl;
std::cout << "difftime: " << difftime(t1, t0) << std::endl;
return difftime(mktime(&tm1), mktime(&tm0)) / (60*60*24);
}
int main (void) {
int i = dateStrToInt("2000-01-01");
double d = i; d /= 365.25;
std::cout << i << " days, about " << d << " years." << std::endl;
return 0;
}
这会输出预期结果:
2000 1 1
times: 31331 946716131
difftime: 9.46685e+08
10957 days, about 29.9986 years.
作为附录,POSIX有this说:
自纪元以来4.14秒
一个值,它近似于自Epoch以来经过的秒数。协调世界时名称(以秒(tm_sec),分钟(tm_min),小时(tm_hour),自1月1日以来的天数(tm_yday)和日历年减去1900(tm_year))指定与时间表示自大纪元以来的秒数,根据下面的表达式。
如果年份<1970年或该值为负,则该关系未定义。如果年份>> = 1970且值为非负值,则该值根据C语言表达式与协调世界时名称相关,其中tm_sec,tm_min,tm_hour,tm_yday和tm_year都是整数类型:
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
未指明自Epoch以来实际时间与秒数当前值之间的关系。
如何对Epoch以来的秒值进行任何更改,以便与当前实际时间的所需关系对齐,这是实现定义的。如自大纪元以来的秒数所示,每天应该恰好以86400秒计算。
注意:表达式的最后三个术语在每年的一天中添加,从闰年开始,这是闰年以来的第一个闰年。第一学期从1973年开始每4年增加一天,第二学期从2001年开始每100年减去一天,第三学期从2001年开始每400年增加一天。公式中的分数是整数除法;也就是说,丢弃余数只留下整数商。
换句话说(参见“如果年份&lt; 1970或价值为负,关系未定义”),请使用1970年以前的日期,风险自负。