Стандарт C гласит в 7.27.1 Компоненты времени:
Структура tm
должна содержать не менее следующих членов в любом порядке. Семантика членов и их нормальные диапазоны выражены в комментариях. 318)
int tm_sec; // seconds after the minute — [0, 60]
int tm_min; // minutes after the hour — [0, 59]
int tm_hour; // hours since midnight — [0, 23]
int tm_mday; // day of the month — [1, 31]
int tm_mon; // months since January — [0, 11]
int tm_year; // years since 1900
int tm_wday; // days since Sunday — [0, 6]
int tm_yday; // days since January 1 — [0, 365]
int tm_isdst; // Daylight Saving Time flag
(выделение мое)
То есть реализацииразрешено добавлять дополнительных членов к tm
, как вы обнаружили с glibc/time/bits/types/struct_tm.h
. Спецификация POSIX имеет почти идентичную формулировку.
В результате %Z
(или даже %z
) нельзя считать переносимым в strftime
. Спецификация для %Z
отражает это:
%Z
заменяется именем или сокращением часового пояса локали, или никакими символами, если часовой пояс не определяется. [tm_isdst]
То есть поставщикам разрешено поднимать руки и просто говорить: «Часовой пояс не был определен, поэтому я вообще не выводил никаких символов».
Мое мнение: API синхронизации C - беспорядок.
Я пытаюсь улучшить готовящийся стандарт C ++ 20 в библиотеке <chrono>
.
ЧерновикСпецификация C ++ 20 изменяет это с «без символов» на исключение, которое выдается, если сокращение time_zone
недоступно:
http://eel.is/c++draft/time.format#3
Если явно не запрошено,Результат форматирования хронографического типа не содержит аббревиатуру часового пояса и информацию о смещении часового пояса. Если информация доступна, спецификаторы преобразования %Z
и %z
отформатируют эту информацию (соответственно). [ Примечание: Если информация недоступна и спецификатор преобразования %Z
или %z
появляется в chrono-format-spec , возникает исключение типа format_error
, как описано выше. - конечная нота ]
За исключением того, что в приведенном выше абзаце описывается не C * strftime
, а новая функция format
, которая работает с типами std::chrono
, а не tm
. Кроме того, появился новый тип: std::chrono::zoned_time
(http://eel.is/c++draft/time.zone.zonedtime), который всегда имеет доступное сокращение time_zone
(и смещение) и может быть отформатирован с помощью упомянутой выше функции format
.
Пример кода:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
auto now = system_clock::now();
std::cout << format("%Z\n", zoned_time{current_zone(), now}); // HKT (or whatever)
std::cout << format("%Z\n", zoned_time{"Asia/Hong_Kong", now}); // HKT or HKST
std::cout << format("%Z\n", zoned_time{"Etc/UTC", now}); // UTC
std::cout << format("%Z\n", now); // UTC
}
(Отказ от ответственности: Окончательный синтаксис строки форматирования в функции format
, вероятно, будет немного отличаться, но функциональность будет там.)
Если вы хотите поэкспериментировать с предварительным просмотром этой библиотеки, она является бесплатной и с открытым исходным кодом здесь: https://github.com/HowardHinnant/date
Требуется некоторая установка: https://howardhinnant.github.io/date/tz.html#Installation
В этомДля предварительного просмотра вам потребуется использовать заголовок "date/tz.h"
, а содержимое библиотеки находится в namespace date
вместо namespace std::chrono
.
Библиотека предварительного просмотра может использоваться с C ++ 11 или более поздней версией.
zoned_time
настроен на std::chrono::duration
, который задает точность момента времени, и выводится в приведенном выше примере кода, используя функцию CTAD C ++ 17 . Если выиспользуя эту библиотеку предварительного просмотра в C ++ 11 или C ++ 14, синтаксис would будет выглядеть примерно так:
cout << format("%Z\n", zoned_time<system_clock::duration>{current_zone(), now});
Или существует фабричная функция помощника, которая не предлагается для стандартизации и которая сделает за вас вывод:
cout << format("%Z\n", make_zoned(current_zone(), now));
(# CTAD_eliminates_factory_functions)