mar*_*964 20 c++ parsing posix datetime-format
我有一个字符串,应该用ISO 8601格式指定一个日期和时间,其中可能有或没有毫秒,我想struct tm从它获得一个以及可能已指定的任何毫秒值(可以是如果不存在于字符串中则假定为零).
检测字符串格式是否正确,以及将用户指定的字符串转换为struct tm毫秒和毫秒值会涉及什么?
如果它不是毫秒问题,我可能只是使用C函数strptime(),但我不知道当秒包含小数点时该函数的定义行为应该是什么.
最后一点需要注意的是,如果可能的话,我会更喜欢一种解决方案,它不依赖于仅在Boost中找到的函数(但我很乐意接受C++ 11作为先决条件).
输入看起来像:
2014-11-12T19:12:14.505Z
Run Code Online (Sandbox Code Playgroud)
要么
2014-11-12T12:12:14.505-5:00
Run Code Online (Sandbox Code Playgroud)
Z在这种情况下,表示UTC,但可以使用任何时区,并将表示为与GMT的+或 - 小时/分钟偏移.秒字段的小数部分是可选的,但它可能存在的事实是我不能简单地使用strptime()或者std::get_time(),如果在字符串的秒部分中找到这样的字符,则不会描述任何特定的定义行为.
How*_*ant 20
旧问题的新答案.理由:更新的工具.
使用这个免费的开源库,可以解析为a std::chrono::time_point<system_clock, milliseconds>,它具有超过tm能够保持毫秒精度的优势.如果你真的需要,你可以继续使用C API system_clock::to_time_t(在此过程中失去毫秒).
#include "date.h"
#include <iostream>
#include <sstream>
date::sys_time<std::chrono::milliseconds>
parse8601(std::istream&& is)
{
std::string save;
is >> save;
std::istringstream in{save};
date::sys_time<std::chrono::milliseconds> tp;
in >> date::parse("%FT%TZ", tp);
if (in.fail())
{
in.clear();
in.exceptions(std::ios::failbit);
in.str(save);
in >> date::parse("%FT%T%Ez", tp);
}
return tp;
}
int
main()
{
using namespace date;
using namespace std;
cout << parse8601(istringstream{"2014-11-12T19:12:14.505Z"}) << '\n';
cout << parse8601(istringstream{"2014-11-12T12:12:14.505-5:00"}) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
这输出:
2014-11-12 19:12:14.505
2014-11-12 17:12:14.505
Run Code Online (Sandbox Code Playgroud)
请注意,两个输出都是UTC.在parse使用转换的本地时间为UTC -5:00偏移.如果你真的想要本地时间,还有一种方法可以解析为一个被调用的类型date::local_time<milliseconds>,然后解析但忽略偏移量.chrono::minutes如果需要,甚至可以将偏移解析为(使用parse过载minutes&).
解析的精度由chrono::time_point传入的精度控制,而不是由格式字符串中的标志控制.并且偏移可以是风格的+/-hhmm用%z,或+/-[h]h:mm用%Ez.
k06*_*06a 14
您可以使用C的sscanf(http://www.cplusplus.com/reference/cstdio/sscanf/)解析它:
const char *dateStr = "2014-11-12T19:12:14.505Z";
int y,M,d,h,m;
float s;
sscanf(dateStr, "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s);
Run Code Online (Sandbox Code Playgroud)
如果你有std::string它可以这样调用(http://www.cplusplus.com/reference/string/string/c_str/):
std::string dateStr = "2014-11-12T19:12:14.505Z";
sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s);
Run Code Online (Sandbox Code Playgroud)
如果它应该处理不同的时区你需要使用sscanf返回值 - 解析参数的数量:
int tzh = 0, tzm = 0;
if (6 < sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%f%d:%dZ", &y, &M, &d, &h, &m, &s, &tzh, &tzm)) {
if (tzh < 0) {
tzm = -tzm; // Fix the sign on minutes.
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以填写tm(http://www.cplusplus.com/reference/ctime/tm/)结构:
tm time;
time.tm_year = y - 1900; // Year since 1900
time.tm_mon = M - 1; // 0-11
time.tm_mday = d; // 1-31
time.tm_hour = h; // 0-23
time.tm_min = m; // 0-59
time.tm_sec = (int)s; // 0-61 (0-60 in C++11)
Run Code Online (Sandbox Code Playgroud)
它也可以用std::get_time(http://en.cppreference.com/w/cpp/io/manip/get_time)来完成,因为C++11@Barry在评论中提到我如何将一个iso 8601日期(带有可选的毫秒)解析为结构tm在C++中?
解析 ISO 8601* 函数的现代 C++ 版本
* - 此代码仅支持 ISO 8601 的子集。唯一支持的形式是“2020-09-19T05:12:32Z”和“2020-09-19T05:12:32.123Z”。毫秒可以是 3 位数的长度或根本没有毫秒部分,除了 没有时区Z,没有其他更罕见的功能。
#include <cstdlib>
#include <ctime>
#include <string>
#ifdef _WIN32
#define timegm _mkgmtime
#endif
inline int ParseInt(const char* value)
{
return std::strtol(value, nullptr, 10);
}
// ParseISO8601 returns milliseconds since 1970
std::time_t ParseISO8601(const std::string& input)
{
constexpr const size_t expectedLength = sizeof("1234-12-12T12:12:12Z") - 1;
static_assert(expectedLength == 20, "Unexpected ISO 8601 date/time length");
if (input.length() < expectedLength)
{
return 0;
}
std::tm time = { 0 };
time.tm_year = ParseInt(&input[0]) - 1900;
time.tm_mon = ParseInt(&input[5]) - 1;
time.tm_mday = ParseInt(&input[8]);
time.tm_hour = ParseInt(&input[11]);
time.tm_min = ParseInt(&input[14]);
time.tm_sec = ParseInt(&input[17]);
time.tm_isdst = 0;
const int millis = input.length() > 20 ? ParseInt(&input[20]) : 0;
return timegm(&time) * 1000 + millis;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14806 次 |
| 最近记录: |