Localdatetime в эпоху/calendar.getTimeInMillis() для менеджера тревог

Я получаю миллисекунды для диспетчера аварийных сигналов, чтобы установить повторяющийся сигнал тревоги, и я получаю странные результаты -

Я поставил будильник на 8:55

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

Затем я использовал этот метод, чтобы получить миллисекунды с эпохи (1970 г.) -

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

Я получил сигнал тревоги мгновенно, поэтому я проверил старый способ получения миллисекунд из календаря и времени Java -

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

Я получил localdatetime, созданный этим -

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

Затем я конвертирую его в Instant и использую ZoneOffset - UTC -

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

Я не уверен, почему toEpochMilliseconds не работает так, как задумано?

Входы календаря -

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

person Meep    schedule 22.05.2018    source источник
comment
В каком часовом поясе вы хотите, чтобы ваш будильник был в 8:55? Ваш Instant в 8:55 UTC, как вы и просили. Вы Calendar, кажется, находитесь в 13:55 UTC, что говорит о том, что он был создан со смещением зоны -05:00.   -  person Ole V.V.    schedule 23.05.2018
comment
Время будильника должно быть в CST. Я пытаюсь понять вашу точку зрения здесь... Мне нужно включить часовой пояс, прежде чем я вызову Instant.toEpochMilli().   -  person Meep    schedule 23.05.2018
comment
np, спасибо за название метода, дайте мне посмотреть, что я могу сделать   -  person Meep    schedule 23.05.2018
comment
Вы правильно поняли - мне нужен ZoneId : America/Chicago, который также составляет -5:00. Будильник сработал правильно. Можете ли вы опубликовать краткий ответ ниже, чтобы я мог дать вам большой палец вверх и спасибо!   -  person Meep    schedule 23.05.2018


Ответы (1)


    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()");

Я также установил часовой пояс своей JVM на Америку/Чикаго и запустил этот код. Затем он напечатал:

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

Разница составляет 0,8 секунды. И это Calendar является неточным, так как его миллисекунды не были очищены.

Если вам нужен будильник в 08:55 в часовом поясе Америки/Чикаго, вы должны указать это и не использовать ZoneOffset.UTC для определения Instant.

Если ваш часовой пояс — Америка/Чикаго, вы можете рассмотреть возможность использования ZoneId.systemDefault() для этого пояса. Настройка по умолчанию может быть изменена в любое время из других частей вашей программы или других программ, работающих в той же JVM, что может привести к неожиданностям.

person Ole V.V.    schedule 23.05.2018
comment
Да, почему-то много отзывов о ZoneOffset.UTC для Android AlarmManager и спасибо за резюме/разъяснения. - person Meep; 23.05.2018