tiempo - pedir hora en java




Obtén milisegundos hasta la medianoche (4)

Estoy creando un widget de Android que quiero actualizar todas las noches a la medianoche. Estoy usando un AlarmManager y necesito saber cuántos milisegundos quedan de la hora actual hasta la medianoche. Aquí está mi código:

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

¿Cómo puedo calcular cuántos milisegundos quedan hasta la medianoche?

Gracias de antemano.


tl; dr

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

java.time

Java 8 y java.time posteriores vienen con el marco java.time incorporado. Estas nuevas clases sustituyen a las antiguas clases de fecha y hora (java.util.Date/.Calendar) incluidas en Java. También reemplaza a Joda-Time, desarrollado por las mismas personas. Gran parte de la funcionalidad de java.time está respaldada a Java 6 y 7, y se adapta aún más a Android (ver más abajo).

Una zona horaria es crucial para determinar una fecha. Para un momento dado, la fecha varía alrededor del mundo por zona. Por ejemplo, unos pocos minutos después de la medianoche en París, Francia es un nuevo día, mientras que todavía es "ayer" en Montreal Quebec .

Especifique un nombre de zona horaria adecuado en el formato de continent/region , como America/Montreal , Africa/Casablanca o Pacific/Auckland . Nunca use la abreviatura de 3 a 4 letras, como EST o IST ya que no son zonas horarias verdaderas, no están estandarizadas y ni siquiera son únicas (!).

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

Queremos obtener la cantidad de milisegundos hasta el primer momento del día siguiente, pero sin incluirlo.

Debemos pasar por la clase LocalDate para llegar al primer momento del día. Así que aquí comenzamos con un ZonedDateTime para obtener un LocalDate , y después de eso obtenemos otro ZonedDateTime . La clave es llamar a atStartOfDay en LocalDate .

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

Tenga en cuenta que no programamos el código de una hora del día a las 00:00:00. Debido a anomalías, como el horario de verano (DST), el día puede comenzar en otro momento como 01:00:00. Deja que java.time determine el primer momento.

Ahora podemos calcular el tiempo transcurrido. En java.time usamos la clase Duration . El marco java.time tiene una resolución más fina de nanosegundos en lugar de los milisegundos más gruesos utilizados tanto por java.util.Date como por Joda-Time. Pero la Duration incluye un método getMillis práctico, como lo solicitó la Pregunta.

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

Vea este código en vivo en IdeOne.com .

now.toString (): 2017-05-02T12: 13: 59.379-04: 00 [América / Montreal]

tomorrowStart.toString (): 2017-05-03T00: 00-04: 00 [América / Montreal]

milisegundos hasta mañana: 42360621

Acerca de java.time

El marco java.time está integrado en Java 8 y java.time posteriores. Estas clases sustituyen a las antiguas y problemáticas clases de fecha y hora como java.util.Date , Calendar y SimpleDateFormat .

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busca para muchos ejemplos y explicaciones. La especificación es JSR 310 .

Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No se necesitan cadenas, no se necesitan clases java.sql.* .

¿Dónde obtener las clases java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 y posteriores
    • Incorporado.
    • Parte de la API de Java estándar con una implementación en paquete.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de java.time está respaldada a Java 6 y 7 en ThreeTen-Backport .
  • Android
    • Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time .
    • Para Android anterior (<26), el proyecto ThreeTen-Backport adapta ThreeTen-Backport (mencionado anteriormente). Vea Cómo usar ThreeTenABP… .

Tiempo de joda

ACTUALIZACIÓN: El proyecto Joda-Time ahora está en modo de mantenimiento , con el equipo que aconseja la migración a las clases de java.time . Dejo esta sección intacta por el bien de la historia, pero recomiendo usar java.time y ThreeTenABP como se explicó anteriormente.

En Android, debe utilizar la biblioteca Joda-Time lugar de las clases Java.util.Date/.Calendar notoriamente problemáticas.

Joda-Time ofrece un comando de milisegundos de día . Pero realmente no necesitamos eso aquí.

En su lugar, solo necesitamos un objeto Duration para representar el intervalo de tiempo hasta el primer momento del día siguiente.

La zona horaria es crítica aquí para determinar cuándo comienza el "mañana". En general, es mejor especificar que depender implícitamente de la zona horaria predeterminada actual de la JVM, que puede cambiar en cualquier momento. O si realmente desea que el valor predeterminado de la JVM, pida eso explícitamente con la llamada a DateTimeZone.getDefault para que su código se autodocumente.

Podría ser una de dos líneas.

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

Vamos a separar eso.

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

Volcar a la consola.

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

Cuando se ejecuta

Desde hoy: 2015-09-20T19: 45: 43.432-04: 00 hasta mañana: 2015-09-21T00: 00: 00.000-04: 00 es 15256568 ms.


¿Funcionaría esto?

long MILLIS_IN_DAY = 86400000;

long currentTime = System.currentTimeInMillis();

long millisTillNow = currentTime % MILLIS_IN_DAY;

long millisecondsUntilMidnight = MILLIS_IN_DAY - millisTillNow;

Puede usar AlarmManager.RTC lugar de AlarmManager.ELAPSED_REALTIME , y simplemente establecer un calendario a la hora que desee:

// 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
);

Usando la siguiente manera, no hay necesidad de preocuparse por la configuración de 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()));




milliseconds