在 Windows 上将时间字符串转换为纪元时间 [英] Converting time string into epoch time on windows

查看:48
本文介绍了在 Windows 上将时间字符串转换为纪元时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个接口,可以在其中获取文件,文件名是内部数据有效时的时间戳.我正在按顺序处理文件并将它们提供给另一个 API,该 API 的时间为 1970 年 1 月 1 日以来的毫秒数.

I have an interface where I'm getting a file and the file name is the time stamp when the internal data was valid. I'm processing the files in order and providing them to another API which takes the time as milliseconds since Jan 1st, 1970.

因此,我将文件名作为 YYYYMMDD_HHmmSS.sss 格式的字符串输入,并且必须将其转换为时间.我假设处理和收集发生在同一时区等,只需将字符转换为数字即可.

So, I get the file name in as a string in the format of YYYYMMDD_HHmmSS.sss and have to turn this into time. I assume the processing and collection occurred in the same timezone and such and simply have to convert the characters to digits.

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;
}

显然,在这里重新发明轮子.似乎应该为此提供某种功能.另外..我如何解释闰秒?处理闰日已经够烦人了.时间戳都是 2015 年及以后的,而且永远都是,但我认为我不能盲目地添加 26 秒.最终我们将有 27 个或备份到 25 个.在之前的函数中,我已经验证了字符串是正确的格式以及存在的文件和所有爵士乐.我正在使用 VS 2010 在 64 位的 Windows 8.1 编译上运行.

Obviously, reinventing the wheel here. Seems like there should be some sort of function for this. Also.. how do I account for leap seconds? It was annoying enough to deal with leap days. The time stamps are all from 2015 and beyond and always will be, but I don't think I can just blindly add 26 seconds. Eventually we will have 27 or back up to 25. In previous functions I have validated the string to be the right format and the file to exist and all that jazz. I'm running on windows 8.1 compilation for 64 bit using VS 2010.

我已经看过 Convert-epoch-time-string-to-time">Convert Epoch Time string to Time 建议ctime(),但它似乎不处理构造函数甚至任何 get 方法中的毫秒,并且它不接受通用格式的字符串输入.我假设我必须调用一些时间类 CTOR,它会接受文件名字符串,然后调用一些访问器来获取自 1970 年以来的毫秒时间,包括闰秒等.

I've looked at Convert Epoch Time string to Time which suggested ctime(), but it doesn't seem to deal with milliseconds in the constructor or even any of the get methods and it doesn't accept generically formatted string inputs. I'm assuming I've got to call some time classes CTOR which will accept the file name string and then call some accessor on it to get the millisecond time since 1970 including leap seconds and such.

我没有使用 boost,也无权使用它.

I am not using boost and don't have access/permission to use it.

推荐答案

这里的答案适用于任何支持 C++11 或 C++14 的平台.它建立在 C++11 中引入的 std::chrono 库之上.它还使用一个免费的、开源的、跨平台的库来简化算法(MIT 许可证,通常被认为律师友好).

Here is an answer that will work on any platform that supports C++11 or C++14. It builds off of the std::chrono library that was introduced in C++11. It also uses a free, open source, cross platform library to simplify the arithmetic (MIT license which is usually considered lawyer-friendly).

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

If you don't need to take leap seconds into account, you can use this date library, and it will look like this:

#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).

After parsing the numbers out of the filename, it is very simple to create a type-safe std::chrono::time_point which simply holds an integral number of milliseconds since 1970-01-01 (as an int64_t).

如果你想考虑闰秒,你需要这个更高级的库 这是 IANA 时区数据库的完整解析器.您还需要保留为 IANA 时区数据库下载的更新副本http://howardhinnant.github.io/date/tz.html" rel="nofollow">my timezone/leap-second library 解析.但是一旦设置好,转换器的源代码就与上面的非常相似,而且几乎一样简单:

If you want to take leap seconds into account, you need this higher-level library which is a complete parser of the IANA timezone database. You will also need to keep an updated copy of the IANA timezone database downloaded for my timezone/leap-second library to parse. But once set up, the source code for your converter is very similar to that above, and nearly as simple:

#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 来实现:

Both of these functions can be exercised with the following 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 毫秒.

Note that these timestamps are exactly 26,000ms apart.

更新

"tz.h" 标头现在包括一个 parse 函数,它使编写这些函数更容易:

The "tz.h" header now includes a parse function which makes writing these functions much easier:

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));
}

这篇关于在 Windows 上将时间字符串转换为纪元时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