当前位置: 首页 > 知识库问答 >
问题:

C timegm将DST转换为未来给定时间的某个时区?

乜胜泫
2023-03-14

我需要在课堂上准确地将UTC时间转换为给定时区的当地时间,无论是否使用DST。我的问题是,当我使用struct tm时,我必须提供tm_isdst成员,或者让它-1自动确定。

from mktime(3) - linux man page:
"The value specified in the tm_isdst field informs mktime() whether or not daylight saving time (DST) is in effect for the time supplied in the tm structure:
a positive value means DST is in effect;
zero means that DST is not in effect;
and a negative value means that mktime() should (use timezone information and system databases to) attempt to determine whether DST is in effect at the specified time.

现在我的问题来了。我与来自世界各地的交易所合作(来自芝加哥、纽约、圣保罗、墨尔本、布宜诺斯艾利斯、约翰内斯堡、上海、首尔……)。我有一张表,上面有每个交易所的时区名称:例如非洲/约翰内斯堡、美国/芝加哥、美国/温尼伯。

我正在研究的数据是一些给定的期货和期权金融工具的到期日。我收到的数据总是UTC格式,我需要转换成交换的本地时间。

长话短说,我当前的实现是在那些不应该使用DST的资产的到期时间上增加1个小时(例如,一台12月到期的仪器,当地时间是美国/芝加哥,应该加上-360分钟偏移量和DST 0,而另一台6月到期的仪器,在同一时区应该加上-360时区偏移量60 DST偏移量,这将是UTC时间戳的-300偏移量。我目前遇到的问题是,例如12月我得到的是上午9:30而不是8:30。)AM,因为UTC时间戳已经包含dst偏移量。

下面是我的转换函数,它显然被破坏了:

#ifdef WIN32
#define timegm _mkgmtime
#endif

SimpleDateTime BusinessDateCalculator::UTC2TZ(const SimpleDateTime& utcDateTime, const int tz_utc_offset, const int tz_dst)
{
    struct tm stm;
    memset(&stm, 0, sizeof(stm));
    stm.tm_year = utcDateTime.getYear() - 1900;
    stm.tm_mon = utcDateTime.getMonth() - 1;
    stm.tm_mday = utcDateTime.getDay();
    stm.tm_hour = utcDateTime.getHour();
    stm.tm_min = utcDateTime.getMinute();
    stm.tm_sec = utcDateTime.getSecond();
    stm.tm_isdst = -1; //see note at the top of this file

    time_t tt = timegm( &stm );
    tt += (tz_utc_offset + tz_dst) * 60;

    struct tm ntm;
    memset(&ntm, 0, sizeof(ntm));
    gmtime_r( &tt, &ntm );
    return SimpleDateTime(ntm.tm_year + 1900, ntm.tm_mon + 1, ntm.tm_mday, ntm.tm_hour, ntm.tm_min, ntm.tm_sec, utcDateTime.getMillisecond());
}

其中SimpleDateTime是具有附加功能的日期时间类,例如从不同的日期/时间格式(SQL、FIX、TimeOnly、DateOnly)进行转换。

我随时都有某个交易所的时区信息。我的问题是,我能否以某种方式提供时区名称,并让timegm执行数据库搜索,并确定DST是否在2014-12-19美国/芝加哥时区生效,从而不将额外的60分钟添加到UTC时间,并在同一天,例如在南半球时区美洲/圣保罗,其有效期至2015年2月16日,对于这个时间戳,它应该增加60分钟,以获得给定日期的正确本地时间。

共有1个答案

黄沈浪
2023-03-14

当您通过IANA标识符(例如“America/Chicago”)引用时区时,它已经包含了所有DST信息和时区的完整历史记录。至少在IANA时区数据库的原始源数据中是这样的。

