如何以编程方式将时间从一个时区转换为另一个时区?

GNU date命令的信息页面包含以下示例:

例如,使用GNU date命令,您可以回答“当巴黎时钟显示2004年10月31日上午6:30时纽约几点钟的时间?” 通过使用以“TZ =”Europe / Paris“’开头的日期,如以下shell脚本中所示:

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

在此示例中,’ – date’操作数以其自己的’TZ’设置开头,因此该操作数的其余部分根据’Europe / Paris’规则处理,将字符串2004-10-31 06:30视为它在巴黎。 但是,由于date命令的输出是根据整个时区规则处理的,因此它使用纽约时间。 (2004年巴黎通常比纽约早6个小时,但这个例子指的是一个短暂的万圣节时期,当时差距为5小时。)

我试图在C语言中以编程方式完成基本相同的事情,而无需数百万次调用date程序。 基本上我正在寻找一种方法,在一个时区中采取任意日期和时间,并将其转换为另一个时区中的等效日期和时间,可以直接转换为UTC转换。 只要我可以使用标准函数( strftime / strptime / mktime / etc)操作它们,我就不关心输入和输出时间的格式。

date程序似乎使用coreutils包内部的复杂例程来实现这一点,我正在寻找一种方法,使用标准POSIX / Linux例程或外部库在C中执行此操作。 我看了很多看起来很有希望的zoneinfo ,但我找不到任何有用的库。

我提出了一个似乎可以在Linux上使用glibc的解决方案,我不知道这种行为是多么可移植,任何有关可移植性的评论或更好的方法都可以接受。

convert_time.c(没有错误检查以确保清晰度):

 #define _XOPEN_SOURCE #include  #include  #include  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 =时区”传递给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获取GMT时间
  • 从time_t.tm_hour添加/减去小时数
  • 使用mktime重新规范化

日期计算将类似,但稍微复杂一点。

我实际上正在寻找你所做的相同答案,这就是我提出的解决方案。 以下示例程序获取本地系统时间并将其转换为您想要的任何时区。

 // compile: gcc snippet.c // usage: ./a.out Europe/Berlin Pacific/Nauru Asia/Hong_Kong Asia/Kabul #include  #include  #include  #include  #include  int main(int argc, char *argv[]) { char buf[80]; time_t tt = time(NULL); struct tm tm; int i; if (!localtime_r(&tt, &tm)) { printf("Could not convert time_t to tm struct. %s\n", strerror(errno)); return 1; } printf("time_t: %ld\n", tt); printf("timezone: %ld, %s/%s, daylight:%d\n", timezone, tzname[0], tzname[1], daylight); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z %Z", &tm); printf("time: %s\n", buf); for (i = 1; i < argc; ++i) { printf("\ninput: %s\n", argv[i]); snprintf(buf, sizeof(buf), "TZ=%s", argv[i]); putenv(buf); tzset(); printf("\ttimezone: %ld, %s/%s, daylight:%d\n", timezone, tzname[0], tzname[1], daylight); if (!localtime_r(&tt, &tm)) { printf("Could not convert time_t to tm struct. %s\n", strerror(errno)); return 1; } strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z %Z", &tm); printf("\ttime: %s\n", buf); } return 0; }