Comment obtenir l'heure de début et l'heure de fin d'une journée?
un code comme celui-ci n'est pas précis:
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();
}
Ce n'est pas précis à la milliseconde.
Le réponse de mprivat est correct. Son but est de ne pas essayer d’obtenir la fin de la journée, mais de comparer avec "avant le début du jour suivant". Son idée est connue sous le nom d’approche "semi-ouverte" dans laquelle un intervalle de temps a un début inclusif tandis que le la fin est exclusive .
Joda-Time 2.3 propose à cet effet une méthode pour obtenir le premier moment de la journée: withTimeAtStartOfDay()
. De même dans Java.time, LocalDate::atStartOfDay
.
Recherche StackOverflow pour "joda semi-ouvert" pour voir plus de discussion et d’exemples.
Voir cet article, Les intervalles de temps et autres plages doivent être à moitié ouverts , de Bill Schneider.
Les classes Java.util.Date et .Calendar sont notoirement gênantes. Évite-les.
Utilisez soit Joda-Time ou, de préférence, Java.time . Le framework Java.time est le successeur officiel de la très performante bibliothèque Joda-Time.
La structure Java.time est intégrée à Java 8 et versions ultérieures. Back-ported to Java 6 & 7 dans le projet ThreeTen-Backport , ensuite adapté à Android dans le ThreeTenABP projet.
Un Instant
est un moment sur la timeline de UTC avec une résolution de nanosecondes .
Instant instant = Instant.now();
Appliquez un fuseau horaire pour obtenir le heure de l'horloge murale pour une localité.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Pour obtenir le premier moment de la journée, utilisez la méthode LocalDate
et sa atStartOfDay
.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
En utilisant l'approche demi-ouverte, obtenez le premier moment du jour suivant.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Actuellement, la structure Java.time ne contient pas de classe Interval
, comme décrit ci-dessous pour Joda-Time. Cependant, le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est le terrain d’essai pour d’éventuels ajouts à Java.time. Parmi ses classes est Interval
. Construisez un Interval
en passant une paire d'objets Instant
. Nous pouvons extraire un Instant
de nos objets ZonedDateTime
.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
MISE À JOUR: le projet Joda-Time est maintenant en mode maintenance et conseille la migration vers les classes Java.time . Je laisse cette section intacte pour l'histoire.
Joda-Time a trois classes pour représenter une période de temps de différentes manières: Interval
, Period
et Duration
. Un Interval
a un début et une fin spécifiques sur la timeline de l'univers. Cela correspond à notre besoin de représenter "un jour".
Nous appelons la méthode withTimeAtStartOfDay
plutôt que de définir l’heure du jour à zéro. En raison de l'heure d'été et d'autres anomalies, il est possible que le premier moment de la journée ne soit pas 00:00:00
.
Exemple de code utilisant 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 vous devez, vous pouvez convertir en Java.util.Date.
Java.util.Date date = todayStart.toDate();
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());
}
Update: j'ai ajouté ces 2 méthodes à mes classes d'utilitaires Java ici
Il se trouve dans le répertoire central Maven à l'adresse:
<dependency>
<groupId>com.github.rkumsher</groupId>
<artifactId>utils</artifactId>
<version>1.3</version>
</dependency>
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);
}
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();
}
dans getEndOfDay, vous pouvez ajouter:
calendar.set(Calendar.MILLISECOND, 999);
Bien que mathématiquement parlant, vous ne pouvez pas spécifier la fin d'une journée autrement qu'en disant "avant le début du jour suivant".
Ainsi, au lieu de dire, if(date >= getStartOfDay(today) && date <= getEndOfDay(today))
, vous devriez dire: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow))
. C'est une définition beaucoup plus solide (et vous n'avez pas à vous soucier de la précision à la milliseconde).
Utilisation du framework Java.time
intégré à 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
Pour Java 8, les instructions à ligne unique suivantes fonctionnent. Dans cet exemple, j'utilise le fuseau horaire UTC. Veuillez envisager de changer le fuseau horaire que vous avez utilisé actuellement.
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 aucune différence de temps avec la sortie. Essayez: ZoneOffset.ofHours(0)
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://stackoverflow.com/a/29145886/1658268
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://stackoverflow.com/a/36408726/1658268
J'espère que cela aide quelqu'un.
Une autre solution qui ne dépend d'aucun cadre est la suivante:
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);
}
Notez qu'il renvoie l'heure UTC
Un moyen supplémentaire de rechercher le début de journée avec Java8 Java.time.ZonedDateTime au lieu de passer par LocalDateTime
consiste simplement à tronquer l'entrée ZonedDateTime en DAYS:
zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );
Je sais que c'est un peu tard, mais dans le cas de Java 8, si vous utilisez OffsetDateTime (qui offre de nombreux avantages, tels que TimeZone, Nanoseconds, etc.), vous pouvez utiliser le code suivant:
OffsetDateTime reallyEndOfDay = someDay.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
// output: 2019-01-10T23:59:59.999999999Z
J'ai essayé ce code et ça marche bien!
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
final ZonedDateTime startofDay =
now.toLocalDate().atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime endOfDay =
now.toLocalDate().atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);