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

时间:2010-03-09 23:28:48

标签: c datetime time timezone

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

  

例如,使用GNU date   命令你可以回答这个问题   “在纽约几点钟的时候   巴黎时钟显示10月6:30   2004年3月31日?“通过使用日期开始   用`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
     

在这个例子中,' - 日'   操作数以自己的'TZ'开头   设置,所以该操作数的其余部分   按照处理   '欧洲/巴黎'的规则,对待   字符串2004-10-31 06:30就像它一样   在巴黎。但是,自从   date命令的输出是   根据整体处理   时区规则,它使用纽约   时间。 (巴黎通常是六个小时   2004年领先于纽约,但这一点   例子是指一个简短的万圣节   差距是五个小时的时期。)

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

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

3 个答案:

答案 0 :(得分:3)

我想出了一个似乎在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测试边案例的结果对应于使用zoneinfo数据库的等效date命令和this站点的结果:

$ ./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)

答案 1 :(得分:2)

时间:

  • 使用gmtime
  • 获取GMT时间
  • 从time_t.tm_hour
  • 添加/减去小时数
  • 使用mktime重新规范化

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

答案 2 :(得分:0)

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

// compile: gcc snippet.c
// usage: ./a.out Europe/Berlin Pacific/Nauru Asia/Hong_Kong Asia/Kabul
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

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;
}