Как вы получаете информацию для произвольного часового пояса в Linux / POSIX? - PullRequest
2 голосов
/ 09 сентября 2010

В идеале, я хотел бы иметь возможность взять имя часового пояса и вызвать функцию для запроса информации о соответствующем часовом поясе (смещение от UTC, смещение летнего времени, даты переключения DST и т. Д.).) в Linux.Тем не менее, я не могу найти способ сделать это.Информация существует в /usr/share/zoneinfo/ в различных бинарных файлах, но я не знаю, как их читать или есть ли способ заставить ОС давать вам информацию в них, вместо того, чтобы читать их самостоятельно.Итак, я ищу способ получить эту информацию.В идеале, была бы функция posix, которая бы делала это для вас, чтобы она работала на системах POSIX, отличных от Linux, но если нет, я бы по крайней мере хотел бы знать правильный путь (или, по крайней мере, лучшийспособ) получить информацию о часовом поясе для произвольного часового пояса в Linux.

Ответы [ 3 ]

3 голосов
/ 09 сентября 2010

Пакет tzcode (находится вместе с данными на ftp: //ftp.iana.org/tz/releases) содержит описание формата tzfile вместе с заголовкомфайл tzfile.h для работы непосредственно с этими данными.

1 голос
/ 08 марта 2017

Новый ответ на старый вопрос.

Обоснование нового ответа: теперь есть современная бесплатная библиотека с открытым исходным кодом, библиотека C ++ 11/14/17 для выполненияthis. 1 Требуется немного установка .Но он переносим через Linux / macOS / Windows.И у него есть полная документация , и даже видео введение .

Вот пример программы для получения информации о конкретном часовом поясе.Я использую свой собственный часовой пояс только в качестве примера.Эта библиотека поддерживает полную базу данных часовых поясов IANA :

#include "tz.h"
#include <iostream>

int
main()
{
    auto zone = date::locate_zone("America/New_York");
    std::cout << *zone << '\n';
    std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
}

Первая строка ищет базу данных по ее имени IANA.

auto zone = date::locate_zone("America/New_York");

Тип возвращаемого значения:date::time_zone const*.Эта функция никогда не сможет вернуть nullptr, хотя она выдаст, если не сможет найти часовой пояс (с отличным what()).

Во второй строке выводится определение часового пояса:

std::cout << *zone << '\n';

Вывод этой строки обычно бесполезен для клиентов этой библиотеки.Это в основном полезно для отладки библиотеки:

America/New_York                   -04:56:02                  LMT        1883 Nov/18                  12:03:58         1883-11-18 17:00:00 UTC   1883-11-18 12:03:58 STD   1883-11-18 12:03:58   00:00      {nullptr, -32768}   {nullptr, 32767}
                                   -05:00:00   US             E%sT       1920 Jan/01                  00:00:00         1920-01-01 05:00:00 UTC   1920-01-01 00:00:00 STD   1920-01-01 00:00:00   00:00   S   {US             1918    1919    Mar/Sun[last]           02:00:00       01:00   D, 1918}   {US             1918    1919    Oct/Sun[last]           02:00:00       00:00   S, 1919}
                                   -05:00:00   NYC            E%sT       1942 Jan/01                  00:00:00         1942-01-01 05:00:00 UTC   1942-01-01 00:00:00 STD   1942-01-01 00:00:00   00:00   S   {NYC            1920    1920    Mar/28                  02:00:00       01:00   D, 1920}   {NYC            1921    1954    Sep/Sun[last]           02:00:00       00:00   S, 1941}
                                   -05:00:00   US             E%sT       1946 Jan/01                  00:00:00         1946-01-01 05:00:00 UTC   1946-01-01 00:00:00 STD   1946-01-01 00:00:00   00:00   S   {US             1942    1942    Feb/09                  02:00:00       01:00   W, 1942}   {US             1945    1945    Sep/30                  02:00:00       00:00   S, 1945}
                                   -05:00:00   NYC            E%sT       1967 Jan/01                  00:00:00         1967-01-01 05:00:00 UTC   1967-01-01 00:00:00 STD   1967-01-01 00:00:00   00:00   S   {NYC            1921    1954    Apr/Sun[last]           02:00:00       01:00   D, 1946}   {NYC            1955    1966    Oct/Sun[last]           02:00:00       00:00   S, 1966}
                                   -05:00:00   US             E%sT       32767 Dec/31                  00:00:00UTC      32767-12-31 00:00:00 UTC   32767-12-30 19:00:00 STD   32767-12-30 19:00:00   00:00   S   {US             1967    1973    Apr/Sun[last]           02:00:00       01:00   D, 1967}   {US             2007    32767    Nov/Sun[1]              02:00:00       00:00   S, 32767}

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

Последняя строка:

std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';

, вероятно, будет наиболее полезной.Это возвращает совокупность sys_info, которая выглядит следующим образом:

struct sys_info
{
    sys_seconds          begin;
    sys_seconds          end;
    std::chrono::seconds offset;
    std::chrono::minutes save;
    std::string          abbrev;
};

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

2016-11-06 06:00:00
2017-03-12 07:00:00
-05:00:00
00:00
EST

Что означает:

  • Эта информациядействует с 2016-11-06 06:00:00 UTC до (но не включая) 2017-03-12 07:00:00 UTC.
  • Смещение UTC для этого периода составляет -5 часов.
  • Это не считается переходом на летнее время (сохранить == 00:00).
  • Сокращение этого периода - EST.

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

Если вы хотите увидеть, как этот результат может выглядеть через 6 месяцев:

std::cout << zone->get_info(std::chrono::system_clock::now() + date::months{6}) << '\n';

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

2017-03-12 07:00:00
2017-11-05 06:00:00
-04:00:00
01:00
EDT

Это все считается низкоуровневым доступом в этой библиотеке.Существует высокоуровневый API, поэтому вам не нужно иметь дело с низкоуровневыми понятиями, такими как текущее смещение UTC.Низкоуровневые вещи есть, если они вам нужны (не скрыты), но не обязательны для общих случаев использования, таких как получение текущего времени в любом конкретном часовом поясе:

using namespace date;
using namespace std::chrono;
std::cout << make_zoned("America/New_York", system_clock::now()) << '\n';

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

2017-03-07 19:26:53.711662 EST

В C ++ 17 из-за шаблонных руководств по выводу приведенная выше строка больше не будет нуждаться в "фабричных функциях" для целей вывода:

std::cout << zoned_time{"America/New_York", system_clock::now()} << '\n';

zoned_timeэто шаблон класса, основанный на продолжительности и выводимый chrono::duration из chrono::time_point (второй аргумент - в моем случае microseconds).

Это полнофункциональная дата / время/ библиотека часовых поясов с низкоуровневым доступом и высокоуровневыми абстракциями (соответствует философии C ++).Корректность и безопасность типов высоко ценятся в этой библиотеке.Это расширение , а не замена библиотеки <chrono>, представленной в C ++ 11.


1 Отказ от ответственности: Я являюсь главнымАвтор этой библиотеки, хотя есть много авторов (за что я благодарен).

1 голос
/ 09 сентября 2010

Нет стандартного способа сделать это.Вы можете посмотреть на ICU .Он требует:

  • Форматирование: форматирование чисел, дат, времени и денежных сумм в соответствии с соглашениями выбранной локали.Это включает в себя перевод названий месяцев и дней на выбранный язык, выбор соответствующих сокращений, правильное упорядочение полей и т. Д. Эти данные также поступают из общего хранилища данных локали.календари предоставляются за пределами традиционного григорианского календаря. Предоставляется полный набор API для расчета часовых поясов ( выделение добавлено ).

...