localtime_s и использование strftime, строящие временную строку ISO

Я написал следующую функцию, которая получает момент времени и возвращает строку 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)

Компиляция работает нормально. Спасибо за помощь, чтобы узнать, что здесь происходит. Я думаю, что-то простое, что я не могу заметить …

2

Решение

%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,

4

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

Это хороший вопрос. И ответ Джерри Коффина — хороший ответ (также проголосовал). Этот ответ касается добавления дополнительной информации об альтернативном решении с открытым исходным кодом, которое, как известно, работает в 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
2

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