Я пришел к решению, которое, похоже, работает на 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)