使用 strptime/strftime 的结果不一致
Inconsistent results using strptime/strftime
我写了一个表示日期的C++类,我使用 strptime/strftime 从字符串编写和实例化日期。
完整代码在这里
当我使用"示例输出"选项卡中的 bash 在我的 linux 上运行它几次时,有时我会创建并解析相同的日期,有时我会得到一个小时的偏移日期(我的时区是 UTC+1(。
所以,这里发生了什么,我不知道!
#ifndef DOLIPRANE_TIMEUNIT_HPP
#define DOLIPRANE_TIMEUNIT_HPP
enum TimeUnit {
DAY,
HOUR,
MINUTE,
SECOND
};
#endif
#ifndef DOLIPRANE_DATE_HPP
#define DOLIPRANE_DATE_HPP
#include <ctime>
#include <string>
class Date
{
public:
Date();
Date(time_t epoch);
/**
* Expected format: dd/MM/YYYY HH:mm:[ss]
*/
Date(const std::string &date);
~Date();
void
add(long val, TimeUnit u = SECOND);
bool
operator==(const Date &other) const;
bool
operator!=(const Date &other) const;
bool
operator<(const Date &other) const;
bool
operator<=(const Date &other) const;
bool
operator>(const Date &other) const;
bool
operator>=(const Date &other) const;
friend std::ostream&
operator<<(std::ostream &, const Date&);
friend std::istream&
operator>>(std::istream &, Date&);
private:
static const std::string FORMAT;
time_t m_time;
};
#endif
#include <iostream>
#include <stdexcept>
#include <ctime>
const char SEPARATOR=';';
const std::string Date::FORMAT="%d/%m/%Y %H:%M:%S";
Date::Date()
{
m_time = time(NULL);
}
Date::Date(time_t epoch)
: m_time(epoch)
{}
Date::Date(const std::string &date)
{
struct tm t;
const char* ptr = strptime(date.c_str(), FORMAT.c_str(), &t);
if (!ptr) {
std::string cause = "Cannot parse date ";
cause += date;
throw std::invalid_argument(cause);
}
m_time = mktime(&t);
if (m_time == -1) {
std::string cause = "Cannot compute epoch from " + date;
throw std::range_error(cause);
}
}
Date::~Date()
{
}
void
Date::add(long val, TimeUnit u) {
switch(u){
case DAY:
m_time += 86400*val;
break;
case HOUR:
m_time += 3600*val;
break;
case MINUTE:
m_time += 60*val;
break;
case SECOND:
m_time += val;
break;
default:
throw std::invalid_argument("Unknown TimeUnit specified");
}
}
bool
Date::operator==(const Date& o) const
{
return m_time == o.m_time;
}
bool
Date::operator!=(const Date& o) const
{
return ! (*this==o);
}
bool
Date::operator<(const Date &other) const
{
return m_time < other.m_time;
}
bool
Date::operator<=(const Date &other) const
{
return m_time <= other.m_time;
}
bool
Date::operator>(const Date &other) const
{
return m_time > other.m_time;
}
bool
Date::operator>=(const Date &other) const
{
return m_time >= other.m_time;
}
std::ostream&
operator<<(std::ostream& out, const Date &d)
{
struct tm* tm = localtime(&d.m_time);
char buffer[20];
strftime(buffer, 20, Date::FORMAT.c_str(), tm);
out << buffer << SEPARATOR;
return out;
}
std::istream&
operator>>(std::istream &in, Date &d)
{
std::string buf;
std::getline(in, buf, SEPARATOR);
Date o(buf);
d = o;
return in;
}
#include <iostream>
#include <fstream>
int
main(void)
{
Date d;
std::cout << d << std::endl;
std::ofstream out("tmp.txt");
out << d;
out.close();
std::ifstream in("tmp.txt");
Date d2;
in >> d2;
in.close();
std::cout << d2 << std::endl;
}
最后,我是如何测试它的:
$ for i in `seq 1 10`; do echo "test $i:"; ./test; rm tmp.txt; done
test 1:
26/03/2016 00:30:31;
26/03/2016 00:30:31;
test 2:
26/03/2016 00:30:31;
26/03/2016 00:30:31;
test 3:
26/03/2016 00:30:31;
25/03/2016 23:30:31;
test 4:
26/03/2016 00:30:31;
26/03/2016 00:30:31;
test 5:
26/03/2016 00:30:31;
25/03/2016 23:30:31;
test 6:
26/03/2016 00:30:31;
26/03/2016 00:30:31;
test 7:
26/03/2016 00:30:31;
25/03/2016 23:30:31;
test 8:
26/03/2016 00:30:31;
25/03/2016 23:30:31;
test 9:
26/03/2016 00:30:31;
25/03/2016 23:30:31;
test 10:
26/03/2016 00:30:31;
26/03/2016 00:30:31;
问题是struct tm t;
在接受字符串的 Date 构造函数中,它从不初始化对象,因此其tm_isdst字段具有未指定的值。正确设置tm_isdst字段,您将获得一致的多次运行的结果。
最有可能的是,问题是夏令时(也称为夏令时(。
struct tm
有一个名为 tm_isdst
的字段。该字段中的正值表示细分时间采用 DST 格式。0 表示它不是 DST。
strftime
将正确设置字段,但strptime
不会触及它(至少在 glibc 实现中(。 mktime
希望它被正确设置,但幸运的是,它允许它设置为负值,这意味着"我不知道"。在这种情况下,mktime
会尝试弄清楚。(这可能是不可能的,因为每年有一个小时重复,一次是夏令时,一次是冬令时,在时钟改变后。
像在代码中一样,使tm_isdst
字段保持未初始化状态是未定义(且不可预测(的行为。通常正确的策略是在调用 strptime
之后和调用 mktime
之前将其设置为 -1。
通常最好的做法是在调用strptime
之前清零或以其他方式初始化struct tm
,因为该函数只设置与格式对应的字段。
相关文章:
- 如何查找导致结果不一致的代码
- 结果与 fstream::read 不一致
- 使用迭代器对向量的C 递归初始化产生不一致的结果
- boost::d ynamic_bitset 与 std::vector 的结果不一致<bool>?
- 使用不同的表达式计算同一整数时的结果不一致
- RapidJSON 在转换为字符串时产生不一致的结果
- 使用两种不同的方法遍历 Vector 的结果不一致
- GDI打印API StartDoc函数给出的结果不一致
- 位掩码结果不一致
- is_assignable<>结果不一致
- opencvmatchTemplate在计算机之间给出不一致的结果
- CPPCheck返回不一致的结果
- 异步函数产生不一致的结果
- 使用 strptime/strftime 的结果不一致
- 在opencv中findChessboardCorners()的结果不一致
- CUDA 共享内存 - 结果不一致
- C++/CImg结果不一致
- 从文件中读取的浮点值与计算结果不一致
- std::regex_search与gcc 4.9.1的结果不一致
- 不同架构下的浮点结果不一致!!如何继续