1

I am developing an Android app using Kotlin and I would like to achieve the following:

  1. Let a user select a time for an alert (hh:mm) from current time until the following 24 hours e.g. at 16:00 user wants to put an alert for tomorrow at 15:00.
  2. Once the user has set the alert, I want to show the time remaining until the alert is activated (hh:mm) e.g. Show a small dialog with the text: 3h:15min remaining.

What is the best way to deal with time operations (subtract current time to the alert time) in Kotlin?

Saeed Entezari
  • 3,685
  • 2
  • 19
  • 40
  • [I feel like i answered very similar question before...](https://stackoverflow.com/questions/53434240/make-timer-count-from-date/53434392#53434392) – Quinn Jan 21 '20 at 17:14
  • It looks like that, yes. But I were looking for (maybe It wasn't clear in my question) the best way to handle this situation in the most kotlin idiomatic way (and to know if already exists a way to handle it, and if it is not deprecated, as `Date` from `Java.util` is). I read you answer to that question before asking it here, but it didn't answer my question. Thanks a lot for answering :) – Miguel Betegón Jan 21 '20 at 17:23

2 Answers2

4

All your questions have been asked and answered many times on Stack Overflow. So I’ll be brief. Search to learn more.

Use only java.time classes, never the terrible legacy classes such as Date and Calendar.

For Android before 26, see the ThreeTen-Backport library and its Android-specific wrapper ThreeTenABP.

Represent a time-of-day with LocalTime.

LocalTime targetLocalTime = LocalTime.of( 15 , 0 ) ;

Get current moment. Requires a time zone. 2-4 letter codes like CST are not real time zones. Real zones are named Continent/Region.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

Compare time portion. Extract a LocalTime to compare.

Boolean runToday = now.toLocalTime().isBefore( targetLocalTime ) ;

Determining next alarm time.

ZonedDateTime zdt = now.with( targetLocalTime ) ; 

Or if needed on next day, tomorrow.

ZonedDateTime zdt = now.toLocalDate().plusDays( 1 ).atStartOfDay( z ).with( targetLocalTime ) ;

Calculate elapsed time. Adjust to UTC by extracting an Instant.

Duration d = Duration.between( now.toInstant() , zdt.toInstant() ) ;

Generate string in standard ISO 8601 format.

String output = d.toString() ;

Or generate a string in another format by calling the Duration::to…Part methods.

As for firing the alarm, in straight Java use the Executors framework, specifically ScheduledExecutorService. This framework makes it simple to run a background thread that fires a task Runnable at a certain moment. Well, nearly certain — slight delays may occur for garbage-collection or thread/process scheduling on the CPU, but good enough for business apps (not good enough for NASA).

Android may also provide some alarm-setting feature. (I don’t know)

Never ever access or manipulate your user-interface from a background thread. Use whatever hook Android provides to update the UI from another thread, such as refreshing a UI widget or presenting a notification.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

According to Basil Bourque, the following is the code he proposed (in Java) converted to Kotlin, just in case someone is interested.


// Credit to Basil Bourque Answer
// https://stackoverflow.com/questions/59846004/what-is-the-best-way-to-operate-with-time-in-kotlin/59846550#59846550

lateinit var zdt: ZonedDateTime
val targetLocaltime = LocalTime.of(21, 0)
val z = ZoneId.of("Europe/Madrid")
val now = ZonedDateTime.now(z)
val runToday = now.toLocalTime().isBefore(targetLocaltime)

zdt = if (runToday){
    now.with(targetLocaltime)
}
else{
    now.toLocalDate().plusDays(1).atStartOfDay(z).with(targetLocaltime)
}
val eta = Duration.between(now.toInstant(), zdt.toInstant()).toMinutes()
if(eta > 60){
    val hours = eta / 60
    val minutes = eta % 60
    print("$hours:$minutes remaining")
}
else{
    print("$eta minutes remaining")
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121