локаль C ++ имеет связанный часовой пояс?И если да, то как вы к нему обращаетесь? - PullRequest
0 голосов
/ 16 октября 2018

Я провел небольшое исследование по этому вопросу, и у меня есть достаточно убедительные доказательства ответа ДА, а ответа - НЕТ.Я не уверен, в какую сторону верить.

Во-первых, документация, которую я нашел на cppreference.com, и http://www.open -std.org / jtc1 / sc22 / wg21 / docs / paper/2017/n4659.pdf, похоже, ничего об этом не говорят.Я принимаю это как доказательство того, что локали НЕ поддерживают часовой пояс.

Но https://en.cppreference.com/w/cpp/locale/time_get/get и https://en.cppreference.com/w/cpp/locale/time_put/put оба говорят:

% z записывает смещение отUTC в формате ISO 8601 (например, -0430) или без символов, если информация о часовом поясе недоступна.% Z записывает имя или сокращение часового пояса, или без символов, если информация о часовом поясе недоступна (зависит от локали)

, который, как представляется, предполагает наличие ИНОГДА часового пояса, связанного с объектом locale ().

Теперь, если вы возьмете язык en_US.utf8 (один из моих любимых ;-)), тамна самом деле нет никакого разумного часового пояса, который нужно связать (в США есть как минимум 4 или более часовых пояса).

Итак, пришло время эмпирически.

Я запустил код:

#include <iostream>
#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;
int main ()
{
    //  locale l;
    locale                l = locale::classic ();
    tm                    when{};
    const time_put<char>& tmput = use_facet<time_put<char>> (l);
    ostringstream         oss;
    oss.imbue (l);
    static const string   kTZOffsetPattern_{"%z"};
    tmput.put (oss, oss, ' ', &when, kTZOffsetPattern_.c_str (), kTZOffsetPattern_.c_str () + kTZOffsetPattern_.length ());
    cout << oss.str ();
    return 0;
}

В Linux (ubuntu) это дало ожидаемый ответ: +0000 (ОК, я бы тоже не удивился ошибке или пустой строке).

Но в Windows (visual studio.net 2k17 - 15.8.7) - это дает: -0500

Да,как вы уже догадались, я тестирую это в восточном часовом поясе.Но я все еще ожидал бы 0 или пустую строку (особенно для случая locale :: classic ()).

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

Прямой ответ на ваш вопрос

Есть ли у локали C ++ связанный часовой пояс?

Нет.

И не будет в будущем.Как правильно отмечено в вопросе, для многих локалей это не имеет смысла, поскольку географическая область, представленная локалью, может иметь более одного часового пояса.

Стандарт C говорит в спецификации для strftime:

%Z заменяется именем или сокращением часового пояса локали или без символов, если часовой пояс не определяется.[tm_isdst]

Но спецификация C для struct lconv не предоставляет такого члена для хранения этой информации.Спецификация позволяет реализациям добавлять такие члены, но на практике реализации не хранят эту информацию с языковым стандартом C.

Фасеты языкового стандарта C ++ time_put и time_get определяют себя в терминах спецификации Cдля strftime, спецификация POSIX для strptime и некоторые дополнения, которые не включают название часового пояса или сокращение.

Спецификация POSIX для strftime гораздо более детальная, чем спецификация C,и удаляет связь с «locale»:

Z Заменяется на название или сокращение часового пояса или на отсутствие байтов, если информация о часовом поясе не существует.[ tm_isdst]

Спецификация POSIX для struct lconv также гораздо более детальная, чем спецификация C, но все еще не предоставляет хранилище для имени или сокращения часового пояса.

Нобудущее дает надежду на более легкий и эффективный доступ к информации о часовых поясах, по крайней мере, в C ++.

До C ++ 20 C ++ знал:

  1. Единый стандарт времени: UTC, который близко моделируется Unix Time .

  2. Один часовой пояс: «местный часовой пояс», установленный пользователем илиадминистратор компьютера.UTC также может использоваться как местный часовой пояс.

Как указано выше, местный часовой пояс является , а не частью данных языкового стандарта C ++ (или C).Локальные данные включают , включая некоторые календарные данные, такие как:

  • Полные и сокращенные названия дней недели.
  • Полные и сокращенные названия месяцев.
  • Локальные обычные форматы для отображения даты и времени (например, год, месяц, порядок дня).

Смещение UTC (%z) и сокращение часового пояса (%Z) , май быть доступным, но будет храниться как часть данных о местном часовом поясе, а не с текущими данными о региональных настройках, главным образом потому, что между часовыми поясами и региональными настройками нет хорошего взаимно-однозначного отображения.

Объяснение того, что произошло с кодом, представленным в вопросе ОП

