簡體   English   中英

是否有人為MSP430的IAR嵌入式工作台實現__getzone()?

[英]Has anyone implemented __getzone() for IAR Embedded Workbench for MSP430?

我必須在我的應用程序中處理一些時間轉換。 我想盡可能地使用標准庫函數。 現在,我正在使用time_t結構作為系統時基。 但是,某些設備可以將時間同步到我的設備,並且該時間可能是也可能不是UTC。 另外,我的設備會將時間同步到另一台設備,並且該時間將始終為UTC。

無論如何,我可以問用戶同步到我設備的時間是什么時區,以及他們是否使用DST。 當我的設備獲得時間同步時,我可以使用mktime直接生成我的時間戳(我的設備系統時間需要與它們為時間戳記而同步的時間相匹配,否則我必須不斷進行轉換),然后我可以如果我知道我的時間同步來自非UTC來源,請使用gmtime()獲取UTC時間。 問題是默認情況下localtime()和gmtime()將返回相同的值,因為默認情況下庫將認為它是直接UTC時間,並且沒有DST或時區偏移。

因此,我認為處理此問題的方法是實現並覆蓋庫__getzone函數。

從EW430_CompilerReference.pdf第106頁

要使__time32,__time64和date函數正常工作,必須實現函數clock,__time32,__time64和__getzone。 使用__time32還是__time64取決於用於time_t的接口,請參見time.h,第304頁。

...

__getzone的默認實現將UTC(世界標准時間)指定為時區。

問題1:我的推理是否正確,執行我想要的最佳方法是實現此__getzone函數?

我討厭的原因是因為__getzone返回的值是帶有以下格式的奇怪字符串:

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

其中XXX是標准時區名稱(例如EST的GMT-5),YYY是夏時制時區名稱(例如EST的GMT-4),NNN是相對於UTC的數字偏移量,格式為HHMM(可以有-符號) ),然后DST為夏令時規則指定一串選項,這些規則具有自己令人討厭的格式。

無論如何,這對我來說應該是很直接的,因為我只擔心加拿大和美國的DST規則相同。

Q2:有人有沒有構成該字符串的示例代碼,所以我可以檢查一下我對此的理解?

這是我對__getzone()的實現。 所以現在我的系統時基將是UTC。 當用戶配置我的系統時,如果時間源未提供UTC,我會詢問他們當地時間。 然后,當他們向我的系統提供時間同步時,他們提供的時間將通過調用MKTIME(將考慮DST規則)而轉換為UTC。 然后,當時間返回給用戶時,將通過調用localtime()來完成。

我們在實現此過程的過程中了解到的另一件事是,IAR的MKTIME()實現將調用__getzone(),但是除非將tm_isdst設置為“ -1”,否則不會考慮DST規則。 -1使對MKTIME()的調用確定是否基於規則應用DST。

/*!
* \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;
}

上面的烏克蘭規則不太正確,因為它不適用於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) )
}
char const * __getzone()
{
        return ":GMT+2:GMT+3:0200:(1996)033103-0:103104-0";



    // Ukraine; rule: (last Sun (March | October) )
}

對於德國,您可以使用:

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

最好的問候邁克爾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM