С++ 11 альтернатива localtime_r
С++ определяет функции форматирования времени в терминах strftime
, для чего требуется запись struct tm
"break down time". Однако языки C и С++ 03 не обеспечивают потокобезопасный способ получения такой записи; для всей программы есть только один мастер struct tm
.
В С++ 03 это было более или менее нормально, потому что язык не поддерживал многопоточность; он просто поддерживал платформы, поддерживающие многопоточность, которые затем предоставляли такие объекты, как POSIX localtime_r
.
С++ 11 также определяет новые утилиты времени, которые взаимодействуют с типом non-broken-down time_t
, который будет использоваться для повторной инициализации глобального struct tm
. Но получение time_t
не является проблемой.
Мне что-то не хватает или эта задача все еще требует опоры на POSIX?
РЕДАКТИРОВАТЬ: Ниже приведен код обходного кода. Он поддерживает совместимость с многопоточными средами, которые обеспечивают ::localtime_r
и однопоточные среды, которые обеспечивают только std::localtime
. Он может быть легко адаптирован для проверки других функций, таких как posix::localtime_r
или ::localtime_s
или что-то-вы.
namespace query {
char localtime_r( ... );
struct has_localtime_r
{ enum { value = sizeof localtime_r( std::declval< std::time_t * >(), std::declval< std::tm * >() )
== sizeof( std::tm * ) }; };
template< bool available > struct safest_localtime {
static std::tm *call( std::time_t const *t, std::tm *r )
{ return localtime_r( t, r ); }
};
template<> struct safest_localtime< false > {
static std::tm *call( std::time_t const *t, std::tm *r )
{ return std::localtime( t ); }
};
}
std::tm *localtime( std::time_t const *t, std::tm *r )
{ return query::safest_localtime< query::has_localtime_r::value >().call( t, r ); }
Ответы
Ответ 1
Вы ничего не пропустите.
Следующий стандарт C (ожидается, вероятно, в этом году) определен в Приложении K:
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
И эта новая функция является потокобезопасной! Но не слишком счастливы. Существуют две основные проблемы:
-
localtime_s
является необязательным расширением до C11.
-
С++ 11 ссылок C99, а не C11. local_time_s
не может быть найден в С++ 11, необязательно или нет.
Обновление
В течение 4 лет с тех пор, как я ответил на этот вопрос, меня также разочаровал плохой дизайн инструментов С++ в этой области. Я был заинтересован в создании современных инструментов С++ для решения этой проблемы:
http://howardhinnant.github.io/date/tz.html
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
auto local_time = make_zoned(current_zone(), std::chrono::system_clock::now());
std::cout << local_time << '\n';
}
Это просто для меня:
2015-10-28 14: 17: 31.980135 EDT
local_time
- это спаривание std::chrono::system_clock::time_point
и time_zone
, указывающее местное время.
Существуют утилиты для разбиения std::chrono::system_clock::time_point
на понятные для человека типы полей, такие как год, месяц, день, час, минута, секунда и подсегменты. Вот презентация, посвященная тем (частицам, не относящимся к часовому поясу):
https://www.youtube.com/watch?v=tzyGjOm8AKo
Все это, конечно, потокобезопасно (это современный С++).