Having trouble with date picker in phone settings

I need to get the Month/Day/Year from the phone settings and I set date in settings on the phone to 1/1/2021 and I am getting 12/31/2020:

var countdown = Application.getApp().getProperty("CountDownDate");
var infoC=Gregorian.info(new Time.Moment(countdown), Time.FORMAT_SHORT);

var cyear = infoC.year;
var cmonth = infoC.month;
var cday = infoC.day;

System.println(" MyWatchFaceView - onUpdate - countdown:"+countdown+" cmonth:"+cmonth+" cday:"+cday+" cyear:"+cyear);

-------------------------------- output

MyWatchFaceView - onUpdate -  countdown:1609459200 cmonth:12 cday:31 cyear:2020 

  • There's few threads about this.  You can find them with search like this:

  • Yes,

    I found a few, but still can't figure out how to actually get the date set on the phone.

    Is there a way or no?

  • Lots of variables involved, like Android vs iOS, GCM vs Connect IQ vs Garmin Express,  They might not all work the same. I'd probably just avoid the date setting and do something myself - entering numbers for month day year hour minute for example.

  • Wow, ok so the date input just plain doesn't work.

    So I will need to have the user enter 3 fields to get a date?

  • Yes, and you can set a range on the Numbers so that month has to be 1-12,day, 1-31, etc, but then you have to handle the case where someone sets February 31.

    date settings might be better today than they were,, but I'd not be surprised there is still a variation based on what's used to set the date.  I seem to recal a recient thread where UTC vs local time also came up.

  • TL;DR try Gregorian.utcInfo() instead of Gregorian.info().

    I need to get the Month/Day/Year from the phone settings and I set date in settings on the phone to 1/1/2021 and I am getting 12/31/2020:

    var countdown = Application.getApp().getProperty("CountDownDate");
    var infoC=Gregorian.info(new Time.Moment(countdown), Time.FORMAT_SHORT);

    var cyear = infoC.year;
    var cmonth = infoC.month;
    var cday = infoC.day;

    System.println(" MyWatchFaceView - onUpdate - countdown:"+countdown+" cmonth:"+cmonth+" cday:"+cday+" cyear:"+cyear);

    -------------------------------- output

    MyWatchFaceView - onUpdate -  countdown:1609459200 cmonth:12 cday:31 cyear:2020 

    Has this ever been fixed?

    Haven't tried this myself, but to address your original question:

    - 1609459200 interpreted as seconds after the Unix epoch (*) is exactly Fri Jan 01 2021 00:00:00 GMT+0000.
    See: [https://www.unixtimestamp.com/]
    (* Midnight, January 1, 1970, UTC)

    This implies that when you select a date using the date picker in CIQ settings, it saves the date as a timestamp for the selected date on midnight in the UTC/GMT time zone. This makes sense, because you probably don't want the meaning of the date that was chosen to be time-zone specific. (In general, when a date/time is not supposed to be tied to a given time zone, internally it's stored as if the time zone is UTC. Similarly, when the specific time of day is not important, the time that's stored is arbitrarily chosen to be midnight.)

    - If you live west of the UK, the above time will be December 31, 2021, in your local time zone (e.g. New York = UTC-5 or UTC-4 in summer time). This explains the results you saw.

    - The docs for Time.Moment.initialize() state that its argument is a UNIX timestamp, so the "new Time.Moment(countdown)" part of your code should be correct

    - The docs for Gregorian.info() state that time information is formatted in *local time*. However, Gregorian.utcInfo formats time info as UTC time.

    - So I think the solution here is to use Gregorian.utcInfo() rather than Gregorian.info()

  • Bit weird that if no timezone is associated that it picks UTC. I would expect a floating timezone, meaning the timezone is whatever timezone the watch is currently in. 

  • Bit weird that if no timezone is associated that it picks UTC. I would expect a floating timezone, meaning the timezone is whatever timezone the watch is currently in. 

    TL;DR IMO, this is a consequence of the chosen date storage format, not the behavior of the watch when you read and convert the stored date. Given that the selected date is stored as a UNIX timestamp, that no time of day is specified, and UNIX timestamps are relative to UTC, seems to me the best choice is to pretend that the input time is midnight and the input time zone is UTC. I'm assuming that the user doesn't care about the current time zone when they set a date-only value. 

    Otherwise you have a situation where you can only reliably recover the original date if you are in the same timezone as when it was set. This is probably not what the user wants, unless the user of your app really expects that if they set a date like 2021-01-01 when they're in the UK, it should be interpreted as 2020-12-31 if the value is read while they're in New York. But doesn't really make sense for a date-only picker IMO -- it might make sense for a combined date and time picker.

    For the purposes of this discussion, I'm assuming that a date in CIQ settings is literally stored as a UNIX timestamp. OTOH, if the date was literally stored as a string (e.g. "1970-01-01"), as is commonly done when data is exchanged/stored as JSON, and if Monkey C had a handy date string-to-time conversion function (which it doesn't), that would be the perfect time to specify whether you want the date to be interpreted as UTC time or local time. Given that CIQ is heavily resource-constrained, the choice of a UNIX timestamp is probably best.

    Similarly, if the code for the date picker stored both the selected date and the current time zone at the time of date selection, it would be possible for an app to choose whether they wanted to respect original time zone or not. But since no time zone is stored, it isn't possible.

    The behavior of Javascript Date constructor (when you pass in a date/time string) kind of follows the above reasoning:

    - If there's a only a date (e.g. "1970-01-01"), it's treated as UTC

    - If there's a date and a time (e.g."1970-01-01T12:00"), it's treated as local

    Anyway, maybe the real problem is that the behavior of the "date" setting isn't fully documented afaict, except to say that it stores a number. You can make an educated guess that number is "seconds since the UNIX epoch", but you can't be sure whether it was stored as "<YOUR DATE> at midnight UTC" or "<YOUR DATE> at midnight local time (in terms of UTC)". I still think the former makes the most sense, especially if you are selecting a date only (and not also a time).

    I will say that in my day job, all kinds of bugs come up when dates are stored as strings without times or time zone information (e.g. "2021-01-01"), due to mismatches between code that interprets time locally as opposed to code that interprets time as UTC (including code associated with the js Date constructor above). But at least when a date is stored as a date string that has no TZ info (e.g. "2021-01-01"), the application is free to interpret it however it wants. With the Garmin situation, application code *has* to interpret the date as a UTC timestamp, which can lead to further confusion.

    Speaking of documentation, the following bug used to exist. I see that it's been fixed now, but it just goes to show how easy it is for conceptual issues to crop up with local vs UTC time.

    https://forums.garmin.com/developer/connect-iq/i/bug-reports/docs-for-gregorian-moment-imply-that-the-input-is-in-local-time-gregorian-info-and-utcinfo-suggest-otherwise

    Docs for Gregorian.moment() imply input is interpreted as local time (not UTC), but Gregorian.info() and utcInfo() suggest otherwise