【问题标题】:Has anyone implemented __getzone() for IAR Embedded Workbench for MSP430?有人为 MSP430 的 IAR Embedded Workbench 实现了 __getzone() 吗?
【发布时间】:2014-06-25 03:30:56
【问题描述】:

我必须在我的应用程序中处理一些时间转换。我想尽可能地坚持使用标准库函数。现在我使用 time_t 结构作为我的系统时基。但是,某些设备可以将时间同步到我的设备,该时间可能是也可能不是 UTC。此外,我的设备会与另一台设备同步时间,并且该时间将始终为 UTC。

无论如何,我可以询问用户正在同步到我的设备的时间的时区是什么,以及他们是否使用 DST。当我的设备获得时间同步时,我可以使用 mktime 直接生成我的时间戳(我的设备系统时间需要与它们同步的时间相匹配以用于时间戳目的,否则我必须不断进行转换),然后我可以如果我知道我的时间同步来自非 UTC 来源,请使用 gmtime() 获取 UTC 时间。问题是默认情况下 localtime() 和 gmtime() 将返回相同的值,因为默认情况下库会认为它是直接 UTC 时间并且没有 DST 或时区偏移。

所以,我认为解决这个问题的方法是实现并覆盖库的__getzone函数。

来自 EW430_CompilerReference.pdf 的第 106 页

要使 __time32、__time64 和日期函数正常工作,您必须实现 函数时钟、__time32、__time64 和 __getzone。是否使用 __time32 或 __time64 取决于您为 time_t 使用的接口,请参见 time.h,第 304 页。

...

__getzone 的默认实现指定 UTC(协调通用 Time) 作为时区。

Q1:我的推理是否走在正确的轨道上,即实现我想要的最佳方法是实现这个 __getzone 函数?

我犹豫的原因是因为 __getzone 返回的值是一个奇怪的字符串,格式如下:

:[XXX[:YYY[:NNN[:DST[:DST ...]]]]]]

其中 XXX 是标准时区名称(例如 GMT-5 表示 EST),YYY 是夏令时时区名称(例如 GMT-4 表示 EST),NNN 是与 UTC 的数字偏移量,格式为 HHMM(并且可以有a - 符号)。然后 DST 为夏令时规则指定了一个选项字符串,这些选项具有自己令人讨厌的格式。

无论如何,这对我来说现在应该很简单,因为我只担心拥有相同 DST 规则的加拿大和美国。

Q2:有没有人有任何用于形成该字符串的示例代码,以便我可以检查我对此的理解?

