Daylight Saving Time Mismatch between Simulator and Device

We live in UTC+1:00 Timezone.

In Summer (lfrom Mar 27 to Okt 30) comes additional hour to this ("Summertime").

The Simulator taks care of summer or wintertime and get local time correct. On Device the getting of a time from the other timearea become 1 hour defference, which is wrong:

  • If now is summer and I want to get correct Gregorian representation of a epoch from winter, it diffs 1 hour from correct time
  • If now is winter and I want to get correct Gregorian representation of a epoch from summer, it diffs 1 hour from correct time

Consider the following Code based on Unix Epochs:

    function test_time(dc as G.Dc) {
        var location = new Position.Location({
                                            :latitude  =>  51.338248,
                                            :longitude => 12.362537,
                                            :format    => :degrees,
                                        });
        var text = "";
        // var m = Time.Gregorian.moment({ :year => 2015, :month => 10, :day => 15, :hour => 14, :minute => 0, :second => 0 });
        // var i = Time.Gregorian.info(m, Time.FORMAT_MEDIUM);
        // var s = Lang.format("$1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")]);
        // Sys.println(s);

        // m = Time.Gregorian.moment({ :year => 2015, :month => 11, :day => 15, :hour => 14, :minute => 0, :second => 0 });
        // i = Time.Gregorian.info(m, Time.FORMAT_MEDIUM);
        // Sys.println(Lang.format("$1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")])); 
    
        // Sys.println("");

        Sys.println("\n *************** test_time *****************");
        Sys.println("summer=1667023200");
        Sys.println("  should GMT: Sat Oct 29 2022 06:00:00 GMT+0000");
        Sys.println("  should loc: Sat Oct 29 2022 08:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)");
        var m = new Time.Moment(1667023200);
        var i = Time.Gregorian.utcInfo(m, Time.FORMAT_SHORT);
        var s = Lang.format("utc: $1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")]);
        text += s;
        Sys.println(s); 
        i = Time.Gregorian.info(m, Time.FORMAT_SHORT);
        s = Lang.format("inf: $1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")]);
        text += "\n" + s;
        Sys.println(s);

        text += "\n";

    
        Sys.println("");
        Sys.println("winter=1667113200");
        Sys.println("  should GMT: Sun Oct 30 2022 07:00:00 GMT+0000");
        Sys.println("  should loc: Sun Oct 30 2022 08:00:00 GMT+0100 (Mitteleuropäische Normalzeit)");
        m = new Time.Moment(1667113200);
        i = Time.Gregorian.utcInfo(m, Time.FORMAT_SHORT);
        s = Lang.format("utc: $1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")]);
        text += "\n" + s;
        Sys.println(s); 
        i = Time.Gregorian.info(m, Time.FORMAT_SHORT);
        s = Lang.format("inf: $1$ $2$ $3$ $4$:$5$:$6$", [i.month, i.day, i.year, i.hour.format("%02d"), i.min.format("%02d"), i.sec.format("%02d")]);
        text += "\n" + s;
        Sys.println(s);  

        
        
        var myTextArea = new WatchUi.TextArea({
            :text=>text,
            :color=>Graphics.COLOR_BLACK,
            :font=>[Graphics.FONT_MEDIUM, Graphics.FONT_XTINY, Graphics.FONT_XTINY],
            :locX =>WatchUi.LAYOUT_HALIGN_CENTER,
            :locY=>WatchUi.LAYOUT_VALIGN_CENTER,
            :width=>220,
            :height=>200
        });
        myTextArea.draw(dc);
    }

on Log it prints:

Info: Okt 29 ist the last day of summertime (UTC+2:00), Okt 30 ist the first day with wintertime (UTC+1:00)

*************** test_time *****************
summer=1667023200
  should GMT: Sat Oct 29 2022 06:00:00 GMT+0000
  should loc: Sat Oct 29 2022 08:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
utc: 10 29 2022 06:00:00
inf: 10 29 2022 08:00:00

winter=1667113200
  should GMT: Sun Oct 30 2022 07:00:00 GMT+0000
  should loc: Sun Oct 30 2022 08:00:00 GMT+0100 (Mitteleuropäische Normalzeit)
utc: 10 30 2022 07:00:00
inf: 10 30 2022 08:00:00

Here the Screenshot of Simulator and real Device:

It is so that the simulator takes into account the correct time zone offset of the given time:

  • in summer 2 hours are added (UTC+2:00)
  • in winter 1 hour is added (UTC+1:00)


But the same call on the clock ALWAYS takes into account the CURRENT timezone offset at runtime of the program.

I can correct this manually in the codee, but this leads to a wrong display in the simulator and works only for Central European Time. The problem cannot be solved satisfactorily for mic. Since my watchface represents the course of the sun and additionally the shortest and longest day, it is always displayed incorrectly, since times must always be calculated from the other time (summer and winter).

This then looks like this:

The simulator calculates (we are NOW in summer time UTC+2:00) the sunrises and sunsets for winter (blue line with UTC+1:00) correctly.

