У меня есть строка даты и времени:
20: 48: 01.469 UTC 31 марта 2016
Я хотел бы преобразовать это строковое представление времени в struct tm
с помощью strptime
, но моя строка формата не работает.
Есть ли спецификатор формата за доли секунды? возможно %S
, %s
, или что-то другое?
Фрагмент кода ниже:
tm tmbuf;
const char *str = "20:48:01.469 UTC MAR 31 2016"const char *fmt = "%H:%M:%s %Z %b %d %Y";
strptime(str,fmt,&tmbuf);
Используя это бесплатная библиотека с открытым исходным кодом C ++ 11/14, Вот еще один способ разобрать дробные секунды:
#include "tz.h"#include <iostream>
#include <sstream>
int main()
{
using namespace date;
using namespace std::chrono;
std::istringstream str("20:48:01.469 UTC MAR 31 2016");
sys_time<milliseconds> tp;
parse(str, "%T %Z %b %d %Y", tp);
std::cout << tp << '\n';
}
Выход:
2016-03-31 20:48:01.469
Т.е. с этим инструментом %S
а также %T
просто работай. Точность контролируется не с флагами, а с точностью std::chrono::time_point
,
Если вы хотите узнать, какое сокращение часового пояса вы проанализировали, это также возможно:
std::istringstream str("20:48:01.469 UTC MAR 31 2016");
sys_time<milliseconds> tp;
std::string abbrev;
parse(str, "%T %Z %b %d %Y", tp, abbrev);
std::cout << tp << ' ' << abbrev << '\n';
Выход:
2016-03-31 20:48:01.469 UTC
При этом, эта библиотека построена на вершине std::get_time
и, таким образом, имеет ту же проблему переносимости, на которую превосходный (и одобренный) ответ Джонатана намекает: только libc ++ в настоящее время анализирует названия месяцев без учета регистра. Надеюсь, что это изменится в недалеком будущем.
Отчет об ошибках в libstdc ++.
VSO # 232129 сообщение об ошибке.
Если вам приходится иметь дело с часовыми поясами, отличными от UTC, в общем, для этого не существует надежного метода, потому что в любой момент более одного часового пояса могут использовать одно и то же сокращение. Таким образом, смещение UTC может быть неоднозначным. тем не мение вот небольшая статья о том, как использовать эту библиотеку, чтобы сузить аббревиатуру до списка возможных часовых поясов, из которых вы могли бы иметь некоторую специальную логику для выбора уникального часового пояса.
Обратите внимание, что tm
член, обозначающий наименьшее приращение времени tm_sec
, который является int
который определяется только в диапазоне:
Секунды после минуты [0,60] после C ++ 11
Таким образом, вы не сможете хранить доли секунды в tm
, вам просто нужно отбросить число после десятичного разделителя.
По предложению Карстена Купа Вы можете просто прочитать год дважды, второй %Y
топнет первым:
auto fmt = "%H:%M:%S.%Y %Z %b %d %Y";
Тем не менее, я бы порекомендовал против с помощью strptime
это функция POSIX, использующая стандартную функцию, такую как get_time
было бы предпочтительнее. Это имеет один незначительный недостаток; get_time
не знает часовых поясов, но не знает tm
, за исключением tm_isdst
какой:
Летнее время флаг. Значение положительное, если действует DST, ноль, если нет, и отрицательное, если информация недоступна
Таким образом, вы можете назначить tm_isdst
независимо, если вы продолжаете что-то вроде этого:
tm tmbuf;
stringstream str("20:48:01.469 UTC MAR 31 2016");
str >> get_time(&tmbuf, "%H:%M:%S.%Y UTC %b %d %Y");
мой get_time
ответ был немного лицемерным, потому что пока я говорил о важности стандартизации, я мог заставить его работать только на libc ++. Поэтому я подумал, что выложу более универсальное решение, которое также откажется от часового пояса, поэтому вам снова нужно будет установить tm_isdst
независимо:
tm tmbuf{};
stringstream str("20:48:01.469 UTC MAR 31 2016");
string tm_mon;
str >> get_time(&tmbuf, "%T");
str.ignore(std::numeric_limits<std::streamsize>::max(), 'C');
str >> tm_mon >> get_time(&tmbuf, "%d %Y");
for (const auto& i : { "JAN"s, "FEB"s, "MAR"s, "APR"s, "MAY"s, "JUN"s, "JUL"s, "AUG"s, "SEP"s, "OCT"s, "NOV"s, "DEC"s }) {
if (equal(cbegin(tm_mon), cend(tm_mon), cbegin(i), cend(i), [](const unsigned char a, const unsigned char b) { return toupper(a) == b; })) break;
++tmbuf.tm_mon;
}
Это имеет 2 ключевых зависимости:
'C'
(должно быть в верхнем регистре)initializer_list