Réglez l'heure sur 00:00:00


121

J'ai un problème pour réinitialiser les heures en Java. Pour une date donnée, je souhaite régler les heures sur 00:00:00.

Voici mon code:

/**
     * Resets milliseconds, seconds, minutes and hours from the provided date
     *
     * @param date
     * @return
     */
    public static Date trim(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR, 0);

        return calendar.getTime();
    }

Le problème est que parfois l'heure est 12:00:00et parfois elle l'est 00:00:00et lorsque j'interroge la base de données pour une entité qui a été enregistrée 07.02.2013 00:00:00et l'heure réelle de l'entité, qui est stockée, 12:00:00la requête échoue.

Je le sais 12:00:00 == 00:00:00!

J'utilise AppEngine. S'agit-il d'un bogue, d'un problème ou d'un autre problème avec Appengine? Ou cela dépend-il d'autre chose?


Cela pourrait-il avoir quelque chose à voir avec différents paramètres régionaux ou cela se produit-il à partir du même PC tout le temps?
LostBoy

cela se produit lorsque je déploie sur appengine.
Adelin

Beaucoup d'autres solutions pour réduire le temps: stackoverflow.com/a/1908955/2646526
heenenee

Pour info, les anciennes classes de date-heure gênantes telles que java.util.Date, java.util.Calendaret java.text.SimpleDateFormatsont maintenant héritées , supplantées par les classes java.time intégrées à Java 8 et Java 9. Voir le didacticiel d'Oracle .
Basil Bourque

1
Je l'ai utilisé calendar.set(Calendar.HOUR_OF_DAY, 0);, pour mon but, ça marche bien.
hariprasad le

Réponses:


209

Utilisez une autre constante au lieu de Calendar.HOUR, utilisez Calendar.HOUR_OF_DAY.

calendar.set(Calendar.HOUR_OF_DAY, 0);

Calendar.HOURutilise 0-11 (pour une utilisation avec AM / PM) et Calendar.HOUR_OF_DAYutilise 0-23.

Pour citer les Javadocs:

public static final int HOUR

Numéro de champ pour obtenir et régler indiquant l'heure du matin ou de l'après-midi. HOUR est utilisé pour l'horloge de 12 heures (0 - 11). Midi et minuit sont représentés par 0, pas par 12. Par exemple, à 10: 04: 15.250 PM, l'HEURE est 10.

et

public static final int HOUR_OF_DAY

Numéro de champ pour obtenir et définir indiquant l'heure de la journée. HOUR_OF_DAY est utilisé pour l'horloge de 24 heures. Par exemple, à 10: 04: 15.250 PM, HOUR_OF_DAY est 22.

Test ("maintenant" est actuellement d'environ 14 h 55 le 23 juillet 2013, heure avancée du Pacifique):

public class Main
{
   static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args)
    {
        Calendar now = Calendar.getInstance();
        now.set(Calendar.HOUR, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        System.out.println(sdf.format(now.getTime()));
        now.set(Calendar.HOUR_OF_DAY, 0);
        System.out.println(sdf.format(now.getTime()));
    }
}

Production:

$ javac Main.java
$ java Main
2013-07-23 12:00:00
2013-07-23 00:00:00

3
@JarrodRoberson Mais utiliser Calendar.HOURne définirait pas PM sur AM, le laissant à midi.
rgettman

Pouvez-vous s'il vous plaît m'aider à construire une LocalDate avec heures, minutes et secondes? Je sais qu'une option est de suivre DateTime.
Woody

11
Celui qui a créé le champ HOUR et HOUR_OF_DAY aurait dû être fouetté et mis sous rations.
AndroidDev

1
@AndroidDev, celui qui a inventé am / pm mérite la même chose ... Cela vaut également pour les normes non métriques
Dédié le

1
Pour info, les anciennes classes de date-heure gênantes telles que java.util.Date, java.util.Calendaret java.text.SimpleDateFormatsont maintenant héritées , supplantées par les classes java.time intégrées à Java 8 et Java 9. Voir le didacticiel d'Oracle .
Basil Bourque

29

java.time

Utilisation du java.timeframework intégré à Java 8 et versions ultérieures. Voir le didacticiel .

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

Si vous n'avez pas besoin de temps de la journée (heure, minute, seconde, etc.), envisagez d'utiliser la LocalDateclasse.

LocalDate.now(); # 2015-11-19

Cela devrait être la nouvelle réponse acceptée depuis la sortie de Java 1.8 depuis que cette question a été posée pour la première fois.
matt forsythe le

LocalDateTimeest exactement la mauvaise classe à utiliser pour cela. Il ne peut pas représenter un moment car il ne dispose d'aucun concept de fuseau horaire ou de décalage par rapport à UTC. Appeler LocalDateTime.nown'a presque jamais de sens. Utilisez ZonedDateTimeplutôt. Sinon, vous ignorez les problèmes cruciaux de fuseau horaire. D'une part, certaines dates dans certaines zones ne commencent pas à 00h00!
Basil Bourque

12

Voici quelques fonctions utilitaires que j'utilise pour faire exactement cela.

/**
 * sets all the time related fields to ZERO!
 *
 * @param date
 *
 * @return Date with hours, minutes, seconds and ms set to ZERO!
 */
public static Date zeroTime( final Date date )
{
    return DateTimeUtil.setTime( date, 0, 0, 0, 0 );
}

/**
 * Set the time of the given Date
 *
 * @param date
 * @param hourOfDay
 * @param minute
 * @param second
 * @param ms
 *
 * @return new instance of java.util.Date with the time set
 */
public static Date setTime( final Date date, final int hourOfDay, final int minute, final int second, final int ms )
{
    final GregorianCalendar gc = new GregorianCalendar();
    gc.setTime( date );
    gc.set( Calendar.HOUR_OF_DAY, hourOfDay );
    gc.set( Calendar.MINUTE, minute );
    gc.set( Calendar.SECOND, second );
    gc.set( Calendar.MILLISECOND, ms );
    return gc.getTime();
}

6

Une autre façon JAVA 8:

LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);

