Подтвердить что ты не робот

Получать миллисекунды до полуночи

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

AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(android.content.Context.ALARM_SERVICE);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, millisecondsUntilMidnight, mSrvcPendingingIntent);

Как рассчитать, сколько миллисекунд осталось до полуночи?

Спасибо заранее.

4b9b3361

Ответ 1

Используйте Календар для его вычисления:

        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        long howMany = (c.getTimeInMillis()-System.currentTimeMillis());

Ответ 2

TL;DR

Duration.between( now , tomorrowStart )
        .toMillis()

java.time

Java 8 и более поздние версии поставляются с java.time framework. Эти новые классы заменяют старые классы времени (java.util.Date/.Calendar) в комплекте с Java. Также вытесняет Joda-Time, разработанный теми же людьми. Большая часть функциональности java.time портирована на Java 6 и 7 и далее адаптирована к Android (см. Ниже).

Часовой пояс имеет решающее значение для определения даты. В любой данный момент дата изменяется по всему миру по зонам. Например, через несколько минут после полуночи в Париж Франция - это новый день, пока еще "вчера" в Монреаль Квебек.

Укажите имя часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте аббревиатуру 3-4 буквы, например EST или IST, поскольку они не являются настоящими часовыми поясами, а не стандартизированы и даже не уникальны (!).

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

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

Мы должны пройти класс LocalDate, чтобы попасть в первый момент дня. Итак, здесь мы начинаем с ZonedDateTime, чтобы получить LocalDate, а затем получим еще один ZonedDateTime. Ключ вызывает atStartOfDay на LocalDate.

LocalDate tomorrow = now.toLocalDate().plusDays(1);
ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z );

Обратите внимание, что мы не жестко кодируем время в 00:00:00. Из-за аномалий, таких как летнее время (DST), день может начинаться в другое время, например, 01:00:00. Пусть java.time определяет первый момент.

Теперь мы можем рассчитать прошедшее время. В java.time мы используем класс Duration. Рамка java.time имеет более тонкое разрешение наносекунд, а не более грубые миллисекунды, используемые как java.util.Date, так и Joda-Time. Но Duration включает удобный getMillis метод, как запросил Вопрос.

Duration duration = Duration.between( now , tomorrowStart );
long millisecondsUntilTomorrow = duration.toMillis();

Смотрите запуск кода на IdeOne.com.

now.toString(): 2017-05-02T12: 13: 59.379-04: 00 [Америка/Монреаль]

tomorrowStart.toString(): 2017-05-03T00: 00-04: 00 [Америка/Монреаль]

millisecondsUntilTomorrow: 42360621


О java.time

Структура java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые legacy классы времени, такие как java.util.Date, Calendar и SimpleDateFormat.

Проект Joda-Time, теперь режим обслуживания, советуем перейти к классам java.time.

Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация JSR 310.

Где получить классы java.time?

  • Java SE 8, Java SE 9, а затем
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональных возможностей java.time обратно переносится на Java 6 и 7 в ThreeTen-Backport.
  • Android

Joda времени

ОБНОВЛЕНИЕ: Joda-Timeтеперь проект находится в режиме обслуживания, при этом команда советует перейти на java.time. Я оставляю этот раздел неповрежденным для истории, но рекомендую использовать java.time и ThreeTenABP, как описано выше.

В Android вы должны использовать Joda-Time библиотеку, а не печально известные классы Java.util.Date/.Calendar.

Joda-Time предлагает команду миллисекунды дня. Но нам это действительно не нужно.

Вместо этого нам нужен объект Duration, чтобы отображать промежуток времени до первого момента следующего дня.

Часовой пояс здесь имеет решающее значение, чтобы определить, когда начинается "завтра". Обычно лучше указывать, чем полагаться неявно на текущий часовой пояс JVM, который может меняться в любой момент. Если вы действительно хотите использовать JVM по умолчанию, попросите это явно с вызовом DateTimeZone.getDefault, чтобы сделать ваш код самодокументированным.

Может быть двухстрочный.

DateTime now = DateTime.now( DateTimeZone.forID( "America/Montreal" ) );
long milliSecondsUntilTomorrow = new Duration( now , now.plusDays( 1 ).withTimeAtStartOfDay() ).getMillis();

Отбросьте это.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ); // Or, DateTimeZone.getDefault()
DateTime now = DateTime.now( zone );
DateTime tomorrow = now.plusDays( 1 ).withTimeAtStartOfDay();  // FYI the day does not *always* start at 00:00:00.0 time.
Duration untilTomorrow = new Duration( now , tomorrow );
long millisecondsUntilTomorrow = untilTomorrow.getMillis();

Дамп для консоли.

System.out.println( "From now : " + now + " until tomorrow : " + tomorrow + " is " + millisecondsUntilTomorrow + " ms." );

При запуске.

Отныне: 2015-09-20T19: 45: 43.432-04: 00 до завтра: 2015-09-21T00: 00: 00.000-04: 00 - 15256568 мс.

Ответ 3

Попробуйте следующее:

Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis();
c.add(Calendar.DATE, 1);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);

long millisecondsUntilMidnight = c.getTimeInMillis() - now;

AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(android.content.Context.ALARM_SERVICE);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, millisecondsUntilMidnight, mSrvcPendingingIntent);

Ответ 4

Будет ли это работать?

long MILLIS_IN_DAY = 86400000;

long currentTime = System.currentTimeInMillis();

long millisTillNow = currentTime % MILLIS_IN_DAY;

long millisecondsUntilMidnight = MILLIS_IN_DAY - millisTillNow;

Ответ 5

Вы можете использовать AlarmManager.RTC вместо AlarmManager.ELAPSED_REALTIME и просто установить календарь на нужное вам время:

// Create a calendar for midnight
Calendar todayMidnight = Calendar.getInstance();
todayMidnight.add(Calendar.DATE, 1);
todayMidnight.set(Calendar.HOUR_OF_DAY, 0);
todayMidnight.set(Calendar.MINUTE, 0);
todayMidnight.set(Calendar.SECOND, 0);

// Create an alarm going off at midnight
mAlarmManager.set(
   AlarmManager.RTC, 
   todayMidnight.getTimeInMillis(), 
   mSrvcPendingingIntent
);

Ответ 6

Используя следующий способ, вам не нужно беспокоиться о настройке DAY_OF_MONTH.

    long msInDay = 86400000;
    Calendar c = Calendar.getInstance();
    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);

    System.out.print(msInDay - (System.currentTimeMillis() - c.getTimeInMillis()));