Search code examples
androidalarmmanagermillisecondsjava.time.instant

Localdatetime to epoch/calendar.getTimeInMillis() for alarmmanager


I'm getting the milliseconds for the alarmmanager to set repeating alarm and I'm getting strange results -

I set alarm at 8:55 am

LocalDateTime Earliest Day : 2018-05-22T08:55
Instant : 2018-05-22T08:55:00Z

Then I used this method to get the milliseconds since epoch (1970) -

LogUtils.LOGD(TAG, instant.toEpochMilli() + " : instant.toEpochMilli()");

I got the alarm came in instantly so I checked the old way of getting milliseconds from Calendar vs java time -

1526996659862 : System.currentTimeMillis() : 
1526979300000 : instant.toEpochMilli()
1526997319862 : calendar.getTimeInMillis()

I got the localdatetime built by this -

LocalDateTime earliestDay = LocalDateTime.of(
        now.getYear(), now.getMonth().getValue(), now.getDayOfMonth(),
        localTime.getHour(), localTime.getMinute(), localTime.getSecond());

Then I get it to convert to Instant and uses ZoneOffset - UTC -

Instant instant = earliestDay.toInstant(ZoneOffset.UTC);

I'm not sure why toEpochMilliseconds isn't working as it is intended?

Calendar inputs -

Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, earliestDay.getHour());
calendar.set(Calendar.MINUTE, earliestDay.getMinute());

Solution

  •     ZoneId zone = ZoneId.of("America/Chicago");
        LocalTime alarmTime = LocalTime.of(8, 55);
    
        LocalDate today = LocalDate.now(zone);
        LocalDateTime earliestDay = today.atTime(alarmTime);
        Instant instant = earliestDay.atZone(zone).toInstant();
    
        System.out.println(instant.toEpochMilli() + " : instant.toEpochMilli()");
    
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, earliestDay.getHour());
        calendar.set(Calendar.MINUTE, earliestDay.getMinute());
    
        System.out.println(calendar.getTimeInMillis() + " : calendar.getTimeInMillis()");
    

    I set my JVM’s time zone to America/Chicago too and ran this code. Then it printed:

    1527083700000 : instant.toEpochMilli()
    1527083700796 : calendar.getTimeInMillis()
    

    The difference is 0.8 second. And it’s the Calendar that’s inaccurate since it hasn’t had its milliseconds cleared.

    When you want an alarm at 08:55 in America/Chicago time zone, you should state that and not use ZoneOffset.UTC for defining the Instant.

    As long as your time zone is America/Chicago, you may consider using ZoneId.systemDefault() for the zone. The default setting may be changed at any time from other parts of your program or other programs running in the same JVM, which might lead to surprises.