Mais il est beaucoup plus utile de modifier la date qui existe déjà.


1
LocalDateTimene peut pas représenter un moment, car il ne dispose d'aucun concept de fuseau horaire ou de décalage par rapport à UTC. Appeler LocalDateTime.nown'a presque jamais de sens. Vous devriez utiliser à la ZonedDateTimeplace.
Basil Bourque

3

Vous feriez mieux de définir principalement le fuseau horaire sur le composant DateFormat comme ceci:

DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

Ensuite, vous pouvez obtenir l'heure "00:00:00" en passant 0 millisecondes au formateur:

String time = dateFormat.format(0);

ou vous pouvez créer un objet Date:

Date date = new Date(0); // also pass milliseconds
String time = dateFormat.foramt(date);

ou vous pouvez avoir plus de possibilités en utilisant le composant Calendrier, mais vous devez également définir le fuseau horaire comme GMT pour l'instance de calendrier:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US);
calendar.set(Calendar.HOUR_OF_DAY, 5);
calendar.set(Calendar.MINUTE, 37);
calendar.set(Calendar.SECOND, 27);

dateFormat.format(calendar.getTime());

2

tl; dr

myJavaUtilDate                                 // The terrible `java.util.Date` class is now legacy. Use *java.time* instead.
.toInstant()                                   // Convert this moment in UTC from the legacy class `Date` to the modern class `Instant`.
.atZone( ZoneId.of( "Africa/Tunis" ) )         // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
.toLocalDate()                                 // Extract the date-only portion.
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )   // Determine the first moment of that date in that zone. The day does *not* always start at 00:00:00.

java.time

Vous utilisez de terribles vieilles classes date-heure qui ont été supplantées il y a des années par les classes java.time modernes définies dans JSR 310.

DateInstant

A java.util.Datereprésente un moment UTC. Son remplacement est Instant. Appelez les nouvelles méthodes de conversion ajoutées aux anciennes classes.

Instant instant = myJavaUtilDate.toInstant() ;

Fuseau horaire

Spécifiez le fuseau horaire dans lequel vous souhaitez que votre nouvelle heure ait du sens.

Indiquez un nom de fuseau horaire approprié dans le format Continent/Region, tels que America/Montreal, Africa/Casablancaou Pacific/Auckland. N'utilisez jamais l'abréviation de 2 à 4 lettres comme ESTou ISTcar ce ne sont pas de vrais fuseaux horaires, ni standardisés, ni même uniques (!)

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

ZonedDateTime

Appliquez le ZoneIdpour Instantobtenir un ZonedDateTime. Même moment, même point sur la chronologie, mais heure d'horloge murale différente.

ZonedDateTime zdt = instant.atZone( z ) ;

Changement d'heure

