C ++ 11 альтернатива localtime_r - PullRequest
35 голосов
/ 06 сентября 2011

C ++ определяет функции форматирования времени в терминах strftime, что требует записи struct tm «разбитого времени». Однако языки C и C ++ 03 не обеспечивают поточно-ориентированного способа получения такой записи; для всей программы есть только один мастер struct tm.

В C ++ 03 это было более или менее нормально, потому что язык не поддерживал многопоточность; он просто поддерживал платформы, поддерживающие многопоточность, которые затем предоставляли такие средства, как POSIX localtime_r.

C ++ 11 также определяет новые утилиты времени, которые взаимодействуют с неразделенным типом 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 Ответ

24 голосов
/ 06 сентября 2011

Вы ничего не упускаете.

Следующий стандарт С (который, вероятно, выйдет в этом году) определен в Приложении K:

struct tm *localtime_s(const time_t * restrict timer,
                       struct tm * restrict result);

И эта новая функция является поточно-ориентированной! Но не становись слишком счастливым. Есть две основные проблемы:

  1. localtime_s является необязательным расширением до C11.

  2. C ++ 11 ссылки C99, а не C11. local_time_s нельзя найти в C ++ 11, необязательно или нет.

Обновление

За 4 года, прошедшие с тех пор, как я ответил на этот вопрос, я также был разочарован плохим дизайном инструментов C ++ в этой области. Я был мотивирован для создания современных инструментов C ++, чтобы справиться с этим:

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

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

...