Not sure exactly where to post this question. Init...
# getting-started
c
Not sure exactly where to post this question. Initially I thought maybe #C01D6HTPATV or #C1CFAFJSK or #C01923PC6A0 but essentially I'm working on a desktop app and I need to do a check every minute, but the minute has to be according to the system clock. Is there a way to somehow get updates on Clock.System() so that I can run a task once a minute at the "top" of the minute (as per the system)? almost like a cron job i suppose. accuracy that this happens at the top of the minute is really high priority to me so i'm also trying to minimize any drift that I would have from my current implementation which is just a delay(1.minute) (which seems to work fine, but the delay starts when the desktop app starts, and not when a minute starts)
h
I don't think you can set a precise alarm like that. But how about just "aiming" your delay at the next full minute? So, if your app starts say on second 13 of the current minute, then you make your delay just 47 seconds and before every delay you check the current offset vs. the clock…
p
That was exactly my thought
Copy code
fun durationToNextMinute(): Duration {
    val now = Clock.System.now()
    val local = now.toLocalDateTime(TimeZone.currentSystemDefault())
    val nextMinute = local.date.atTime(local.hour, local.minute + 1)
    return nextMinute.toInstant(TimeZone.currentSystemDefault()) - now
}

suspend fun delayUntilNextMinute() = delay(durationToNextMinute())
c
I think that should work. let me give that a try.
j
c
ooh. thanks Joe! @phldavies that code worked! nice. that was simpler than I imagined. i thought maybe there was some sort of timer api i was missing
c
If you’re interested in a more declarative approach to defining scheduled tasks like this, you might check out Ballast’s Scheduler plugin.
❤️ 1
c
for anyone following along in the future i had to update val nextMinute = local.date.atTime(local.hour, local.minute + 1) to val nextMinute = if (local.minute == 59) { local.date.atTime(local.hour + 1, 0) // Go to next hour at minute 0 } else { local.date.atTime(local.hour, local.minute + 1) }
p
You could just do atTime at the same minute, then add 1 minute to the duration
🤔 1
Effectively truncate to the current minute and add one
c
If I'm understanding correctly
Copy code
fun durationToNextMinute(): Duration {
    val now = Clock.System.now()
    val local = now.toLocalDateTime(TimeZone.currentSystemDefault())

    val nextMinute = local.date.atTime(local.hour, local.minute)

    return (nextMinute.toInstant(TimeZone.currentSystemDefault()) - now) + 1.minutes
}
?
p
I'd rename "nextMinute" but yes, if my late night addled brain can do maths ...
👍 1
c
cool. will test this out. wanted to make sure i understood you correctly.
c
@Colton Idle You can look at the implementation used in Ballast Scheduler. Rather than trying to calculate how long to delay, it’s easier to just calculate the next
Instant
you need to trigger, then delay by the difference in time between
Clock.System.now()
and that Instant https://github.com/copper-leaf/ballast/blob/main/ballast-schedules/src/commonMain/kotlin/com/copperleaf/ballast/scheduler/schedule/EveryMinuteSchedule.kt#L15-L42 https://github.com/copper-leaf/ballast/blob/main/ballast-schedules/src/commonMain/kotlin/com/copperleaf/ballast/scheduler/executor/CoroutineClockScheduleExecutor.kt#L13-L41
👀 1