Vous avez demandé à changer l'heure de la journée. Appliquer a LocalTimepour changer toutes les parties de l'heure: heure, minute, seconde, fraction de seconde. Un nouveau ZonedDateTimeest instancié, avec des valeurs basées sur l'original. Les classes java.time utilisent ce modèle d' objets immuables pour assurer la sécurité des threads .

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.
ZonedDateTime zdtAtThreeThirty = zdt.with( lt ) ; 

Premier moment de la journée

Mais vous avez demandé spécifiquement 00h00. Donc, apparemment, vous voulez le premier moment de la journée. Attention: certains jours dans certaines zones ne commencent pas à 00h00. Ils peuvent démarrer à une autre heure telle que 01:00:00 en raison d'anomalies telles que l'heure d'été (DST).

Laissez java.time déterminer le premier moment. Extrayez la partie datée uniquement. Passez ensuite le fuseau horaire pour obtenir le premier moment.

LocalDate ld = zdt.toLocalDate() ;
ZonedDateTime zdtFirstMomentOfDay = ld.atStartOfDay( z ) ;

Ajuster à UTC

Si vous devez revenir à UTC, extrayez un fichier Instant.

Instant instant = zdtFirstMomentOfDay.toInstant() ;

InstantDate

Si vous avez besoin d'un java.util.Datepour interagir avec l'ancien code pas encore mis à jour vers java.time , convertissez.

java.util.Date d = java.util.Date.from( instant ) ;

1

Faire cela pourrait être plus facile (dans Java 8)

LocalTime.ofNanoOfDay(0)

Merci, j'ai travaillé avec d'autres trucs ces 2 dernières années, et Java 6/7 avant. Je suis de retour à Java maintenant (après avoir travaillé avec peu de choses sur Groovy) et j'aime les différences de Java 8.
meszias

1

Nous pouvons définir la partie d'heure java.util.Date sur 00:00:00 en utilisant la classe LocalDate de l' API Java 8 / Joda-datetime :

Date datewithTime = new Date() ; // ex: Sat Apr 21 01:30:44 IST 2018
LocalDate localDate = LocalDate.fromDateFields(datewithTime);
Date datewithoutTime = localDate.toDate(); // Sat Apr 21 00:00:00 IST 2018

1

Si vous avez besoin du format 00:00:00 dans une chaîne, vous devez utiliser SimpleDateFormat comme ci-dessous. Utiliser "H" au lieu de "h".

Date today = new Date();
SimpleDateFormat ft = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); 
//not SimpleDateFormat("dd-MM-yyyy hh:mm:ss")
Calendar calendarDM = Calendar.getInstance();
calendarDM.setTime(today);
calendarDM.set(Calendar.HOUR, 0);
calendarDM.set(Calendar.MINUTE, 0);
calendarDM.set(Calendar.SECOND, 0);
System.out.println("Current Date: " + ft.format(calendarDM.getTime()));

//Result is: Current Date: 29-10-2018 00:00:00

0

Une autre façon de faire cela serait d'utiliser un DateFormat sans aucune seconde:

public static Date trim(Date date) {
    DateFormat format = new SimpleDateFormat("dd.MM.yyyy");
    Date trimmed = null;
    try {
        trimmed = format.parse(format.format(date));
    } catch (ParseException e) {} // will never happen
    return trimmed;
}

0

Vous pouvez faire cela avec les éléments suivants:

Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth, 0, 0, 0);
Date date = cal.getTime();

0

Comme Java8 ajoute de nouvelles fonctions de date, nous pouvons le faire facilement.


    // If you have instant, then:
    Instant instant1 = Instant.now();
    Instant day1 = instant1.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day1); //2019-01-14T00:00:00Z

    // If you have Date, then:
    Date date = new Date();
    Instant instant2 = date.toInstant();
    Instant day2 = instant2.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day2); //2019-01-14T00:00:00Z

    // If you have LocalDateTime, then:
    LocalDateTime dateTime = LocalDateTime.now();
    LocalDateTime day3 = dateTime.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day3); //2019-01-14T00:00
    String format = day3.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    System.out.println(format);//2019-01-14T00:00:00


LocalDateTimene peut pas représenter un moment, car il ne dispose d'aucun concept de fuseau horaire ou de décalage par rapport à UTC. Appeler LocalDateTime.nown'a presque jamais de sens. Vous devriez utiliser à la ZonedDateTimeplace.
Basil Bourque
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.