【问题讨论】:

    标签: c c99 msp430 iar ctime


    【解决方案1】:

    这是我对 __getzone() 的实现。所以现在我的系统时基将是 UTC。当用户配置我的系统时,如果时间源不提供 UTC,我会询问他们的当地时间。然后,当他们向我的系统提供时间同步时,他们提供的时间将通过调用 MKTIME 转换为 UTC(这将考虑 DST 规则)。然后,当时间返回给用户时,它将通过调用 localtime() 来完成。

    在实现这一点的过程中我们了解到的另一件事是 IAR 的 MKTIME() 实现将调用 __getzone(),但除非将 tm_isdst 设置为“-1”,否则不会考虑 DST 规则。 -1 调用 MKTIME() 根据规则判断是否应用夏令时。

    /*!
    * \brief Overrides default library function __getzone to support different time
    * zones and DST rules.
    * \returns Pointer to a const string containing the timezone + dst rules
    *
    * This function supports all time zones and DST rules for the U.S. and Canada.
    *
    * \par IAR Notes
    * The return value should be a string on the following form:
    * \code
    * :[XXX[:YYY[:NNN[:DST[:DST ...]]]]]
    * \endcode
    * \par
    * Where \b XXX is the standard time-zone name, \b YYY is the daylight
    * savings time-zone name, \b NNN is the time zone offset, and the DSTs
    * are the daylight savings time rules. Daylight savings time will add
    * one hour to the normal time.
    * \par
    * The time zone offset \b NNN is specified as a number relative to UTC,
    * possibly negative (east is positive), on the format HHMM, where HH
    * is hours and MM is minutes.
    * \par
    * The DSTs specifes a set of rules for how daylight savings time is
    * applied. The rules must be sorted in increasing date order starting
    * from the earliest date. The first rule for a specific year will
    * enable DST, the next will disable it, and so on. Each rule is on
    * the following form:
    * \code
    *   [(YYYY)]MMDD[HH][-W|+W]
    * \endcode
    *
    * * \b (YYYY) is the first year the daylight savings rule was applied.
    *      It is optional. If not specified it will default to the same
    *      year as the previous rule or zero if no previous rule.
    * * \b MM is the month number (1-12).
    * * \b DD is the day of the month (1-31).
    * * \b HH is the hour number in a 24-hour day (optional, defaults to 0).
    * * \b +/-W specifies the day of the week the rule takes effect (where
    *      Sunday = 0, Monday = 1, etc). +W means that the rule applies
    *      to the first such day on or after the specified date and -W
    *      strictly before the date. If this is not specified, the rule
    *      will take effect on the exact date, regardless of the day of
    *      the week.
    *
    * \par Example
    * U.S. Eastern Standard time is UTC -5. Eastern Daylight time is UTC -4.
    * Daylight time goes into affect on the second sunday of March at 2:00AM local
    * time. Daylight time ends on the first sunday of November at 2:00AM local
    * time. The law that defines this went into affect in 2007.
    * Therefore here is how the DST string is constructed:
    * | \| | STD Time | \| | DST Time | \| | UTC Offset | \| | DST Rule Year | Month DST Starts | Day DST Starts | Hour DST Starts | Day of Week | \| | Month DST Ends | Day DST Ends | Hour DST Ends | Day of Week |
    * |----|----------|----|----------|----|------------|----|---------------|------------------|----------------|-----------------|-------------|----|----------------|--------------|---------------|-------------|
    * | :  |  XXX     | :  | YYY      | :  | NNN        | :  | (YYYY)        | MM               | DD*            | HH              | +/-W**      | :  | MM             | DD           | HH            | +/-W        |
    * | :  |  GMT-5   | :  | GMT-4    | :  | -0500      | :  | (2007)        | 03               | 08             | 02              | +0          | :  | 11             | 01           | 02            | +0          |
    * - * An 8 for the day means that DST will start around the 8th day of the
    *   month. Or that the +/-W parameter is relative to the 8th day of the month.
    * - ** A + here means that the DST rule will start \b on or \b after the
    *   previously specified day (the 8th). 0 means that it should happen on a
    *   sunday. Therefore if the 8th is a sunday (and the 8th cannot be the first
    *   sunday of the month) then the rule will take affect on that day - or it
    *   will happen on the very next sunday.
    * \par
    * Result:
    * \code
    * :GMT-5:GMT-4:-0500:(2007)030802+0:110102+0
    * \endcode
    *
    * \sa
    * - time_zones - Supported time zones
    */
    const char8_t * __getzone(void)
    {
        const char8_t *current_zone = NULL;
        static const char8_t dst_time_zones[][50] =
        {
            // UTC time
            ":GMT+0:GMT+0:0000:0",
            // Newfoundland Standard Time UTC – 3:30
            ":GMT-3:GMT-2:-0330:(2007)030802+0:110102+0",
            // Atlantic Standard Time, UTC – 4
            ":GMT-4:GMT-3:-0400:(2007)030802+0:110102+0",
            // Eastern Standard Time, UTC – 5
            ":GMT-5:GMT-4:-0500:(2007)030802+0:110102+0",
            // Central Standard Time, UTC – 6
            ":GMT-6:GMT-5:-0600:(2007)030802+0:110102+0",
            // Mountain Standard Time, UTC – 7
            ":GMT-7:GMT-6:-0700:(2007)030802+0:110102+0",
            // Pacific Standard Time, UTC – 8
            ":GMT-8:GMT-7:-0800:(2007)030802+0:110102+0",
            // Alaska Standard Time, UTC – 9
            ":GMT-9:GMT-8:-0900:(2007)030802+0:110102+0",
            // Hawaii-Aleutian Standard Time, UTC – 10
            ":GMT-10:GMT-9:-1000:(2007)030802+0:110102+0"
        };
    
        static const char8_t std_time_zones[][20] =
        {
            // UTC time
            ":GMT+0:GMT+0:0000",
            // Newfoundland Standard Time UTC – 3:30
            ":GMT-3:GMT-2:-0330",
            // Atlantic Standard Time, UTC – 4
            ":GMT-4:GMT-3:-0400",
            // Eastern Standard Time, UTC – 5
            ":GMT-5:GMT-4:-0500",
            // Central Standard Time, UTC – 6
            ":GMT-6:GMT-5:-0600",
            // Mountain Standard Time, UTC – 7
            ":GMT-7:GMT-6:-0700",
            // Pacific Standard Time, UTC – 8
            ":GMT-8:GMT-7:-0800",
            // Alaska Standard Time, UTC – 9
            ":GMT-9:GMT-8:-0900",
            // Hawaii-Aleutian Standard Time, UTC – 10
            ":GMT-10:GMT-9:-1000"
        };
    
        switch(get_config()->time_zone)
        {
            case NST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[NST];
                }
                else
                {
                    current_zone = std_time_zones[NST];
                }
            }
            break;
    
            case AST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[AST];
                }
                else
                {
                    current_zone = std_time_zones[AST];
                }
            }
            break;
    
            case EST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[EST];
                }
                else
                {
                    current_zone = std_time_zones[EST];
                }
            }
            break;
    
            case CST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[CST];
                }
                else
                {
                    current_zone = std_time_zones[CST];
                }
            }
            break;
    
            case MST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[MST];
                }
                else
                {
                    current_zone = std_time_zones[MST];
                }
            }
            break;
    
            case PST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[PST];
                }
                else
                {
                    current_zone = std_time_zones[PST];
                }
            }
            break;
    
            case AKST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[AKST];
                }
                else
                {
                    current_zone = std_time_zones[AKST];
                }
            }
            break;
    
            case HAST:
            {
                if(get_config()->b_dst)
                {
                    current_zone = dst_time_zones[HAST];
                }
                else
                {
                    current_zone = std_time_zones[HAST];
                }
            }
            break;
    
            case UTC:
            default:
                current_zone = std_time_zones[UTC];
            break;
        }
    
        return current_zone;
    }
    

    【讨论】:

    • 感谢您回来展示您所做的事情。 +1
    • Np - 如果您有任何问题,请告诉我!
    【解决方案2】:

    上面的乌克兰规则并不完全正确,因为它不适用于 31 日的星期日。如果您阅读了 getzone.c 中的规则,则 -W 表示此日期之前的星期日。

    +/-W specifies the day of the week the rule takes effect (where
        Sunday = 0, Monday = 1, etc). +W means that the rule applies
        to the first such day on or after the specified date and -W
        strictly before the date. If this is not specified, the rule
        will take effect on the exact date, regardless of the day of
        the week.
    

    正确的规则如下

    char const * __getzone()
    {
        return ":GMT+2:GMT+3:0200:(1996)032503+0:102504+0";
      // Ukraine; rule: (last Sun (March | October) )
    }
    

    【讨论】:

      【解决方案3】:
      char const * __getzone()
      {
              return ":GMT+2:GMT+3:0200:(1996)033103-0:103104-0";
      
      
      
          // Ukraine; rule: (last Sun (March | October) )
      }
      

      【讨论】:

      • 我认为这是有道理的,但请确保我理解:对于该月的某一天,您有 '31' 和 -0 表示这一天。因此,它是最接近该月最后一天的上一个星期日。
      【解决方案4】:

      对于德国,您可以使用:

      char const * __getzone() {
        return ":GMT+1:GMT+2:0100:032502+0:102502+0";
      }
      

      乌克兰的错误或我的错误,但我用实际设备测试了我的并得到了正确的结果。这是我的测试:

      //Forward
      time_t ts = 1490489997L;//26.03.2017-01:59:57 3 seconds before dst
      struct tm* pre = localtime(&ts);
      
      time_t after = ts + 5L;//wait 5 seconds -> 26.03.2017-03:00:02
      struct tm* post = localtime(&after);
      
      //Backward
      time_t ts = 1509238797L;//29.10.2017-02:59:57 3 seconds before dst
      struct tm* pre = localtime(&ts);
      
      time_t after = ts + 5L;//wait 5 seconds -> 29.10.2017-02:00:02
      struct tm* post = localtime(&after);
      

      最好的问候 迈克尔

      【讨论】:

        猜你喜欢
        • 2015-02-01
        • 2013-06-21
        • 2013-10-20
        • 1970-01-01
        • 2021-01-10
        • 2019-02-17
        • 1970-01-01
        • 1970-01-01
        • 2011-02-25
        相关资源
        最近更新 更多