Я хочу преобразовать строку в формате «20160907-05: 00: 54.123» в миллисекунды. Я знаю, что strptime недоступен в Windows, и я хочу запускать свою программу как в Windows, так и в Linux. Я также не могу использовать сторонние библиотеки. Я могу разметить строку и преобразовать ее. Но есть ли для этого более элегантный способ, например, с помощью strptime?

3
Will_Panda 7 Сен 2016 в 16:40

3 ответа

Лучший ответ

Учитывая формат вашей строки, довольно легко ее проанализировать следующим образом (хотя регулярное выражение или get_time может быть более элегантным):

tm t;
t.tm_year = stoi(s.substr(0, 4));
t.tm_mon = stoi(s.substr(4, 2));
t.tm_mday = stoi(s.substr(6, 2));
t.tm_hour = stoi(s.substr(9, 2));
t.tm_min = stoi(s.substr(12, 2));
t.tm_sec = 0;
double sec = stod(s.substr(15));

Узнать время, прошедшее с начала эпохи, можно с помощью mktime:

mktime(&t) + sec * 1000

Обратите внимание, что дробные секунды нужно обрабатывать иначе - к сожалению, tm имеет только целые секунды.

(Полный код см. здесь.)


Изменить

Как правильно отмечают Майн и Панайотис Канавос в комментариях, Visual C ++ явно поддерживает get_time в течение некоторого времени, и с ним он намного короче (хотя, обратите внимание, что дробные секунды должны обрабатываться таким же образом).

3
Ami Tavory 7 Сен 2016 в 14:46

Жаль, что нет сторонних библиотек, потому что вот одна (лицензия MIT ), который представляет собой всего лишь один заголовок, работает в Linux и Windows и без проблем обрабатывает миллисекунды:

#include "date.h"
#include <iostream>
#include <sstream>

int
main()
{
    date::sys_time<std::chrono::milliseconds> tp;
    std::istringstream in{"20160907-05:00:54.123"};
    date::parse(in, "%Y%m%d-%T", tp);
    std::cout << tp.time_since_epoch().count() << '\n';
}

Это выводит:

1473224454123

Проверка ошибок сделана за вас. Поток будет fail(), если дата недействительна.

date::sys_time<std::chrono::milliseconds> - это псевдоним типа для std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>. Т.е. это из семейства system_clock::time_point, просто точность milliseconds.

Полностью задокументировано:

https://howardhinnant.github.io/date/date.html

Нет ничего более элегантного, чем это.

4
Howard Hinnant 7 Сен 2016 в 20:12

А как насчет std::sscanf?

#include <iostream>
#include <cstring>

int main() {
    const char *str_time = "20160907-05:00:54.123";
    unsigned int year, month, day, hour, minute, second, miliseconds;

    if (std::sscanf(str_time, "%4u%2u%2u-%2u:%2u:%2u.%3u", &year, &month,
               &day, &hour, &minute, &second,&miliseconds) != 7)
    {
        std::cout << "Parse failed" << std::endl;
    } 
    else
    {
        std::cout << year << month << day << "-" << hour << ":" 
                  << minute << ":" << second << "." << miliseconds
                  << std::endl;
    }
}

Вывод (ideone): 201697-5: 0: 54.123.

Однако вы должны убедиться, что введенные данные действительны (например, день может быть в диапазоне [0,99]).

5
Shmuel H. 7 Сен 2016 в 15:36