How to determine DST on the watch?

I found DST always returns 0 on the actual watch when using Toybox.System.getClockTime().dst. I wonder what would be a good workaround?

I do see System.getClockTime().timeZoneOffset correctly gives the correct offset from UTC (reflecting DST). Maybe that could be used as a workaround if I knew the current time without DST. Any idea?

Context is that I want to show 'DST' icon if DST is active for current location.

Top Replies

All Replies

  • I do see System.getClockTime().timeZoneOffset correctly gives the correct offset from UTC (reflecting DST). Maybe that could be used as a workaround if I knew the current time without DST

    If you know the coordinates of your current location (or last known location), and your device supports a CIQ API level of at least 3.3/4.1 (System 5), you should be able to use LocalMoment which has getDaylightSavingsTimeOffset() and isDaylightSavingsTime() methods. (I assume both of those work properly).

    So the only problems are that it won't work on old devices and it requires you to know the current or last known location (which means your app has to have the positioning permission). (BTW, If your app is a watchface, the last I heard, you have to use Activity.Info.currentLocation to get the last known position.)

    Unfortunately, I don't think there's any other way to determine whether DST is currently in effect, because on a real device, for the purposes of determining whether DST is active or not on a given date, Gregorian.info() acts as though the input date is today.

    For example, if you call Gregorian.moment() (which takes a UTC date/time as input) with a date that's known to be non-DST (such as January 1st in the northern hemisphere), Gregorian.info() will return a local time that's adjusted for DST (or not) based on today's date, not the input date.

    If this wasn't the case, you could use Gregorian.info() to get the local times for noon Jan 1 UTC and noon July 1 UTC, determine which one of them represents summertime based on which one has the larger UTC delta, and compare the two deltas with System.getClockTime().timeZoneOffset to determine whether you're currently in DST.

    See:

    [https://forums.garmin.com/developer/connect-iq/i/bug-reports/clockinfo-dst-is-0-on-the-watch-correct-value-on-the-simulator]

    [https://forums.garmin.com/developer/connect-iq/i/bug-reports/gregorian-info-handles-dst-incorrectly-for-dates-other-than-now-today-works-in-sim-not-on-device]

  • Thanks very much! I only want to make it work for the 955 so that should work. I looked into LocalMoment but couldn't test this since wasn't sure how to pass location. But I can try Activity.Info.currentLocation.

  • I tried Activity.Info.currentLocation and Weather.getCurrentConditions().observationLocationPosition but for some reason typically null on my watch (I had briefly a value for weather but for reason only for a minute). I don't have always a phone connection so maybe that's why. But it seems tough to get current location reliably for a WF.

  • Yeah...that's why it would be great if the watch gave a sensible result when you ask for the local time on a *different* date (based on a UTC input), that way you could derive the DST status indirectly. (If you ask some people on this forum, it's not a bug, it's a difference of opinion ¯\_(ツ)_/¯)

    Or maybe just implement the dst flag in the first place idk.

  • I tried Activity.Info.currentLocation and Weather.getCurrentConditions().observationLocationPosition but for some reason typically null on my watch

    Sorry, I forgot to mention that one way to "prime" Activity.Info.currentLocation is to open an activity (like Run) and get a GPS fix, then exit the activity. (At least that's my hazy recollection from the forums -- I don't develop watchfaces.)

  • Yes, in a WF you want to null check currentLocation, and if it's not null, save it to Application.Storage.  Then if it is later null, use the value from Application.Storage.  currentLocation will go "stale" after a period of time (the time varies by device) and return null.  That way, you always have a location after it was first "primed".

  • Thanks, make sense. For some reason I also got null for sample code below but could be something else going on:

    using Toybox;

    var options = {
     :year => 2018,
     :month => 2,
     :day => 24,
     :hour => 0,
     :min => 12
    };

    var when = Time.Gregorian.moment(options);

    var where = new Position.Location({
     :latitude => 38.85391,
     :longitude => -94.79630,
     :format => :degrees,
    });

    var local = Time.Gregorian.localMoment(where, when);  // NULL FOR SOME REASON

  • I found SDK doc example appears to be wrong. Last 2 lines should be instead:

    var options = {
    :year => 2023,
    :month => 1,
    :day => 1,
    :hour => 0,
    :min => 0
    };

    var when = Toybox.Time.Gregorian.moment(options);
    var local = Time.Gregorian.localMoment(where, when.value());

  • (BTW, If your app is a watchface, the last I heard, you have to use Activity.Info.currentLocation to get the last known position.)

    I have found that on an actual Fenix 7X position works in a watchface meaning the position seems to be updating somewhat continuously, but .accuracy is always 1.This might be CIQ version dependent, it currently shows 4.2.3.

    		var locInfo = Position.getInfo();
    		var locAcc = locInfo.accuracy;
    		var locPos = locInfo.position.toRadians() as Array<Double>;
    

  • An accuracy of 1 is actually "QUALITY_LAST_KNOWN which is the last location when GPS was on.

    The location itself doesn't update unless GPS is on, which is only the case with a widget or device app that turns on GPS with 

    Position.enableLocationEvents(Position.LOCATION_CONTINUOUS, method(:onPosition));
    if you use LOCATION_ONE_SHOT, you'll often get QUALITY_LAST_KNOWN as it doesn't actually start GPS, if it's still got a location.
    GPS is very expensive battery wise so it's only on when it's specifically enabled.