Информационные страницы для 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 вполне немного, который казался обещанием, но я не могу найти, что любые библиотеки делают что-либо полезное с ним.
Я придумал решение, которое, кажется, работает в 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)
Для времени:
gmtime
mktime
для перенормировки Расчет даты будет аналогичным, но немного сложнее.