c/c++日期时间处理与字符串string转换
在c/c++实际问题的编程中,我们经常会用到日期与时间的格式,在算法运行中,通常将时间转化为int来进行计算,而处理输入输出的时候,日期时间的格式却是五花八门,以各种标点空格相连或者不加标点。
首先,在c中,是有一个标准的日期时间结构体的,在标准库wchar.h内,我们可以看到结构体tm的声明如下:
1 #ifndef _TM_DEFINED 2 struct tm { 3 int tm_sec; /* seconds after the minute - [0,59] */ 4 int tm_min; /* minutes after the hour - [0,59] */ 5 int tm_hour; /* hours since midnight - [0,23] */ 6 int tm_mday; /* day of the month - [1,31] */ 7 int tm_mon; /* months since January - [0,11] */ 8 int tm_year; /* years since 1900 */ 9 int tm_wday; /* days since Sunday - [0,6] */ 10 int tm_yday; /* days since January 1 - [0,365] */ 11 int tm_isdst; /* daylight savings time flag */ 12 }; 13 #define _TM_DEFINED 14 #endif /* _TM_DEFINED */
由于各项英文注释很好理解,这里只做简要补充。
1)注意月份是0-11,而不是1-12,所以在tm结构体与string转换的时候,要相应的做减1加1处理。
2)tm_isdst为夏令时设置,0为非夏令时,1为夏令时。由于21世纪的中国并没有实行夏令时制度,所以编写国内程序我们可以忽略这个变量。
利用这个结构体,我们就可以完成日期时间与string字符串的转换了,由于计算的方便,我们一般选择将日期时间的string转换成time_t类型。
如果你非要int的话,我可以负责任的告诉你,time_t在visual studio环境下,就是"__int64"类型的变量,它由typedef关键字在库文件crtdefs.h里给定,所以,把time_t放心的拿去用就好了。
言归正传,这里,我们假定输入的字符串格式为"2017-05-27 19:50:02",这个设定并不影响其他格式的字符串时间与可参与计算的变量的转换,如果要参与转换的日期字符串不是这个格式,读者可自行更改下面给出代码的对应部分。
下面给出日期时间string转换为time_t的函数代码。
1 time_t StringToDatetime(string str) 2 { 3 char *cha = (char*)str.data(); // 将string转换成char*。 4 tm tm_; // 定义tm结构体。 5 int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。 6 sscanf(cha, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);// 将string存储的日期时间,转换为int临时变量。 7 tm_.tm_year = year - 1900; // 年,由于tm结构体存储的是从1900年开始的时间,所以tm_year为int临时变量减去1900。 8 tm_.tm_mon = month - 1; // 月,由于tm结构体的月份存储范围为0-11,所以tm_mon为int临时变量减去1。 9 tm_.tm_mday = day; // 日。 10 tm_.tm_hour = hour; // 时。 11 tm_.tm_min = minute; // 分。 12 tm_.tm_sec = second; // 秒。 13 tm_.tm_isdst = 0; // 非夏令时。 14 time_t t_ = mktime(&tm_); // 将tm结构体转换成time_t格式。 15 return t_; // 返回值。 16 }
其中,第6行为给定的日期string设置语句,由于这里假定是输入的string是"2017-05-27 19:50:02",所以将参数设置为"%d-%d-%d %d:%d:%d",如果输入的是其他格式的日期时间形式,将这个参数改为对应的格式即可。另外,如果在一个程序中,设计到多种不同的日期时间格式,可以将这个参数作为这个函数的参数之一来给定。
第14行的mktime函数位于c头文件time.h中,用来将输入参数所指的tm结构数据转换成从公元1970年1月1日0时0分0秒算起至今的本地时间所经过的秒数。
由于返回的time_t通常很大,不利于算法计算的效率,所以我们可以将所有的时间转换完毕后,将所有的time_t全部减去一个数,这个数可以是这个time_t中最小的那个数,也可以是其他方便算法计算的数。在算法执行完毕之后,我们再将结果的时间全部加上这个数,以便将时间转换回来。
现在假定我们已经将算法运行完毕,那么我们需要将结果的time_t转换为之前给定的string格式以便于结果的展示。
下面给出日期时间time_t转换为string的函数代码。
1 string DatetimeToString(time_t time) 2 { 3 tm *tm_ = localtime(&time); // 将time_t格式转换为tm结构体 4 int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。 5 year = tm_->tm_year + 1900; // 临时变量,年,由于tm结构体存储的是从1900年开始的时间,所以临时变量int为tm_year加上1900。 6 month = tm_->tm_mon + 1; // 临时变量,月,由于tm结构体的月份存储范围为0-11,所以临时变量int为tm_mon加上1。 7 day = tm_->tm_mday; // 临时变量,日。 8 hour = tm_->tm_hour; // 临时变量,时。 9 minute = tm_->tm_min; // 临时变量,分。 10 second = tm_->tm_sec; // 临时变量,秒。 11 char yearStr[5], monthStr[3], dayStr[3], hourStr[3], minuteStr[3], secondStr[3];// 定义时间的各个char*变量。 12 sprintf(yearStr, "%d", year); // 年。 13 sprintf(monthStr, "%d", month); // 月。 14 sprintf(dayStr, "%d", day); // 日。 15 sprintf(hourStr, "%d", hour); // 时。 16 sprintf(minuteStr, "%d", minute); // 分。 17 if (minuteStr[1] == '\0') // 如果分为一位,如5,则需要转换字符串为两位,如05。 18 { 19 minuteStr[2] = '\0'; 20 minuteStr[1] = minuteStr[0]; 21 minuteStr[0] = '0'; 22 } 23 sprintf(secondStr, "%d", second); // 秒。 24 if (secondStr[1] == '\0') // 如果秒为一位,如5,则需要转换字符串为两位,如05。 25 { 26 secondStr[2] = '\0'; 27 secondStr[1] = secondStr[0]; 28 secondStr[0] = '0'; 29 } 30 char s[20]; // 定义总日期时间char*变量。 31 sprintf(s, "%s-%s-%s %s:%s:%s", yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);// 将年月日时分秒合并。 32 string str(s); // 定义string变量,并将总日期时间char*变量作为构造函数的参数传入。 33 return str; // 返回转换日期时间后的string变量。 34 }
其中,第3行的localtime函数位于c头文件time.h中,用来将从公元1970年1月1日0时0分0秒算起至今的本地时间所经过的秒数转换成标准tm结构体。
第31行是输出日期时间字符串string格式的给定,如果需要其他格式,可以修改"%s-%s-%s %s:%s:%s"为指定格式,如果在同一个程序里需要多种格式的输出,可以将这个参数作为本函数的参数来输入。
下面给出完整调试用程序及所需头文件,代码测试通过环境windows10 + vs2013;Ubuntu 14.04 + gcc version 4.8.2。
1 #include <iostream> 2 #include <ctime> 3 #include <string> 4 using namespace std; 5 time_t StringToDatetime(string str) 6 { 7 char *cha = (char*)str.data(); // 将string转换成char*。 8 tm tm_; // 定义tm结构体。 9 int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。 10 sscanf(cha, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);// 将string存储的日期时间,转换为int临时变量。 11 tm_.tm_year = year - 1900; // 年,由于tm结构体存储的是从1900年开始的时间,所以tm_year为int临时变量减去1900。 12 tm_.tm_mon = month - 1; // 月,由于tm结构体的月份存储范围为0-11,所以tm_mon为int临时变量减去1。 13 tm_.tm_mday = day; // 日。 14 tm_.tm_hour = hour; // 时。 15 tm_.tm_min = minute; // 分。 16 tm_.tm_sec = second; // 秒。 17 tm_.tm_isdst = 0; // 非夏令时。 18 time_t t_ = mktime(&tm_); // 将tm结构体转换成time_t格式。 19 return t_; // 返回值。 20 } 21 string DatetimeToString(time_t time) 22 { 23 tm *tm_ = localtime(&time); // 将time_t格式转换为tm结构体 24 int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。 25 year = tm_->tm_year + 1900; // 临时变量,年,由于tm结构体存储的是从1900年开始的时间,所以临时变量int为tm_year加上1900。 26 month = tm_->tm_mon + 1; // 临时变量,月,由于tm结构体的月份存储范围为0-11,所以临时变量int为tm_mon加上1。 27 day = tm_->tm_mday; // 临时变量,日。 28 hour = tm_->tm_hour; // 临时变量,时。 29 minute = tm_->tm_min; // 临时变量,分。 30 second = tm_->tm_sec; // 临时变量,秒。 31 char yearStr[5], monthStr[3], dayStr[3], hourStr[3], minuteStr[3], secondStr[3];// 定义时间的各个char*变量。 32 sprintf(yearStr, "%d", year); // 年。 33 sprintf(monthStr, "%d", month); // 月。 34 sprintf(dayStr, "%d", day); // 日。 35 sprintf(hourStr, "%d", hour); // 时。 36 sprintf(minuteStr, "%d", minute); // 分。 37 if (minuteStr[1] == '\0') // 如果分为一位,如5,则需要转换字符串为两位,如05。 38 { 39 minuteStr[2] = '\0'; 40 minuteStr[1] = minuteStr[0]; 41 minuteStr[0] = '0'; 42 } 43 sprintf(secondStr, "%d", second); // 秒。 44 if (secondStr[1] == '\0') // 如果秒为一位,如5,则需要转换字符串为两位,如05。 45 { 46 secondStr[2] = '\0'; 47 secondStr[1] = secondStr[0]; 48 secondStr[0] = '0'; 49 } 50 char s[20]; // 定义总日期时间char*变量。 51 sprintf(s, "%s-%s-%s %s:%s:%s", yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);// 将年月日时分秒合并。 52 string str(s); // 定义string变量,并将总日期时间char*变量作为构造函数的参数传入。 53 return str; // 返回转换日期时间后的string变量。 54 } 55 int main() 56 { 57 string timeStr = "2017-05-27 19:50:02"; 58 cout << timeStr << endl; 59 time_t timet = StringToDatetime(timeStr); 60 timet += 5 * 24 * 3600; 61 string timeStr2 = DatetimeToString(timet); 62 cout << timeStr2 << endl; 63 return 0; 64 }
主函数中给定一个字符串"2017-05-27 19:50:02"。
经过增加5*24*3600秒之后,得到的字符串是"2017-6-1 19:50:02"。
端午节过了就到儿童节啦,完结撒花!*★,°*:。☆\(~▽~)/$:*。°★*。。