web-dev-qa-db-fra.com

Comment obtenir l'heure de début et l'heure de fin d'une journée?

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.

88
kalman03

À moitié ouvert

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 .

  • Les structures date-heure actuelles sont Java (Java.util.Date/Calendar et Joda-Time ) utilisent des millisecondes à partir de Epoch . Mais dans Java 8, les nouvelles classes JSR 310 Java.time. * Utilisent une résolution en nanosecondes. Tout code que vous avez écrit en forçant le nombre de millisecondes du dernier moment de la journée serait incorrect si vous basculiez vers les nouvelles classes.
  • La comparaison de données provenant d'autres sources devient défectueuse si elles utilisent d'autres résolutions. Par exemple, les bibliothèques Unix utilisent généralement des secondes entières et des bases de données telles que Postgres résolvent date-heure en microsecondes.
  • Certains changements d’heure d’été ont lieu après minuit, ce qui pourrait encore compliquer les choses.

enter image description here

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.

Évitez les anciennes classes date-heure

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.

Java.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 );

Table of date-time types in Java, both modern and legacy.

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

Joda-Time

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();
85
Basil Bourque

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

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>

Java 7 et versions antérieures


Avec 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);
}

Sans 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();
}
126
RKumsher

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).

24
mprivat

Java.time

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
5
Przemek

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)

2
Fırat KÜÇÜK

Java 8 ou 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://stackoverflow.com/a/29145886/1658268

Heure locale

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.

1
SudoPlz

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

1
Alexander Chingarev

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 );
1
laur

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
0
Florin

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);
0
Siddhey Sankhe