在Windows上将时间string转换为纪元时间

我有一个接口,我得到一个文件,文件名是内部数据有效时的时间戳。 我正在按顺序处理这些文件,并将它们提供给另一个自1970年1月1日以来的毫秒时间的API。

所以,我以YYYYMMDD_HHmmSS.sss格式的string获取文件名,并且必须将其转化为时间。 我假设处理和收集发生在相同的时区,并且只需要将字符转换为数字。

uint64_t foo::convertFileNameToTimestamp(const std::string& filename) const { const uint64_t yyyy = atoi(filename.substr(0,4).c_str()); const uint64_t MM = atoi(filename.substr(4,2).c_str()); const uint64_t DD = atoi(filename.substr(6,2).c_str()); const uint64_t HH = atoi(filename.substr(9,2).c_str()); const uint64_t MI = atoi(filename.substr(11,2).c_str()); const uint64_t SS = atoi(filename.substr(13,2).c_str()); const uint64_t sss = atoi(filename.substr(16,3).c_str()); // number of milliseconds in a day const uint64_t DAY = 24 * 60 * 60 * 1000; int MD = 0; if (MM == 2) MD = 31; // currently feb, so add all of january's days else if (MM == 3) MD = 31+28; // ... else if (MM == 4) MD = 31+28+31; else if (MM == 5) MD = 31+28+31+30; else if (MM == 6) MD = 31+28+31+30+31; else if (MM == 7) MD = 31+28+31+30+31+30; else if (MM == 8) MD = 31+28+31+30+31+30+31; else if (MM == 9) MD = 31+28+31+30+31+30+31+31; else if (MM == 10) MD = 31+28+31+30+31+30+31+31+30; else if (MM == 11) MD = 31+28+31+30+31+30+31+31+30+31; else if (MM == 12) MD = 31+28+31+30+31+30+31+31+30+31+30; // year 2000 wasn't a leap year uint64_t YLD = ((yyyy-1970) / 4); if (yyyy > 2000) --YLD; uint64_t temp = sss; temp += SS * 1000; temp += MI * 60 * 1000; temp += HH * 60 * 60 * 1000; temp += (DD-1) * DAY; temp += (MD) * DAY; temp += (yyyy-1970) * 365 * DAY + YLD*DAY; return temp; } 

显然,在这里重新发明轮子。 似乎应该有这样的function。 另外..我如何计算闰秒? 处理闰日已经够烦人的了。 时间戳都是从2015年开始的,总是会的,但是我不认为我可以一味地加26秒。 最后,我们将有27或备份到25.在以前的函数中,我已validationstring是正确的格式和文件存在,所有的爵士乐。 我在使用VS 2010的64位Windows 8.1编译运行。

我已经看过转换大纪元时间string时间build议ctime() ,但它似乎并没有处理毫秒的构造函数,甚至任何get方法,它不接受一般格式化的stringinput。 我假设我必须调用一些时间类CTOR,它将接受文件名string,然后调用一些访问器来获得自1970年以来的毫秒时间,包括闰秒等。

我没有使用提升,并没有访问/许可使用它。

Solutions Collecting From Web of "在Windows上将时间string转换为纪元时间"

这是一个可以在任何支持C ++ 11或C ++ 14的平台上工作的答案。 它建立在C ++ 11中引入的std::chrono库中。 它还使用免费的开源跨平台库来简化算法(麻省理工学院的许可证,通常被认为是律师友好的 )。

如果你不需要考虑闰秒,你可以使用这个日期库 ,它看起来像这样:

 #include <string> #include "date.h" using time_stamp = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>; time_stamp convertFileNameToTimestamp(const std::string& filename) { using namespace std::chrono; using namespace date; const uint64_t yyyy = atoi(filename.substr(0,4).c_str()); const uint64_t MM = atoi(filename.substr(4,2).c_str()); const uint64_t DD = atoi(filename.substr(6,2).c_str()); const uint64_t HH = atoi(filename.substr(9,2).c_str()); const uint64_t MI = atoi(filename.substr(11,2).c_str()); const uint64_t SS = atoi(filename.substr(13,2).c_str()); const uint64_t sss = atoi(filename.substr(16,3).c_str()); return sys_days{year(yyyy)/MM/DD} + hours{HH} + minutes{MI} + seconds{SS} + milliseconds{sss}; } 

从文件名中解析出数字后,创建一个类型安全的std::chrono::time_point非常简单,该类型自1970-01-01( int64_t )以来只保存了整数个毫秒。

如果您想考虑闰秒,则需要这个更高级别的库 ,它是IANA时区数据库的完整解析器。 您还需要保留为我的时区/闰秒库下载的IANA时区数据库的最新副本进行解析。 但是一旦建立起来,你的转换器的源代码就和上面非常相似,几乎一样简单:

 #include <string> #include "tz.h" using time_stamp_ls = std::chrono::time_point<date::utc_clock, std::chrono::milliseconds>; time_stamp_ls convertFileNameToTimestamp_ls(const std::string& filename) { using namespace std::chrono; using namespace date; const uint64_t yyyy = atoi(filename.substr(0,4).c_str()); const uint64_t MM = atoi(filename.substr(4,2).c_str()); const uint64_t DD = atoi(filename.substr(6,2).c_str()); const uint64_t HH = atoi(filename.substr(9,2).c_str()); const uint64_t MI = atoi(filename.substr(11,2).c_str()); const uint64_t SS = atoi(filename.substr(13,2).c_str()); const uint64_t sss = atoi(filename.substr(16,3).c_str()); return utc_clock::sys_to_utc(sys_days{year(yyyy)/MM/DD} + hours{HH} + minutes{MI} + seconds{SS} + milliseconds{sss}); } 

这两个函数都可以用下面的HelloWorld来执行:

 #include <iostream> int main() { std::string filename = "20150830_002120.123"; std::cout << convertFileNameToTimestamp (filename).time_since_epoch().count() << '\n'; std::cout << convertFileNameToTimestamp_ls(filename).time_since_epoch().count() << '\n'; } 

其输出:

 1440894080123 1440894106123 

请注意,这些时间戳是相距26,000毫秒。

更新

现在"tz.h"头文件包含了一个parse函数,这使得写这些函数变得更容易:

 date::sys_time<std::chrono::milliseconds> convertFileNameToTimestamp(const std::string& filename) { using namespace std::chrono; using namespace date; std::istringstream in{filename}; sys_time<milliseconds> tp; parse(in, "%Y%m%d_%H%M%S", tp); return tp; } date::utc_time<std::chrono::milliseconds> convertFileNameToTimestamp_ls(const std::string& filename) { return date::to_utc_time(convertFileNameToTimestamp(filename)); } 

你可以使用这段代码(你不必担心闰年和所有相关的东西)。 @ Edit1:修改代码以考虑闰秒; 也重组成了一个类:

Foo.h

 #ifndef __FOO__H__ #define __FOO__H__ #include <string> #include <Windows.h> #include <stdint.h> class CFoo { private: const static int kLeapSecsDim = 26; static uint64_t msecsBetweenEpochs; static SYSTEMTIME leapSecs[kLeapSecsDim]; ULARGE_INTEGER leapSecsUi[kLeapSecsDim]; int CFoo::getLeapSeconds(ULARGE_INTEGER ui) const; public: CFoo(); ~CFoo() {}; uint64_t toEpoch(const std::string& filename) const; }; #endif //__FOO__H__ 

Foo.cpp

 #include "Foo.h" uint64_t CFoo::msecsBetweenEpochs = 11644473600000; /* Milliseconds between 1.1.1601 and 1.1.1970 */ SYSTEMTIME CFoo::leapSecs[CFoo::kLeapSecsDim] = {{1972, 06, 0, 30, 23, 59, 59, 999}, {1972, 12, 0, 31, 23, 59, 59, 999}, {1973, 12, 0, 31, 23, 59, 59, 999}, {1974, 12, 0, 31, 23, 59, 59, 999}, {1975, 12, 0, 31, 23, 59, 59, 999}, {1976, 12, 0, 31, 23, 59, 59, 999}, {1977, 12, 0, 31, 23, 59, 59, 999}, {1978, 12, 0, 31, 23, 59, 59, 999}, {1979, 12, 0, 31, 23, 59, 59, 999}, {1981, 06, 0, 30, 23, 59, 59, 999}, {1982, 06, 0, 30, 23, 59, 59, 999}, {1983, 06, 0, 30, 23, 59, 59, 999}, {1985, 06, 0, 30, 23, 59, 59, 999}, {1987, 12, 0, 31, 23, 59, 59, 999}, {1989, 12, 0, 31, 23, 59, 59, 999}, {1990, 12, 0, 31, 23, 59, 59, 999}, {1992, 06, 0, 30, 23, 59, 59, 999}, {1993, 06, 0, 30, 23, 59, 59, 999}, {1994, 06, 0, 30, 23, 59, 59, 999}, {1995, 12, 0, 31, 23, 59, 59, 999}, {1997, 06, 0, 30, 23, 59, 59, 999}, {1998, 12, 0, 31, 23, 59, 59, 999}, {2005, 12, 0, 31, 23, 59, 59, 999}, {2008, 12, 0, 31, 23, 59, 59, 999}, {2012, 06, 0, 30, 23, 59, 59, 999}, {2015, 06, 0, 30, 23, 59, 59, 999}, }; int CFoo::getLeapSeconds(ULARGE_INTEGER ui) const { int ret = 0; for (int i = 0; i < kLeapSecsDim; i++) { if (ui.QuadPart <= this->leapSecsUi[i].QuadPart) break; ret++; } return ret; } CFoo::CFoo() { FILETIME ft; BOOL res; for (int i = 0; i < this->kLeapSecsDim; i++) { res = SystemTimeToFileTime(&(this->leapSecs[i]), &ft); if (res == FALSE) throw std::exception("SystemTimeToFileTime error", GetLastError()); this->leapSecsUi[i].LowPart = ft.dwLowDateTime; this->leapSecsUi[i].HighPart = ft.dwHighDateTime; } } uint64_t CFoo::toEpoch(const std::string& filename) const { SYSTEMTIME st; FILETIME ft; ULARGE_INTEGER ui; st.wYear = atoi(filename.substr(0, 4).c_str()); st.wMonth = atoi(filename.substr(4, 2).c_str()); st.wDay = atoi(filename.substr(6, 2).c_str()); st.wHour = atoi(filename.substr(9, 2).c_str()); st.wMinute = atoi(filename.substr(11, 2).c_str()); st.wSecond = atoi(filename.substr(13, 2).c_str()); st.wMilliseconds = atoi(filename.substr(16, 3).c_str()); BOOL result = SystemTimeToFileTime(&st, &ft); if (result == FALSE) throw std::exception("SystemTimeToFileTime error", GetLastError()); ui.HighPart = ft.dwHighDateTime; ui.LowPart = ft.dwLowDateTime; //printf("%016I64X - %I64u\n", ui.QuadPart, ui.QuadPart); //printf("%016I64X - %I64u\n", ui.QuadPart/10000, ui.QuadPart/10000); return (ui.QuadPart / 10000) - this->msecsBetweenEpochs + this->getLeapSeconds(ui) * 1000; } 

备注

  • 对于无效日期/时间SystemTimeToFileTime将失败

  • CFoo::msecsBetweenEpochs的常量我认为可以在Google上找到; 我从Python(2.7.10)posixmodule.c (实际上有秒数;我只需要乘以1000)

  • 你的实现产生的结果不是很准确(我使用http://www.epochconverter.com作为参考)&#x3002;

  • 根据SystemTimeToFileTime ,时间戳是UTC