time handling

How did you habdle the time in an Application, for now I use a timer with 1 sec fireing, but when the main view is hide/change this timer is stop, so when I return to this view, there is missing lot's of seconds !
I was wandering how other keep track of time in their app ? what's the best practice, as from I've read, the number of timer is a limited resource ?

thanks
  • It kind of depends on what you want for time, and what kind of app you're doing. If it's a DF or device app with recording, Acutivity.Info has elpasedTime and timerTime (it's in ms since you started recording, where timerTime does change while paused).

    You can use Sys.getClockTime() for the time of day, you can use Sys.getTimer() to get the ms count since the watch was booted. (it will roll after something like 50 days)

    Time.now().value() gives to the time in "Unix time" (seconds since Jan 1,1970 00:00 UTC)
  • It kind of depends on what you want for time, and what kind of app you're doing. If it's a DF or device app with recording, Acutivity.Info has elpasedTime and timerTime (it's in ms since you started recording, where timerTime does change while paused).

    You can use Sys.getClockTime() for the time of day, you can use Sys.getTimer() to get the ms count since the watch was booted. (it will roll after something like 50 days)

    Time.now().value() gives to the time in "Unix time" (seconds since Jan 1,1970 00:00 UTC)


    answer, I was trying to replace my timer, by elpasedTime, but was staying at zero, from what you say, it seems I need to better use timerTime.
  • vald70 To clarify what Jim said:

    Both elapsedTime and timerTime will not start until you start your activity. The difference is:
    - elapsedTime: continues even if activity is paused
    - timerTime: stops when activity is paused, restarts when activity is un-paused

    (I think Jim meant to type that timerTime does not change while paused.)

    Sys.getClockTime() is okay, but it's the wall clock / time of day, which means that it can jump forwards or backwards if the user changes their date/time. Admittedly that's a rare case on most devices, but it can still cause problems in your app if you really need relative time (duration) and not absolute time (wall clock). Also, it only has a resolution of one second.

    From what you are saying, it sounds like you really need Sys.getTimer(), which is a timer that continues to run as long as the watch is turned on and can never "jump forwards/backwards" (unlike Sys.getClockTime()). It's exactly like the "up time" on a computer.
  • Actually, getTimer() can reset. It's a 32 bit value, so after something like 50 days, it resets to zero. It restarts if you power off the watch and turn it back on, but will keep going if you use a wall charger. Definitely an edge case!
  • vald70 To clarify what Jim said:

    Both elapsedTime and timerTime will not start until you start your activity. The difference is:
    - elapsedTime: continues even if activity is paused
    - timerTime: stops when activity is paused, restarts when activity is un-paused

    (I think Jim meant to type that timerTime does not change while paused.)

    Sys.getClockTime() is okay, but it's the wall clock / time of day, which means that it can jump forwards or backwards if the user changes their date/time. Admittedly that's a rare case on most devices, but it can still cause problems in your app if you really need relative time (duration) and not absolute time (wall clock). Also, it only has a resolution of one second.

    From what you are saying, it sounds like you really need Sys.getTimer(), which is a timer that continues to run as long as the watch is turned on and can never "jump forwards/backwards" (unlike Sys.getClockTime()). It's exactly like the "up time" on a computer.


    Thanks for clarification. what I need is duration, so from what you say Sys.getTimer() should be ok,
    I previously try elapsedTime, but in simulator seem to stay at zero even after activity start. maybe my problem is : when an activity start (I am writing a watch app)

    jim_m_58 : I am only looking for max a few hour, so wrap around should'n be a problem !
  • jim_m_58 correct me if I'm mistaken, but as a 32-bit signed integer, the result of System.getTimer() does not reset to 0 when it reaches the max value, it wraps around to the lowest negative number.

    If you are only comparing two durations, then wrapping shouldn't be a problem as long the time between sampling the durations is less than the total "width" of timer (i.e. 50 days). You can still subtract T1 - T0 and get the right answer if T1 wrapped. Wrapping should only be a problem if you are using absolute values somehow (like displaying uptime).

    Anyway, let me be more precise:

    Unlike the other metrics, I believe that as long as the watch is powered on (I mentioned this already) Sys.getTimer() is a monotonically increasing value which never pauses and does not jump forwards or backwards due to external factors like the user changing their date / time of day settings. The exception is when the value wraps around when the maximum signed 32-bit value is reached.

    Of course if your app needs to compare times between power offs / reboots, then it also needs to store the clock time for certain situations.

    vald70 The only watch app I've ever made is a stopwatch, but I believe (correct me if I'm wrong), that the activity only starts when you start recording a FIT file:
    https://developer.garmin.com/downloa...g/Session.html

    The ActivityRecording::Session object has start, stop, addLap, save and discard() methods, just like a native activity.

    I also believe (again correct me if I'm wrong) that it's impossible to have an "activity" (in the watch app sense) unless you are recording a FIT file.

    Anyway, your app is still running before the activity starts, and it may still run after the activity ends, so you probably don't want to use elapsedTime for measuring durations (unless it's literally duration of an activity in progress).
  • I am only looking for max a few hour, so wrap around should'n be a problem !


    It's not that your app runs for 50 days, it's that it's running when the number hits the max. Encountering the problem would be quite rare, but possible. :)
  • It's not that your app runs for 50 days, it's that it's running when the number hits the max. Encountering the problem would be quite rare, but possible. :)


    As I said, if Sys.getTimer() (a 32-bit signed value) wraps, then comparing two samples by subtraction will still be correct, as long as the time between two samples is less than 50 days. IOW, subtraction still works as long as the value only wrapped once (or zero times).

    Suppose you sample T0 = 0x7FFFFFFF = 2147483647
    1 millisecond later, you sample T1 = 0x8000000 = -2147483648

    When you calculate T1 - T0, the answer is still 1. The same goes for 0 - 0xFFFFFFF or any other example of wrapping (as long as the value only wrapped once between samples).

    The only problems arise when:
    - Waiting longer than 0xFFFFFFFF milliseconds between samples (50 days)
    - Printing out the value of Sys.getTimer() and expecting a non-negative number, as if it could never wrap. (Of course one way around this is to interpret it as an unsigned 32-bit number when you print it out. But it can still wrap around to 0 in that case.)
    - Using comparison operators on the absolute values like greater than or less than without taking wrapping into account. (But why would you, since the time is always increasing?)

    ---

    EDIT: Also, I don't see why wrapping should be considered so rare that we shouldn't care about it, unless Garmins never stay up for longer than 50 days. The system timer will wrap every 50 days, and apps should be able to handle that. If a user last turned the watch on around the same time of day that they normally open a certain app, and if they use that app every day, then it's not unlikely that the app will see the system timer wrap every now and then (at worst, every 50 days, of course).

    Anyway, I will reiterate that as long as you are only comparing two samples from Sys.getTimer() using subtraction, you shouldn't even notice wrapping.
  • There's a thread from a while back when this came up and in 50 days, it's back to zero. It turns negative (if you look at it as signed) after 25.

    2147483647/(24x60x60x1000) =~25 days
    0x7FFFFFFF+1=0x80000000, and in about 25 more days, it will be 0xFFFFFFFF. Add 1 to that, you get 0x00000000.
  • jim_m_58, thanks for the clarification. I should've done the math and been more precise, but looking back at my posts, I actually still didn't say anything that was incorrect regarding wrapping. The value wraps around to a negative number after it goes past 0x7FFFFFFF (the highest positive Number). I actually never said when that would happen, although you're right, it's 25 days.

    In any case it's incomplete to say that it resets to 0 after 50 days, when it also wraps around to a negative number after 25 days. Since Numbers are signed 32-bit integers, and Monkey C does not have an unsigned 32-bit type, comparison operators will interpret Numbers "larger than" 0x7FFFFFFF as negative. So the wrapping to negative is equally relevant (or more) than the "reset to 0".

    Any app that relied on the "absolute" value (*) of System.getTimer() should have problems after 25 days, not 50, unless I'm missing something. Unless it's just printing out that number (and interpreting as an unsigned 32-bit). Or if it's storing the result in a Long so it can do unsigned 32-bit math.

    (* As opposed to a "relative" duration, obtained by subtracting two values)

    For example, the following code will not work as expected after 25 days:
    // I don't see any easy way in Monkey C to interpret System.getTimer() as
    // an unsigned 32-bit value here, without doing some math and possibly using a Long
    //
    // So most apps that look at System.getTimer() are going to see a negative
    // number at some point
    if (System.getTimer() > 1000 * 60 * 60) // fails when the timer goes past 0x7FFFFFFF
    {
    // do something if watch has been up / powered on for longer than 1 hour
    }


    Anyway, please correct me if I'm wrong, but the wrapping just does not matter as long as you are only subtracting two samples of Sys.getTimer() to obtain a duration.

    If you are printing the values out or using comparison operators, then you would need to be aware of wrapping.

    It turns negative (if you look at it as signed) after 25.


    Please correct me if I'm wrong, but there's no easy way to not look at Numbers as signed in Monkey C, unless you are just printing them out. If you are doing comparisons, they're signed. The only way I can think of to do unsigned comparisons between Numbers is to store them in Longs, after doing the appropriate math to get rid of the sign bit. (I suppose you could format a Number to a string using "%u", then convert that to a Long, but that's really inefficient).