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

I need to deal with some time conversions in my application. I would like to use standard library functions as much as possible. Right now I am using the time_t structure as my time base. However, some devices may sync the time with my device and this time may or may not be UTC. In addition, my device will sync the time with the other device, and this time will always be UTC.

Anyway, I can ask the user what the timezone has in the time that syncs with my device and if they are using DST. When my device gets timestamped, I can use mktime to directly create my timestamp (my device system time must match the time they sync for timestamping purposes, otherwise I have to do conversions all the time) and then from that I can use gmtime () to get UTC time if I know my time sync came from a non-UTC source. The default problem localtime () and gmtime () will return the same value, because the library by default thinks it is in direct UTC time and there are no DST or timezone offsets.

So, I think the way to handle this is to implement and overwrite the library of the __getzone function.

From page 106 of EW430_CompilerReference.pdf

For the __time32, __time64, and date functions to work, you must implement the function clock, __time32, __time64, and __getzone. Whether you use __time32 or __time64 depends on which interface you are using for time_t, see time.h, page 304.

...

The default implementation of __getzone sets UTC (Coordinated Universal Time) as the time zone by default.

Q1: I am on the right track in my reasoning that the best way to do what I want is to implement this __getzone function?

The reason I am giving up is because the value returned by __getzone is an oddball w / formatting string like this:

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

Where XXX is the standard time zone name (for example, GMT-5 for EST), YYY is the name of the daylight saving time zone (for example, GMT-4 for EST), NNN is the numerical offset from UTC in the form HHMM (and can have a - symbol). and then DST sets a parameter string for daytime rules, which have their annoying formatting.

Anyway, it should be pretty straight forward for me right now, because I'm only concerned about Canada and the US, which have the same DST rules.

Q2: Does anyone have some sample code to generate this line so I can test my understanding of it?

+2


source to share


4 answers


Here is my implementation of __getzone (). So now my system timebase will be UTC. When a user configures my system, I ask them what their local time is, if the time source does NOT provide UTC. Then when they feed the time sync to my system, their delivery time will be converted to UTC by calling MKTIME (which will respect DST rules). Then, when the time is returned to the user, it will be done by calling localtime ().

Another thing we learned in the process of implementing this is that the IAR implementation of MKTIME () will call __getzone (), but DST rules will not be considered unless you set tm_isdst to '-1'. -1 makes a call to MKTIME () to find out if DST should be applied based on the rule.



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

      

+2


source


char const * __getzone()
{
        return ":GMT+2:GMT+3:0200:(1996)033103-0:103104-0";



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

      



+1


source


The Ukraine rule above is not entirely true as it will not work on Sundays that fall in 31st place. If you read the rules in getzone.c -W, then Sunday is strictly before that date.

+/-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.

      

The correct rule would be as follows:

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

      

+1


source


For Germany, you can use:

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

      

Either one from Ukraine is wrong or mine, but I checked mine with an actual device and got the correct results. Here's my tests:

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

      

Regards Michael

0


source







All Articles