2016-03-23 10 views
2

I've написал следующую функцию, которая принимает момент времени и возвращает строку ISO с миллисекундах:localtime_s и строительство использования STRFTIME времени строка 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(); 
    } 

I've используется для запуска, что на Linux с localtime() функция без проблем. Теперь я перехожу к Windows/VS2012, и компилятор предлагает изменить localtime() для более безопасного localtime_s(), сделанного немедленно.

После конверсии strftime вызова делает врезаться во время выполнения со следующей ошибкой:

Expression: ("Invalid format directive", 0) 

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

ответ

4

Конверсии %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.

+0

Джерри, I've пытался 'сс << станд :: put_time (& timeinfo, "% FT% TZ") ; 'без успеха также ... Такая же ошибка ... Seens, что'% FT' и '% TZ' вообще не поддерживаются в VS2012.Поэтому я изменился на «% Y-% m-% dT% H:% M:% SZ» и работает с 'strftime' AND std :: put_time. Спасибо за помощь. – Mendes

+0

@Mendes: Да, я бы предположил, что 'put_time' - это нечто большее, чем обертка вокруг' strftime' (или оба используют один и тот же движок), поэтому для любого заданного компилятора они, вероятно, будут поддерживать одни и те же преобразования - переключение между ними является исключительно вопросом удобства, вряд ли повлияет на ваш первоначальный вопрос. –

2

Это хороший вопрос (рекомендуется). И ответ Джерри Коффина - хороший ответ (также одобренный). Этот ответ заключается в добавлении дополнительной информации об альтернативном решении с открытым исходным кодом, которое, как известно, работает на 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 Timezone database и используется здесь для простоты найдите смещение UTC для локального часового пояса. Как только локальная точка времени найдена (хранится как std::chrono::system_clock::time_point), она разбивается на типы полей год/месяц/день/час/минута/секунда/миллисекунда, используя this library, реализация которых находится на том же сайте github.

Я просто побежал и TimePointToISOString и to_local_string на том же time_point и выход был:

2016-03-23T22:54:52.626 
2016-03-23T22:54:52.626