C++ 如何导致std::mktime失败?
我过去常常在程序中设置/获取时间。手册页显示: 允许时间值超出其正常范围 如果不能将结果表示为std::time\t,则返回-1 我在我的单元测试中尝试了所有的方法使这个函数失败,但是没有成功。 只是一些尝试:C++ 如何导致std::mktime失败?,c++,gcc,64-bit,C++,Gcc,64 Bit,我过去常常在程序中设置/获取时间。手册页显示: 允许时间值超出其正常范围 如果不能将结果表示为std::time\t,则返回-1 我在我的单元测试中尝试了所有的方法使这个函数失败,但是没有成功。 只是一些尝试: #include <iostream> #include <iomanip> #include <ctime> #include <stdlib.h> int main() { setenv("TZ", "/usr/share/z
#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>
int main()
{
setenv("TZ", "/usr/share/zoneinfo/America/New_York", 1); // POSIX-specific
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
std::cout << "Today is " << std::put_time(&tm, "%c %Z")
<< " and DST is " << (tm.tm_isdst ? "in effect" : "not in effect") << '\n';
tm.tm_year = 550;
tm.tm_year = 123456789;
tm.tm_mon = 88;
tm.tm_mday = 200;
//tm.tm_mon -= 100; // tm_mon is now outside its normal range
std::mktime(&tm); // tm_dst is not set to -1; today's DST status is used
std::cout << "100 months ago was " << std::put_time(&tm, "%c %Z")
<< " and DST was " << (tm.tm_isdst ? "in effect" : "not in effect") << '\n';
}
对于建议的输入
std::numeric\u limits::max()
,您的示例确实失败。您的示例没有检查-1返回值。如果你加上
auto err = std::mktime(&tm); // tm_dst is not set to -1, err is.
对于此输入,err
设置为-1
你可以在下面看到失败
您还可以在以下位置看到失败:
两种服务上的输出相同:
Today is Thu Apr 19 09:07:40 2018 EDT and DST is in effect
100 months ago was Thu ? 200 09:07:40 -2147481749 EDT and DST was in effect
-1
当发生溢出时,
mktime
将无法更新tm
结构,例如,当年份设置为INT\u MAX
并且添加了超过12个月(超过一年)时。像这样:
std::tm tm;
tm.tm_year = INT_MAX;
tm.tm_mon = 13;
std::time_t rc = std::mktime(&tm);
如果您将年份设置为INT\u MIN
,月份设置为零并减去一天(将tm\u mon
设置为0,将tm\u mday
设置为-1),则它也将无法更新tm
结构:
如果月份和tm_mday的组合仍然少于一年,则当year设置为INT_MAX
时,它不会失败,因为这仍然是可表示的
然而,正如MSalters提到的,这并不总是导致返回值为-1。有时,
mktime
无法将时间戳规范化为有效的tm
结构时,它将返回-1。但是,根据实现的不同,mktime
也只能在时间不能用time\t
表示时返回-1(因为time\t是“未指定的”)。在后一种情况下,假设tm结构规范化为有效值实际上是危险的。如果您将年份更改为例如INT\u MAX
,std::mktime
将返回-1。从现在开始已经很长时间了,但是你现在用的日期作为例子仍然可以表示…@Elijan9谢谢,但这并没有让它失败。检查编辑。如果失败返回-1,那么它确实会打印负值。你说失败是什么意思?@B确切地说,你需要检查返回值,当mktime
无法设置有效时间时(例如,当它溢出时),返回值将为-1@Elijan9:这很重要,因为即使在INT\u MAX
为32位的系统上,time\u t
也可以合理地为64位。由于一年中的时间远远少于2^32秒,因此任何32位的年份都可以转换为64位的时间(以秒为单位)。我进行检查(请参见编辑中的示例)。为什么它能在ideone上工作,而不能在coliru上工作,以及在我的编译器上工作?@Bцћcoliru在给定的示例中也会失败;您不能假设某个特定的实现。一个实现可以很好地使用64位进行所有后台计算,并在任何操作之前将tm_year
转换为64位。我刚刚构建并安装了一个32位gcc编译器,当我使用INT_MAX时它会失败。但是64位,我不能让它失败。它永远不会回来-1@MSalters从技术上讲,它将失败,因为标准将tm_year定义为int
,而int_MAX是数据类型可以保存的最大值?(但是,mktime可能不会注意到溢出。)
Today is Thu Apr 19 09:07:40 2018 EDT and DST is in effect
100 months ago was Thu ? 200 09:07:40 -2147481749 EDT and DST was in effect
-1
std::tm tm;
tm.tm_year = INT_MAX;
tm.tm_mon = 13;
std::time_t rc = std::mktime(&tm);
std::tm tm;
tm.tm_year = INT_MIN;
tm.tm_mon = 0;
tm.tm_mday = -1;
std::time_t rc = std::mktime(&tm);