Как программно преобразовать время от одного часового пояса до другого в C?

Информационные страницы для GNU date команда содержит этот пример:

Например, с GNU date команда можно ли ответить на вопрос "Который час в Нью-Йорке, когда Парижские часы показывают 6:30 31 октября 2004?" при помощи даты, начинающейся 'с TZ = "Европа/Париж"' как показано в следующей расшифровке стенограммы оболочки:

 $ export TZ="America/New_York"
 $ date --date='TZ="Europe/Paris" 2004-10-31 06:30'
 Sun Oct 31 01:30:00 EDT 2004

В этом примере '-дата' операнд начинается со своей собственной установки 'TZ', таким образом, остальная часть того операнда обрабатывается согласно правилам 'Европы/Парижа', рассматривая строку 2004-10-31 06:30 как будто это было в Париже. Однако начиная с вывода date команда обрабатывается согласно полным правилам часового пояса, она использует нью-йоркское время. (Париж был обычно шестью часами перед Нью-Йорком в 2004, но этот пример относится к краткому периоду Хэллоуина, когда разрыв составлял пять часов.)

Я пытаюсь выполнить по существу то же самое программно в C, не звоня date программа миллионы времен. В основном я ищу способ взять произвольную дату и время в одном часовом поясе и преобразовать его в эквивалентную дату и время в другом часовом поясе или непосредственно или через преобразование в и от UTC. Я не забочусь о форматах входного и выходного времени, пока я могу управлять ими использующий стандартные функции (strftime/strptime/mktime/ и т.д.).

date программа, кажется, выполняет этот использующие сложные стандартные программы, внутренние к coreutils пакет, я ищу способ сделать это в C, использующем или стандартные стандартные программы POSIX/Linux или внешнюю библиотеку. Я посмотрел на zoneinfo вполне немного, который казался обещанием, но я не могу найти, что любые библиотеки делают что-либо полезное с ним.

6
задан Robert Gamble 9 March 2010 в 23:28
поделиться

2 ответа

Я придумал решение, которое, кажется, работает в Linux с glibc, я не знаю, насколько это переносимо поведение, любые комментарии о переносимости или лучшем способе решения этой проблемы приветствуются.

convert_time.c (Без проверки ошибок для ясности):

#define _XOPEN_SOURCE
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
  struct tm mytm = {0};
  time_t mytime;
  char buf[100];

  mytm.tm_isdst = -1;
  putenv(argv[1]);
  tzset();
  strptime(argv[2], "%Y-%m-%d %H:%M", &mytm);
  mytime = mktime(&mytm);

  putenv(argv[3]);
  tzset();
  localtime_r(&mytime, &mytm);
  strftime(buf, 100, "%a, %d %b %Y %H:%M:%S %z(%Z)", &mytm);
  puts(buf);

  return 0;
}

Первый аргумент - это часовой пояс источника (на самом деле «TZ = Timezone» для передачи в putenv), второй аргумент - время в указанном формате, последний аргумент - часовой пояс места назначения. Я использую имена часовых поясов zoneinfo, которые glibc поддерживает с помощью базы данных zoneinfo.

Результаты нескольких тестовых углов DST соответствуют результатам эквивалентной команды date , а также этого сайта , который использует базу данных zoneinfo:

$ ./convert_time "TZ=America/New_York" "2005-05-31 06:30" "TZ=America/Indiana/Indianapolis"
Tue, 31 May 2005 05:30:00 -0500(EST)

$ ./convert_time "TZ=America/New_York" "2006-05-31 06:30" "TZ=America/Indiana/Indianapolis"
Wed, 31 May 2006 06:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-10-30 06:30" "TZ=America/New_York"
Sat, 30 Oct 2004 00:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-10-31 06:30" "TZ=America/New_York"
Sun, 31 Oct 2004 01:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-11-01 06:30" "TZ=America/New_York"
Mon, 01 Nov 2004 00:30:00 -0500(EST)
3
ответ дан 17 December 2019 в 04:45
поделиться

Для времени:

  • Получите время по Гринвичу с помощью gmtime
  • Добавьте / вычтите часы из time_t.tm_hour
  • Используйте mktime для перенормировки

Расчет даты будет аналогичным, но немного сложнее.

2
ответ дан 17 December 2019 в 04:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: