Я написал следующую функцию, которая получает момент времени и возвращает строку ISO с миллисекундами:
std::string TimePointToISOString(const std::chrono::time_point<std::chrono::system_clock>& time)
{
std::time_t rawTime = std::chrono::system_clock::to_time_t(time);
struct tm timeinfo;
localtime_s(&timeinfo, &rawTime);
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch());
std::size_t frac_seconds = ms.count() % 1000;
char buffer[32];
std::strftime(buffer, 32, "%FT%TZ", &timeinfo);
std::string bufferStr(buffer);
std::stringstream ss;
ss << bufferStr.substr(0, 19) << "." << std::setw(3) << std::setfill ('0') << frac_seconds << bufferStr.substr(20);
return ss.str();
}
Я привык запускать это на Linux с localtime()
работать без проблем на всех. Сейчас я перехожу на Windows / VS2012 и компилятор предлагает изменить localtime()
для безопасности localtime_s()
, сделано немедленно.
После преобразования strftime
вызов вызывает сбой во время выполнения со следующей ошибкой:
Expression: ("Invalid format directive", 0)
Компиляция работает нормально. Спасибо за помощь, чтобы узнать, что здесь происходит. Я думаю, что-то простое, что я не могу заметить …
%F
а также %T
преобразования были добавлены в C99, а VS 2012 поддерживает только C89.
Хотя он все еще не пытается поддерживать весь C99, я считаю, что в VS 2015 добавлено достаточно больше (особенно библиотечных функций C99, которые также являются частью C ++ 11), что с ним должно работать нормально.
Если вам нужно продолжать использовать более старый компилятор / библиотеку,% F и% T являются в основном «горячими клавишами» для некоторых форматов, которые уже поддерживаются в C89. Если я правильно читаю требования, следующее должно быть эквивалентным:
std::strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
Кроме того, если ваш компилятор поддерживает C ++ 11, его проще и понятнее использовать std::put_time
вместо strftime
,
Это хороший вопрос. И ответ Джерри Коффина — хороший ответ (также проголосовал). Этот ответ касается добавления дополнительной информации об альтернативном решении с открытым исходным кодом, которое, как известно, работает в VS-2013 и более поздних версиях, gcc и clang Эта альтернатива будет производить идентичный вывод на TimePointToISOString
, Чтобы выделить его, я дал ему другое имя: to_local_string
:
std::string
to_local_string(const std::chrono::system_clock::time_point& time)
{
using namespace date;
auto zone = current_zone();
auto local = floor<std::chrono::milliseconds>(zone->to_local(time).first);
auto dp = floor<days>(local);
year_month_day ymd = dp;
std::stringstream ss;
ss << ymd << 'T' << make_time(local-dp);
return ss.str();
}
Это использует анализатор базы данных часовых поясов, найденный здесь:
https://github.com/HowardHinnant/date
и задокументировано здесь:
http://howardhinnant.github.io/tz.html
Это парсер База данных часовых поясов IANA, и используется здесь, чтобы просто найти смещение UTC для местного часового пояса. Как только локальная точка времени найдена (сохраняется как std::chrono::system_clock::time_point
), он разбит на поля типа год / месяц / день / час / минута / секунда / миллисекунда, используя эта библиотека чья реализация находится на том же сайте github.
Я просто побежал оба TimePointToISOString
а также to_local_string
в тот же момент времени и результат был:
2016-03-23T22:54:52.626
2016-03-23T22:54:52.626