В вашем примере: tm when{}; обнуляет всех членов tm, включая tm_isdst.Если tm_isdst равно нулю, это означает, что переход на летнее время, как известно, не действует, для этого конкретного tm.

tm также разрешено иметь элементы, не указанные в стандарте.Популярным расширением является наличие члена tm_gmtoff, который содержит смещение UTC в секундах.Если ваша реализация Linux имеет такого члена, tm when{}; установит для него значение 0 секунд.Если ваша реализация Windows не имеет такого члена, смещение UTC локального часового пояса будет храниться в другом месте.Это объясняет различия, которые вы видите, и обе реализации соответствуют.


Полезная информация о том, как получить доступ к часовым поясам, так как локали C ++ не предоставляют доступ

В проекте спецификации C ++ 20 существует новый тип с именем std::chrono::time_zone.Одна из функций-членов time_zone:

template<class Duration> sys_info get_info(const sys_time<Duration>& st) const;

sys_time<Duration> - это просто system_clock::time_point, но с любой точностью.Таким образом, вы даете time_zone a time_point, и вы получаете sys_info, который содержит все виды полезной информации о , time_zone в , time_point:

struct sys_info
{
    sys_seconds begin;
    sys_seconds end;
    seconds     offset;
    minutes     save;
    string      abbrev;
};
  • Диапазон [begin, end) указывает, в какое время эта информация действительна (это временные точки UTC).
  • offset - текущее смещение UTC time_zone в seconds.
  • Если save != 0min, time_zone в настоящее время считается в дневном режиме.
  • Текущее сокращение time_zone хранится в abbrev.

Кроме того, есть функция, не являющаяся членом:

const time_zone* current_zone();

, которая возвращает указатель на ваш текущийместный часовой пояс.Все это вместе, вот программа на C ++ 20, которая печатает интересную информацию о вашем текущем часовом поясе:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    std::cout << current_zone()->get_info(system_clock::now()) << '\n';
}

Это просто вывод для меня:

2018-03-11 07:00:00
2018-11-04 06:00:00
-04:00:00
01:00
EDT

Есливы можете поэкспериментировать с этой частью C ++ 20, используя C ++ 11, 14 или 17, используя библиотеку часовых поясов Говарда Хиннанта .Эта библиотека помещает все в пространство имен date вместо std::chrono.

Вы также можете получить информацию о любом часовом поясе IANA , например:

#include "date/tz.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << locate_zone("Australia/Sydney")->get_info(system_clock::now()) << '\n';
}

, который просто выводит для меня:

2018-10-06 16:00:00
2019-04-06 16:00:00
11:00:00
01:00
AEDT

Обратите внимание, что даже в C ++ 20 часовые пояса и локали не связаны.Это просто бессмысленно.

0 голосов
/ 21 октября 2018

Соответствующий отрывок стандарта C (на который опирается стандарт C ++) гласит:

% z заменяется смещением от UTC в формате ISO 8601 '' -0430 '' (что означает4 часа 30 минут после UTC, к западу от Гринвича) или без символов, если часовой пояс не определен.[tm_isdst]

% Z заменяется именем или сокращением часового пояса локали или без символов, если часовой пояс не определяется.[tm_isdst]

Обратите внимание, что часовой пояс имя , как говорят, зависит от локали, но часовой пояс смещение не является.

Cppreferenceнужно исправить их неаккуратную формулировку.

0 голосов
/ 16 октября 2018

имеет ли локаль C ++ связанный часовой пояс?

Все аспекты текущего часового пояса определяются реализацией.

Точная формулировка спецификатора %Z из C99 (C ++ делегирует спецификацию функции библиотеки C к стандарту C):

заменяется именем или сокращением часового пояса локали или без символов, если часовой пояс не определяется.

Это кажется немного двусмысленным.Одно из толкований заключается в том, что локаль может влиять на часовой пояс.Другой, который также не совсем соответствует формулировке, - это то, что локаль влияет на название или сокращение часового пояса.Несмотря на это, кажется, нет никакой гарантии, что языковой стандарт не влияет на часовой пояс, хотя я не ожидал бы, что это так.


как вы к нему обращаетесь?

Насколько я знаю, вы не можете использовать стандартные библиотечные утилиты.В любом случае, не напрямую, и нет способа его изменить.

Способ печати текущего часового пояса состоит в использовании спецификаторов формата %z или %Z со значением strftime / put_time / time_put в качествеВы показали.

Существует также способ получить разницу зон в виде целого числа.std::mktime разбирает структуру std::tm на временную метку в соответствии с локалью, тогда как std::gmtime разбирает временную метку на структуру std::tm в соответствии с UTC, поэтому, если вы начнете с эпохи и объедините эти две, вы получитеразница между текущим часовым поясом и UTC в секундах.

std::time_t t = 0;
std::cout << -1 * std::mktime(std::gmtime(&t));
...