Подтвердить что ты не робот

С++ 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 ); }
4b9b3361

Ответ 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

Все это, конечно, потокобезопасно (это современный С++).