你(在评论中)提到了Boost。虽然Boost确实支持这些类型的标识符,但它错误地假设它们在时间上是永久固定的。这不是真的,因为世界上的时区一直在改变它们的偏移量和DST规则。考虑到美国在2007年改变了其DST规则,而俄罗斯在今年晚些时候(2014年10月)正在显着改变其时区。如果您查看Boost时区数据文件,您会发现它的格式删除了所有历史记录,只是将每个标识符映射到一组规则。出于这个原因,我建议您不要使用Boost进行本地时区转换。

相反,考虑使用ICU。其中包括时区转换功能,并使用IANA时区数据库的完整副本。您可以在这里阅读更多内容,并在这里查看示例代码。我对C语言不是特别熟练,但似乎可以使用ICU的日历类将UTC时间投影到特定时区的本地时间。

另一种选择是使用GNU C库中内置的时区函数。它还使用完整的时区数据库。本网站上有一个使用IANA/Olson标识符转换UTC到当地时间的简单示例,我还发布了以下内容:

/*
    C source code example: Convert UTC to local time zone, considering daylight
    savings. Uses mktime(), gmtime() and localtime(). Works for dates between
    years 1902 and 2037. Should compile and run with any recent GNU C if your
    tzdata is healthy. Written by Robert Larsson  http://rl.se

    Code put in public domain; do what you want with it.
*/

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

#define     DESTZONE    "TZ=Europe/Stockholm"       // Our destination time zone

int main(void)
{
    struct tm   i;
    time_t      stamp;                              // Can be negative, so works before 1970

    putenv("TZ=UTC");                               // Begin work in Greenwich …

    i.tm_year = 2009-1900;                          // Populate struct members with
    i.tm_mon  = 8-1;                                // the UTC time details, we use
    i.tm_mday = 29;                                 // 29th August, 2009 12:34:56
    i.tm_hour = 12;                                 // in this example
    i.tm_min  = 34;
    i.tm_sec  = 56;

    stamp = mktime(&i);                             // Convert the struct to a Unix timestamp

    putenv(DESTZONE);                               // Switch to destination time zone

    printf("UTC  : %s", asctime(gmtime(&stamp)));
    printf("Local: %s", asctime(localtime(&stamp)));

    return 0;                                       // That’s it, folks.
}
 类似资料:
  • 问题内容: 我有一个字符串类型就像一个计时:和是。 如何使用Java 8 datetime API将此时间信息转换为与UTC时间相对应的时间? 还需要考虑DST的东西。 问题答案: 您正在Java8 中寻找类-带有时区的完整日期时间和与UTC /格林威治标准时间的偏移量。就设计而言,此类应主要视为a 和a 的组合。的是一个至关重要的,但次要的,一条信息,用于确保所述类表示瞬间,特别是在夏令重叠。

  • 问题内容: 我需要预测下一个至少2个时区转换何时将用于特定时区。 Java 8特别提供了新的API 。看起来确实正是我需要的东西,但是它没有列出“澳大利亚/悉尼” 2010年以后的任何东西。 确定下两个时区转换的日期/时间/偏移量的最可靠方法是什么? 问题答案: 该方法不会列出所有过渡,直到无限远(显然)为止。这将获得以下两个过渡: 输出: 下一次转换时间:2016-10-02T03:00 + 1

  • 我将要求用户输入一个特定时间:上午10点、下午12点30分、下午2点47分、上午1点09分、下午5点等。我将使用获取用户的输入。 如何将该解析/转换为对象?Java中是否有任何内置函数允许我这样做?

  • 我想将时间戳转换为。 这是我到目前为止已经实现的,但是它给了我错误的月份 任何帮助将不胜感激。

  • 问题内容: 我想将此GMT时间戳转换为GMT + 13: 我已经尝试过约100种不同的DateFormat,TimeZone,Date,GregorianCalendar等组合,以尝试执行此非常基本的任务。 这段代码可以满足我在当前时间的需求: 但是我想要的是设置时间而不是使用当前时间。 我发现任何时候我都尝试这样设置时间: 使用本地计算机的TimeZone。这是为什么?我知道,当“ new Da