The real device calculates the times in coming winter with the TODAY SHIFT (UTC+2:00) and therefore wrong.

How can I solve the Probelem? To me it looks like a bug in the API.

  • Look at using LocalMoment:

    https://developer.garmin.com/connect-iq/api-docs/Toybox/Time/LocalMoment.html

    Here I use a position, take the current time where I am, and println the hour at the position.

        		var now=Time.now();
        		var lm=Time.Gregorian.localMoment(pos,now);
        		var greg=Time.Gregorian.info(lm, Time.FORMAT_MEDIUM);
        		System.println(""+greg.hour);

    It's only available on devices With CIQ 3.3.x or 4.1.x, and you need the actual position of the other place.

    With the sim vs device, in one case it does chance the UTC offset based on DST, and in the other, it uses a DST offset that's either 0 or non-zero, and is only valid for "today".  If you use both UTC offset and DST offset, you should see the correct time in both, but again, only for today.

  • Thanks.

    I had test: on Simulator exact same behaviour as before (correct), BUT: on Device crashes.

    Log says "Error: Unhandled Exception" on the line with "localMoment(...)".

    I did'nt understand it: it's a brand new fenix 7

  • With the sim vs device, in one case it does chance the UTC offset based on DST, and in the other, it uses a DST offset that's either 0 or non-zero, and is only valid for "today".  If you use both UTC offset and DST offset, you should see the correct time in both, but again, only for today.

    I'm still not sure how it makes sense to calculate the TZ offset for another date based on today's DST offset. The dev isn't asking for today's time, they're asking for the time on another day. Before you say that we don't necessarily know how DST rules will change in the future, that's a separate issue which doesn't prevent other systems (Windows, Linux, etc) from doing it properly - i.e. the DST offset is applied (or not) based on whether it's summer time on the date in question, not today.

    I opened a bug report for this last year. If anyone reading this thread is interested in seeing it fixed, please upvote!

    forums.garmin.com/.../gregorian-info-handles-dst-incorrectly-for-dates-other-than-now-today-works-in-sim-not-on-device

  • I don't really know where is the problem.

    1. you can know only valid UTC-0 time for every day

    2. if you want to know LOCAL TIME for any day you have to know what utc offset and dst is in this particular day. No such info - no local time. In past you need library for this values in future library and assumption that government won't change rules (like e.g. Japan decided to not use dst since some moment).

    3. library - your own :-) system api. bad api/library bad time.

  • So, does anyone want to vote on the bug report? I feel like two people in this thread other than me agree that it's a bug.

  • To fixthis bug  api has to implement "library".

  • To fixthis bug  api has to implement "library".

    What are you talking about?

    The API can stay the same, it just has to work the same as it does in the sim. It should be a very simple fix.

    Sim: When you ask for local time on a different utc time/date, it uses the DST offset for that date. Correct

    Real device: When you ask for local time on a different utc time/date, it uses the DST offset for today. Incorrect

    It's exactly as OP described and as I described in my bug report.

    In other discussions, it's already been made clear that Garmin stores a time zone map (tzmap) on the watch in order to do TZ/DST calculations. Since the watch isn't constantly connected to the internet, it must have an offline way of knowing whether DST is in effect today, in order to show the correct local time today. (Especially if you travel to a different time zone)

    So for example, the rule for New York / Eastern Time would look like this:

    - Normal UTC offset = -5 hours

    - Is DST supported? Yes

    - DST starts: March, 2nd Sunday, 2:00 AM

    - DST ends: November, 1st Sunday, 2:00 AM

    To determine local time in New York, given a UTC time/date:

    Correct behavior (everyone except Garmin):
    - Use the given time/date to determine whether DST is in effect

    Incorrect behavior (Garmin):
    - Use *today's* date (and the given time, I guess) to determine whether DST in effect

    And whether historical rules are available or not is a secondary issue. If they're not available, then the calculations will be wrong for some past dates in some time zones. But that's better then the calculations being wrong for *most* past and future dates.

  • A simpler way of looking at this. Today is September 23, 2022 and I'm in the Eastern Time Zone (e.g. New York).

    If someone asks me "is DST in effect in New York on January 1, 2023?", then I should answer according to the rule for January 1, 2023, not the rule for September 23, 2022.

    Either way I already know the rules for the whole year:

    - DST starts: March, 2nd Sunday, 2:00 AM

    - DST ends: November, 1st Sunday, 2:00 AM

    Garmin watches already have to know these rules, too, otherwise they couldn't correctly show you the current local time, given that the watch's time can be synced via GPS (which ofc gives you a kind of universal time, not local time). The problem is they're being applied incorrectly.

  • And even if it's some kind of insanely complex fix (I don't think it is), that doesn't change the fact that it's a bug.

  • Problem is that on sim api calls windows/linux api and it returns good values. On device probably there is no library to handle it. But from time to time in express I can see info about updating of DST zones so it means there is an bug in CIQ.