C++对输入string字符串进行格式判断并转化为time_t时间戳
前言
学校实验要求输入一个时间段,在此时间段内进行查询统计。
我的思路是规定格式,让用户按照格式分别输入开始时间和结束时间,对时间格式进行判断,为有效时间后,将string字符串转化为time_t时间戳,通过时间戳比大小获得相应时间段的数据。
在格式判断方面,我最初是一大连串if条件判断,耗时耗力也冗杂易错。后来经过男票的提醒,老老实实用正则表达式判断。由于刚接触正则表达式,不够熟练。所以最后成型的格式判断是土洋结合的正则+部分条件判断。纯正则可以参考大佬链接:正则应用之一——日期正则表达式
代码
bool isTime(string str) {
regex pattern("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}");
if(!regex_match(str, pattern)){
return false;
}
int year = stoi(str.substr(0, 4));
int month = stoi(str.substr(5, 2));
int day = stoi(str.substr(8, 2));
int minute = stoi(str.substr(11,2));
int second = stoi(str.substr(14,2));
if(year >= 1900 && month > 0 && month < 13 && minute < 25 && second < 61){
switch(month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: {
if(day > 31){
return false;
}
break;
}
case 4:
case 6:
case 9:
case 11: {
if (day > 30) {
return false;
}
break;
}
default:break;
}
if(month == 2) {
if (((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)) {
if(day > 29) {
return false;
}
}
else {
if(day > 28){
return false;
}
}
}
}else{
return false;
}
return true;
}
isTime()函数是格式判断的主体,先确定字符串为yyyy-MM-dd的正确格式,再对该字符串进行字符截取,截取出年月日时分,并进行月份日期匹配判断,以及年、时、分的有效范围判断。
time_t stringToTime(char *pTime){
struct tm tm1;
time_t time1;
sscanf(pTime, "%d-%d-%d %d:%d",&tm1.tm_year, &tm1.tm_mon,
&tm1.tm_mday , &tm1.tm_hour, &tm1.tm_min);
tm1.tm_year -= 1900;
tm1.tm_mon -= 1;
tm1.tm_sec = 0;
tm1.tm_isdst = -1;
time1 = mktime(&tm1);
return time1;
}
stringToTime()函数将时间有效的字符串以字符数组为媒介转化为时间戳。sscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据,函数原型为int sscanf (const char *str,const char * format,…)。我一开始没得脑子想用sscanf函数的返回值来判断时间格式的有效性,可是根本办不到,其实sscanf这里就应该老老实实作为格式化数据的工具,格式判断应该交给外部去处理,它只用拿到正确的格式就好了。
bool loop(){
string cho = "";
while (cho != "N" && cho != "Y"&& cho != "n"&& cho != "y") {
cout <<endl<< "是否重新输入?(y/n)";
cin.clear();
cin.sync();
cin >> cho;
}
return cho != "N"&& cho != "n";
}
loop()函数用于用户输入错误时间,系统向用户确认是否需要再次输入。此函数也处理了用户输入"y"和"n"之外的数据,将一直循环到你老老实实输入"y"和"n"为止。
bool timeInput(long& lBeginTime, long& lEndTime){
char aBeginTime[20] = {0};
char aEndTime[20] = {0};
string sBeginTime;
string sEndTime;
cout << "请输入查询时间段:" << endl;
while (true) {
cout << "开始时间:(输入格式:2019-03-21 10:59)";
getline(cin, sBeginTime);
if (!isTime(sBeginTime)) {
cout << "时间格式输入错误" << endl;
if (!loop()) {
return false;
}
getchar();
} else {
break;
}
}
while(true) {
cout << "结束时间:(输入格式:2019-03-21 10:59)";
getline(cin, sEndTime);
if (!isTime(sEndTime)) {
cout << "时间格式输入错误" << endl;
if (!loop()) {
return false;
}
getchar();
} else {
break;
}
}
strcpy(aBeginTime, sBeginTime.c_str());
strcpy(aEndTime, sEndTime.c_str());
lBeginTime = stringToTime(aBeginTime);
lEndTime = stringToTime(aEndTime);
if(lEndTime<=lBeginTime){
cout<<"结束时间不能小于开始时间!"<<endl;
return false;
}
return true;
}
timeInput()函数用于输入开始时间和结束时间并进行判断,包括判断时间段是否有效。其中,由于cin>>无法接收用户输入的字符串中的空格,所以调用getline()函数能够接收空格,同时需要配合getchar()函数来使用,吸收回车字符。
int main() {
long lBeginTime;
long lEndTime;
if(!timeInput(lBeginTime,lEndTime)){
cout << endl << "输入时间段失败!";
}else{
cout << endl << "输入时间段成功!";
}
}
输入时间段成功后,手上就已经拿到lBeginTime和lEndTime两个时间的时间戳了,后面想和什么时间进行大小比较就能比了,直接判断大小,如
if(lBeginTime < lCurrentTime && lCurrentTime < lEndTime){
//TODO
}