tomar - obtener fecha java calendar
¿Cómo obtener la hora de inicio y la hora de finalización de un día? (12)
¿Cómo obtener la hora de inicio y la hora de finalización de un día?
código como este no es exacto:
private Date getStartOfDay(Date date) {
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
calendar.set(year, month, day, 0, 0, 0);
return calendar.getTime();
}
private Date getEndOfDay(Date date) {
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
calendar.set(year, month, day, 23, 59, 59);
return calendar.getTime();
}
No es exacto al milisegundo.
Java 8 o ThreeTenABP
ZonedDateTime
ZonedDateTime curDate = ZonedDateTime.now();
public ZonedDateTime startOfDay() {
return curDate
.toLocalDate()
.atStartOfDay()
.atZone(curDate.getZone())
.withEarlierOffsetAtOverlap();
}
public ZonedDateTime endOfDay() {
ZonedDateTime startOfTomorrow =
curDate
.toLocalDate()
.plusDays(1)
.atStartOfDay()
.atZone(curDate.getZone())
.withEarlierOffsetAtOverlap();
return startOfTomorrow.minusSeconds(1);
}
// based on https://.com/a/29145886/1658268
LocalDateTime
LocalDateTime curDate = LocalDateTime.now();
public LocalDateTime startOfDay() {
return curDate.atStartOfDay();
}
public LocalDateTime endOfDay() {
return startOfTomorrow.atTime(LocalTime.MAX); //23:59:59.999999999;
}
// based on https://.com/a/36408726/1658268
Espero que ayude a alguien.
Medio abierto
La respuesta de mprivat es correcta. Su punto es no intentar obtener el final de un día, sino compararlo con "antes del inicio del día siguiente". Su idea se conoce como el enfoque "medio abierto", donde un lapso de tiempo tiene un comienzo que es inclusivo, mientras que el final es exclusivo .
- Los marcos actuales de fecha y hora son Java (java.util.Date/Calendar y Joda-Time ) ambos usan milisegundos de la epoch . Pero en Java 8, las nuevas clases JSR 310 java.time. * Usan una resolución de nanosegundos. Cualquier código que haya escrito basándose en forzar el recuento de milisegundos del último momento del día sería incorrecto si se cambia a las nuevas clases.
- Comparar datos de otras fuentes se vuelve defectuoso si emplean otras resoluciones. Por ejemplo, las librerías de Unix típicamente emplean segundos enteros, y las bases de datos como Postgres resuelven la fecha-hora en microsegundos.
- Algunos cambios en el horario de verano ocurren más allá de la medianoche, lo que puede confundir aún más las cosas.
Joda-Time 2.3 ofrece un método para este propósito, obtener el primer momento del día: con withTimeAtStartOfDay()
. Del mismo modo en java.time, LocalDate::atStartOfDay
.
Busque para "joda half-open" para ver más discusión y ejemplos.
Vea esta publicación, Los intervalos de tiempo y otros rangos deben estar semiabiertos , por Bill Schneider.
Evite las clases heredadas de fecha y hora
Las clases java.util.Date y .Calendar son notoriamente problemáticas. Evítales.
Use Joda-Time o, preferiblemente, java.time . El framework java.time es el sucesor oficial de la exitosa librería Joda-Time.
java.time
El marco java.time está integrado en Java 8 y posterior. Back-ported a Java 6 y 7 en el proyecto ThreeTen-Backport , más adaptado a Android en el proyecto ThreeTenABP .
Un Instant
es un momento en la línea de tiempo en UTC con una resolución de nanoseconds .
Instant instant = Instant.now();
Aplique una zona horaria para obtener la hora del reloj de pared de alguna localidad.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Para obtener el primer momento del día, vaya a la clase LocalDate
y su método atStartOfDay
.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Usando el enfoque de Medio Abierto, obtenga el primer momento del día siguiente.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Actualmente el framework java.time carece de una clase Interval
como se describe a continuación para Joda-Time. Sin embargo, el proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es el terreno de prueba para posibles adiciones futuras a java.time. Entre sus clases está Interval
. Construye un Interval
pasando un par de objetos Instant
. Podemos extraer un Instant
de nuestros objetos ZonedDateTime
.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
Joda-Time
Joda-Time tiene tres clases para representar un lapso de tiempo de varias maneras: Interval
, Period
y Duration
. Un Interval
tiene un comienzo y un final específicos en la línea de tiempo del Universo. Esto se ajusta a nuestra necesidad de representar "un día".
Llamamos al método con withTimeAtStartOfDay
lugar de establecer la hora del día en ceros. Debido al horario de verano y otras anomalías, el primer momento del día puede no ser 00:00:00
.
Código de ejemplo usando Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
Si debe, puede convertir a java.util.Date.
java.util.Date date = todayStart.toDate();
java.time
Usando el framework java.time
integrado en Java 8.
import java.time.LocalTime;
import java.time.LocalDateTime;
LocalDateTime now = LocalDateTime.now(); // 2015-11-19T19:42:19.224
// start of a day
now.with(LocalTime.MIN); // 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); // 2015-11-19T00:00
// end of a day
now.with(LocalTime.MAX); // 2015-11-19T23:59:59.999999999
Java 8
public static Date atStartOfDay(Date date) {
LocalDateTime localDateTime = dateToLocalDateTime(date);
LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
return localDateTimeToDate(startOfDay);
}
public static Date atEndOfDay(Date date) {
LocalDateTime localDateTime = dateToLocalDateTime(date);
LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
return localDateTimeToDate(endOfDay);
}
private static LocalDateTime dateToLocalDateTime(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
private static Date localDateTimeToDate(LocalDateTime localDateTime) {
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
Actualización : he agregado estos 2 métodos a mis clases de utilidad de Java here
Está en el repositorio central de Maven en:
<dependency>
<groupId>com.github.rkumsher</groupId>
<artifactId>utils</artifactId>
<version>1.3</version>
</dependency>
Java 7 y anteriores
Con Apache Commons
public static Date atEndOfDay(Date date) {
return DateUtils.addMilliseconds(DateUtils.ceiling(date, Calendar.DATE), -1);
}
public static Date atStartOfDay(Date date) {
return DateUtils.truncate(date, Calendar.DATE);
}
Sin Apache Commons
public Date atEndOfDay(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar.getTime();
}
public Date atStartOfDay(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
¡Probé este código y funciona bien! :
Date d= new Date();
GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
String s_d=d.getYear()+"-"+(d.getMonth()+1)+"-"+d.getDay();
DateFormat dateFormat = DateFormat.getDateInstance();
try {
// for the end of day :
c.setTime(dateFormat.parse(s_d+" 23:59:59"));
// for the start of day:
//c.setTime(dateFormat .parse(s_d+" 00:00:00"));
} catch (ParseException e) {
e.printStackTrace();
}
En complemento a @BasilBourque respuesta:
Un método un poco pesado pero seguro para establecer un tiempo mínimo (solo para comenzar):
cal.setTime(...);
cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
Esto asegura que los valores mínimos son los del Calendario.
La forma adicional de encontrar el inicio del día con java8 java.time.ZonedDateTime en lugar de pasar por LocalDateTime
es simplemente truncar la entrada ZonedDateTime a DAYS:
zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );
Otra solución que no depende de ningún marco es:
static public Date getStartOfADay(Date day) {
final long oneDayInMillis = 24 * 60 * 60 * 1000;
return new Date(day.getTime() / oneDayInMillis * oneDayInMillis);
}
static public Date getEndOfADay(Date day) {
final long oneDayInMillis = 24 * 60 * 60 * 1000;
return new Date((day.getTime() / oneDayInMillis + 1) * oneDayInMillis - 1);
}
Tenga en cuenta que devuelve tiempo basado en UTC
Para java 8, las siguientes declaraciones de una sola línea están funcionando. En este ejemplo, uso la zona horaria UTC. Considere cambiar TimeZone que usa actualmente.
System.out.println(new Date());
final LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
final Date endOfDayAsDate = Date.from(endOfDay.toInstant(ZoneOffset.UTC));
System.out.println(endOfDayAsDate);
final LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
final Date startOfDayAsDate = Date.from(startOfDay.toInstant(ZoneOffset.UTC));
System.out.println(startOfDayAsDate);
Si no hay diferencia de tiempo con la salida. Pruebe: ZoneOffset.ofHours(0)
Sé que es una vieja pregunta, pero esa es mi proposición al respecto, espero que esto pueda ayudarlo:
Usando JodaTime, podemos hacer esto:
public static final Integer CURRENT_YEAR = DateTime.now().getYear(); public static final Integer CURRENT_MONTH = DateTime.now().getMonthOfYear(); public static final Integer CURRENT_DAY = DateTime.now().getDayOfMonth(); public static final Integer LAST_HOUR_OF_CURRENT_DAY = DateTime.now().hourOfDay().getMaximumValue(); public static final Integer FIRST_HOUR_OF_CURRENT_DAY = DateTime.now().hourOfDay().getMinimumValue(); public static final Integer LAST_MINUTE_OF_CURRENT_HOUR = DateTime.now().minuteOfHour().getMaximumValue(); public static final Integer FIRST_MINUTE_OF_CURRENT_HOUR = DateTime.now().minuteOfHour().getMinimumValue(); public static final Integer LAST_SECOND_OF_CURRENT_MINUTE = DateTime.now().secondOfMinute().getMaximumValue(); public static final Integer FIRST_SECOND_OF_CURRENT_MINUTE = DateTime.now().secondOfMinute().getMinimumValue();
public static DateTime getFirstDateOfDay() { return new DateTime(CURRENT_YEAR, CURRENT_MONTH, CURRENT_DAY, FIRST_HOUR_OF_CURRENT_DAY, FIRST_MINUTE_OF_CURRENT_HOUR, FIRST_SECOND_OF_CURRENT_MINUTE); } public static DateTime getLastDateOfDay() { return new DateTime(CURRENT_YEAR, CURRENT_MONTH, CURRENT_DAY, LAST_HOUR_OF_CURRENT_DAY, LAST_MINUTE_OF_CURRENT_HOUR, LAST_SECOND_OF_CURRENT_MINUTE); }
Como lo describo en mi pequeña idea aquí en github: joda time, java8 date time (utils)
en getEndOfDay, puede agregar:
calendar.set(Calendar.MILLISECOND, 999);
Aunque matemáticamente hablando, no puede especificar el final de un día más que diciendo que es "antes del comienzo del día siguiente".
Entonces, en lugar de decir, if(date >= getStartOfDay(today) && date <= getEndOfDay(today))
, debería decir: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow))
. Esa es una definición mucho más sólida (y no tiene que preocuparse por la precisión en milisegundos).
public static Date beginOfDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
public static Date endOfDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
return cal.getTime();
}