Как я могу преобразовать имя часового пояса IANA в смещение UTC в настоящее время в Ubuntu C / Stack Overflow

В Python или Java вы можете получить смещение UTC (в настоящее время), учитывая имя часового пояса IANA (например, «America / Los_Angeles»). Увидеть Получить смещение UTC от имени часового пояса в python например.

Как вы можете сделать то же самое, используя C / C ++ в Ubuntu 14.04?

РЕДАКТИРОВАТЬ: Предпочтительно в поточно-ориентированном виде (без переменных окружения).

1

Решение

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

Один из способов найти смещение — это потратить время, которое вас интересует, передать его localtime() функции, а затем посмотреть на tm_gmtoff поле. Сделайте это с TZ Переменная окружения установлена ​​на интересующее вас имя зоны. Вот пример, который делает это для текущего времени:

#include <time.h>
#include <stdio.h>

int main()
{
setenv("TZ", "America/Los_Angeles", 1);
time_t t = time(NULL);
struct tm *tmp = localtime(&t);
printf("%ld\n", tmp->tm_gmtoff);
}

На данный момент это печатает -25200, указывая, что Лос-Анджелес составляет 25200 секунд, или 420 минут, или 7 часов к западу от Гринвича. Но на следующей неделе (фактически завтра) США выходят из DST, после чего этот код начнет печатать -28800.

Это не гарантируется, так как tm_gmtoff поле не переносимое Но я верю, что все версии Linux будут иметь его. (Возможно, вам придется скомпилировать с -D_BSD_SOURCE или что-то, или ссылаться на поле как __tm_gmtoff, Но по моему опыту, он работает по умолчанию, так как tm_gmtoff.)

Другой способ состоит в том, чтобы идти вперед и назад с gmtime а также mktime, как описано в ответе Сэма Варшавчика.


Приложение: Вы спрашивали о том, чтобы не использовать переменные окружения. Есть способ, но, к сожалению, он еще менее стандартен. Есть функции BSD tzalloc а также localtime_rz которые делают работу, но они не существуют в Linux. Вот как выглядит код:

    timezone_t tz = tzalloc("America/Los_Angeles");
if(tz == NULL) return 1;
time_t t = time(NULL);
struct tm tm, *tmp = localtime_rz(tz, &t, &tm);
printf("%ld\n", tmp->tm_gmtoff);

Для меня это печатает -28800 (потому что PDT вернулся к PST всего несколько минут назад).

Если бы у вас было это, вы могли бы также использовать localtime_rz вместе с mktime в ответе Сэма Варшавчика. И, конечно же, библиотека Говарда Хиннанта, очевидно, ориентирована на многопотоковое исполнение и не требует перебора TZ совсем.

РЕДАКТИРОВАТЬ (OP): код для localtime_rz а также tzalloc можно загрузить с https://www.iana.org/time-zones и работает на Ubuntu 14.04.

2

Другие решения

Вы могли бы использовать это бесплатная библиотека с открытым исходным кодом C ++ 11/14 сделать это так:

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

int
main()
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned("America/Los_Angeles", system_clock::now());
std::cout << zt.get_info().offset << '\n';
}

Это в настоящее время выводит:

-25200s

Или вы можете отформатировать его по-другому, как это:

    std::cout << make_time(zt.get_info().offset) << '\n';

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

-07:00:00

Заводская функция make_zoned создает zoned_time используя имя IANA «America / Los_Angeles» и текущее время из std::chrono::system_clock, zoned_time имеет член получатель, чтобы получить информацию о часовом поясе в это время. Информация типа называется sys_info которая содержит все виды полезной информации, включая текущее смещение UTC.

Смещение UTC сохраняется как std::chrono::seconds, Заголовок "chrono_io.h" будет форматировать durations для потоковой передачи. Или make_time Утилита может быть использована для форматирования продолжительности в hh:mm:ss,

Программа выше является поточно-ориентированной. Вам не нужно беспокоиться о том, что какой-то другой процесс изменит TZ из-под вас или каким-либо другим образом изменит текущий часовой пояс компьютера. если ты хочу информация о текущем часовом поясе, которая также доступна, просто используйте current_zone() на месте "America/Los_Angeles",

Если вы хотите исследовать другие времена, это так же просто. Например, начиная с 6 ноября 2016 года в 2 часа по местному времени:

    auto zt = make_zoned("America/Los_Angeles", local_days{nov/6/2016} + 2h);

Выход изменяется на:

-28800s
-08:00:00

Более подробная информация об этой библиотеке была представлена ​​на Cppcon 2016 и доступна для просмотра здесь:

https://www.youtube.com/watch?v=Vwd3pduVGKY

2

использование gmtime()сначала преобразовать текущее время в UTC, а затем использовать mktime() пересчитать время эпохи, затем сравнить результат с реальным временем эпохи.

gmtime() рассчитывает struct tm в UTC, пока mktime() предполагает, что struct tm представляет текущее местное календарное время. Таким образом, выполняя это круговое вычисление, вы косвенно вычисляете текущее смещение часового пояса.

Обратите внимание, что mktime() может вернуть ошибку, если struct tm не может быть преобразовано в время эпохи, которое произойдет во время определенных переходов между стандартным временем и альтернативным временем. Вам решать, что это значит в вашем случае.

Рецепт выглядит примерно так:

time_t t = time(NULL);
struct tm *tmp = gmtime(&t);
time_t t2 = mktime(tmp);
int offset = t - t2;

Увидеть документация этих библиотечных функций для дополнительной информации.

Чтобы использовать определенный часовой пояс, либо установите TZ переменная окружения, или вы можете попробовать использовать localtime_rz как в ответе Стива Саммита. Как уже упоминалось, будьте осторожны, что mktime иногда может вернуть -1 для необратимых времен.

1
По вопросам рекламы [email protected]