Как мне разобрать строку даты и времени, которая включает дробное время?

У меня есть строка даты и времени:

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

4

Решение

Используя это бесплатная библиотека с открытым исходным кодом 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 может быть неоднозначным. тем не мение вот небольшая статья о том, как использовать эту библиотеку, чтобы сузить аббревиатуру до списка возможных часовых поясов, из которых вы могли бы иметь некоторую специальную логику для выбора уникального часового пояса.

3

Другие решения

Обратите внимание, что 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 ключевых зависимости:

  1. Что часовой пояс всегда заканчивается в характере 'C' (должно быть в верхнем регистре)
  2. Что месячные аббревиатуры подаются в соответствии с одним из тех, что в моем initializer_list
1

По вопросам рекламы [email protected]