Прямой ответ на ваш вопрос
Есть ли у локали 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 ++ знал:
Единый стандарт времени: UTC, который близко моделируется Unix Time .
Один часовой пояс: «местный часовой пояс», установленный пользователем илиадминистратор компьютера.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 часовые пояса и локали не связаны.Это просто бессмысленно.