如何判断我的 struct tm 是否处于无效状态?
How Can I Tell if My struct tm Has Been Left in an Invalid State?
这是一个关于无效输入的问题,不是无效格式。例如给定以下代码:
tm bar;
foo >> get_time(&bar, "%Y-%m-%d");
cout >> bar.tm_year >> bar.tm_mon >> bar.tm_mday >> endl;
如果我定义这样就没问题:stringstream foo("2001-02-28 non-leap year");
如果我的格式无效,则会出现明显的错误,例如:stringstream foo("bad format 2001-02-28 non-leap year");
但我不知道如何检测我的输入是否无效,例如:
stringstream foo("2001-02-30 non-leap year");
在这种情况下 bar
可以读起来好像没有任何问题。有什么我可以听的东西会提醒我输入无效吗?
由于 mktime
也尝试解释超出范围的值(即 2001-02-30 将被解释为 2001-03-01),您可以执行 mktime
之后通过 localtime
,如果您返回不同的值,则表示原始值无效。
如 Matteo Italia's answer, apart from writing your own Gregorian validator, your only reliable double check is mktime
所述。使用 get_time
获得的 tm
s 无法验证,因为可能会填写也可能不会填写字段。考虑以下 2 个无效示例:
这样做:istringstream("2001-02-30") >> get_time(&bar, "%Y-%m-%d");
导致 将 改变 运行 彻底 mktime
:
bar.tm_mday
: 30
bar.tm_mon
: 1
bar.tm_year
: 100
执行此操作时:istringstream("2001-13-30") >> get_time(&bar, "%Y-%m-%d");
导致 在 运行 到 mktime
时 不会改变的结果:
bar.tm_mday
: 13
bar.tm_mon
: 0
bar.tm_year
: 100
为了让 mktime
更改所有无效日期,我们需要在不使用 get_time
的情况下读取日期:
int year;
int month;
int day;
istringstream foo("2000-13-30");
foo >> year >> ws;
foo.ignore();
foo >> month >> ws;
foo.ignore();
foo >> day;
tm bar = { 0, 0, 0, day, month - 1, year - 1900 };
此时 bar
中的任何错误都可以由 mktime
纠正,因此我们的实际验证步骤将是检查非 time_t(-1)
return 并进行比较修改后的 bar
返回 到原始值:
if(time_t(-1) != mktime(&bar) && bar.tm_mday == day && bar.tm_mon == month - 1 && bar.tm_year == year - 1900)
如果此条件为真,则 bar
的输入有效。
总而言之,可以在不编写公历验证程序的情况下验证 tm
,但是不可能验证具有以下特征的 tm
get_time
.
阅读了
这是一个关于无效输入的问题,不是无效格式。例如给定以下代码:
tm bar;
foo >> get_time(&bar, "%Y-%m-%d");
cout >> bar.tm_year >> bar.tm_mon >> bar.tm_mday >> endl;
如果我定义这样就没问题:stringstream foo("2001-02-28 non-leap year");
如果我的格式无效,则会出现明显的错误,例如:stringstream foo("bad format 2001-02-28 non-leap year");
但我不知道如何检测我的输入是否无效,例如:
stringstream foo("2001-02-30 non-leap year");
在这种情况下 bar
可以读起来好像没有任何问题。有什么我可以听的东西会提醒我输入无效吗?
由于 mktime
也尝试解释超出范围的值(即 2001-02-30 将被解释为 2001-03-01),您可以执行 mktime
之后通过 localtime
,如果您返回不同的值,则表示原始值无效。
如 Matteo Italia's answer, apart from writing your own Gregorian validator, your only reliable double check is mktime
所述。使用 get_time
获得的 tm
s 无法验证,因为可能会填写也可能不会填写字段。考虑以下 2 个无效示例:
这样做:istringstream("2001-02-30") >> get_time(&bar, "%Y-%m-%d");
导致 将 改变 运行 彻底 mktime
:
bar.tm_mday
: 30
bar.tm_mon
: 1
bar.tm_year
: 100
执行此操作时:istringstream("2001-13-30") >> get_time(&bar, "%Y-%m-%d");
导致 在 运行 到 mktime
时 不会改变的结果:
bar.tm_mday
: 13
bar.tm_mon
: 0
bar.tm_year
: 100
为了让 mktime
更改所有无效日期,我们需要在不使用 get_time
的情况下读取日期:
int year;
int month;
int day;
istringstream foo("2000-13-30");
foo >> year >> ws;
foo.ignore();
foo >> month >> ws;
foo.ignore();
foo >> day;
tm bar = { 0, 0, 0, day, month - 1, year - 1900 };
此时 bar
中的任何错误都可以由 mktime
纠正,因此我们的实际验证步骤将是检查非 time_t(-1)
return 并进行比较修改后的 bar
返回 到原始值:
if(time_t(-1) != mktime(&bar) && bar.tm_mday == day && bar.tm_mon == month - 1 && bar.tm_year == year - 1900)
如果此条件为真,则 bar
的输入有效。
总而言之,可以在不编写公历验证程序的情况下验证 tm
,但是不可能验证具有以下特征的 tm
get_time
.