Comment obtenir une date sans heure en Java?

235

Suite du programme Java de la question Stack Overflow pour obtenir la date actuelle sans horodatage :

Quelle est la façon la plus efficace d'obtenir un objet Date sans l'heure? Y a-t-il un autre moyen que ces deux-là?

// Method 1
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

// Method 2
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dateWithoutTime = cal.getTime();

Mise à jour :

  1. Je connaissais Joda-Time ; J'essaie juste d'éviter une bibliothèque supplémentaire pour une tâche aussi simple (je pense). Mais d'après les réponses jusqu'à présent, Joda-Time semble extrêmement populaire, donc je pourrais y penser.

  2. Par efficace , je veux dire que je veux éviter la Stringcréation d' objets temporaires telle qu'utilisée par method 1, en attendant, cela method 2ressemble à un hack au lieu d'une solution.

Rosdi Kasim
la source
1
Efficace? Avez-vous besoin de plus d'efficacité que ce qui est fourni, par exemple, par method1?
Johan Sjöberg
2
Qu'entendez-vous par «efficace»? Une date est essentiellement une longue saisie, vous ne pouvez pas vraiment faire ceci avec moins de mémoire que cela. Si vous voulez dire "pratique", l'heure JODA est la voie à suivre.
millimoose
3
+1 Exactement la question que j'avais.
Alba Mendez
1
J'aime la méthode 2. Créez une méthode statique dans une classe utilitaire et utilisez-la. Je suis cette approche depuis des années.
Wilson Freitas
1
Nitpicking sur votre "mise à jour 1": si c'était "une tâche si simple", je suppose que Sun ne serait pas venu à une API aussi horrible et inefficace, et vous (et beaucoup d'autres personnes) ne poseriez pas cette question du tout ;-)
Flávio Etrusco

Réponses:

108

Avez - vous absolument avoir à utiliser java.util.Date? Je bien vous recommandons d' utiliser Joda temps ou le java.timepackage de Java 8 au lieu. En particulier, alors que la date et le calendrier toujours représentent un instant particulier dans le temps, sans ce concept comme « juste une date », Joda Time ne possède un type qui représente ce ( LocalDate). Votre code sera beaucoup plus clair si vous pouvez utiliser des types qui représentent ce que vous essayez de faire.

Il existe de nombreuses autres raisons d'utiliser Joda Time ou java.timeau lieu des java.utiltypes intégrés - ce sont généralement de bien meilleures API. Vous pouvez toujours convertir vers / depuis a java.util.Dateaux limites de votre propre code si vous en avez besoin, par exemple pour l'interaction avec la base de données.

Jon Skeet
la source
75
Dans les applications d'entreprise, nous n'avons pas toujours la possibilité d'ajouter / d'utiliser d'autres bibliothèques. J'apprécie le pointeur sur Joda Time, mais ce n'est vraiment pas une réponse au problème d'origine d'obtenir la partie date en utilisant le Java standard. Merci. Revoir la réponse de Chathuranga.
noogrub
3
@noogrub: La réponse de Chathugranga ne répond pas à la question d'origine, qui demande comment obtenir un Dateobjet - cette réponse formate une date en une chaîne, ce qui n'est pas la même chose. Fondamentalement, demander à quelle date a Datelieu est une question dénuée de sens sans plus d'informations: le fuseau horaire et le système de calendrier que vous utilisez.
Jon Skeet
7
"Dans les applications d'entreprise, nous n'avons pas toujours la possibilité d'ajouter / d'utiliser d'autres bibliothèques". Vraiment ? Êtes-vous en train de suggérer que vous ne pouvez pas du tout utiliser des bibliothèques tierces?
Brian Agnew
3
Le commentaire de @BrianAgnew noogrub semble être lié à des contraintes non technologiques, je pense
Jose_GD
3
Du point de vue d'aujourd'hui: " Joda-Time est la bibliothèque de date et d'heure standard de facto pour Java avant Java SE 8. Les utilisateurs sont désormais invités à migrer vers java.time (JSR-310)."
Drux
66

Voici ce que j'ai utilisé pour obtenir la date d'aujourd'hui avec l'heure définie sur 00:00:00:

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));
Shobbi
la source
28
En quoi est-ce différent de la "méthode 1" déjà proposée dans la question initiale?
Chris
Ne traite pas du fuseau horaire dans lequel cela se produit (laissé au fuseau horaire par défaut arbitraire de la JVM).
Darrell Teague
58

Vous pouvez utiliser le DateUtils.truncate de la bibliothèque Apache Commons.

Exemple:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)
JoGo
la source
3
Si vous souhaitez ajouter une nouvelle bibliothèque, que ce soit Joda au lieu d'Apache Commons.
Dibbeke
6
+1 @Dibbeke La différence n'est pas seulement que vous ajouteriez une bibliothèque au lieu d'une autre. Parfois, on ne veut pas apprendre une toute nouvelle bibliothèque juste pour la tâche triviale de tronquer l'heure d'une date. Ou ne veut pas avoir de code qui mélange Date / Calendrier avec des dates Joda en utilisant parfois le premier et parfois le dernier. Ou ne peut pas se permettre / justifier de remplacer tout le code basé sur la date / le calendrier qui fonctionne bien par une autre bibliothèque dans un but aussi trivial. Tout en suggérant que Joda est certainement bon car il est clairement supérieur et simplement The Right Thing, parfois la vraie vie entre en jeu.
SantiBailors
Génie!
M'a
37

Y a-t-il un autre moyen que ces deux-là?

Oui il y a.

LocalDate.now( 
    ZoneId.of( "Pacific/Auckland" ) 
)

java.time

Java 8 et versions ultérieures sont livrées avec le nouveau package java.time intégré . Voir Tutoriel . Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport et adaptée à Android dans ThreeTenABP .

Semblable à Joda-Time , java.time propose une LocalDateclasse pour représenter une valeur de date uniquement sans heure et sans fuseau horaire.

Notez que le fuseau horaire est essentiel pour déterminer une date particulière. Par exemple, à minuit à Paris, la date est encore «hier» à Montréal.

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;

Par défaut, java.time utilise la norme ISO 8601 pour générer une représentation sous forme de chaîne d'une date ou d'une date-heure. (Une autre similitude avec Joda-Time.) Il suffit donc d'appeler toString()pour générer du texte comme 2015-05-21.

String output = today.toString() ; 

À propos de java.time

Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que java.util.Date, Calendar, et SimpleDateFormat.

Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .

Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Où obtenir les classes java.time?

  • Java SE 8 , Java SE 9 et versions ultérieures
    • Intégré.
    • Une partie de l'API Java standard avec une implémentation groupée.
    • Java 9 ajoute quelques fonctionnalités et correctifs mineurs.
  • Java SE 6 et Java SE 7
    • Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport .
  • Android

Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à java.time. Vous trouverez peut - être des classes utiles ici, comme Interval, YearWeek, YearQuarteret plus .

Basil Bourque
la source
1
Merci d'avoir mentionné le fuseau horaire . Il ne m'était pas venu à l'esprit que «quel jour c'était» n'est pas un concept absolu.
ToolmakerSteve
@ToolmakerSteve L'obtention de la date implique toujours un fuseau horaire. Mais l'astuce est que si vous ne spécifiez pas de fuseau horaire, le fuseau horaire par défaut actuel de votre machine virtuelle Java est automatiquement appliqué pour déterminer la date. En plus de cela, le fuseau horaire par défaut actuel de la JVM peut changer à tout moment ! Tout code dans n'importe quel thread de n'importe quelle application de la JVM peut appeler TimeZone.setDefaultpendant l'exécution et affecter immédiatement tout autre code exécuté dans cette JVM. Morale de l'histoire: spécifiez toujours un fuseau horaire.
Basil Bourque
22

La manière la plus simple:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);
romain
la source
5
Pour moi, c'est actuellement: "Sam Feb 19 01 : 00: 00 CET 2011". Si vous souhaitez l'utiliser, alors uniquement avec UTC.
Chris Lercher
4
La ligne 3 n'est-elle pas long dateOnly = (currentTime / millisInDay) * millisInDay;identique à l'écriture long dateOnly = currentTime;?
Chris
5
Ce n'est pas le cas, à cause des mathématiques entières. Pensez-y plutôt comme Math.floor (currentTime / millisInDay) * millisInDay. Il définit effectivement l'heure à 00:00:00 de cette façon.
Nicholas Flynt
2
Cette solution convient probablement à la plupart des applications, mais sachez que l'hypothèse qu'un jour a 60 * 60 * 24 * 1000 n'est pas toujours vraie. Vous pouvez par exemple avoir des secondes intercalaires en quelques jours.
Pierre-Antoine
1
C'est sans doute le moyen le plus obtus et non recommandé par rapport aux autres méthodes claires et concises à 1 et 2 lignes.
Darrell Teague
22

La réponse standard à ces questions est d'utiliser Joda Time . L'API est meilleure et si vous utilisez les formateurs et les analyseurs, vous pouvez éviter le manque non intuitif de sécurité des threads SimpleDateFormat.

Utiliser Joda signifie que vous pouvez simplement faire:

LocalDate d = new LocalDate();

Update :: Using java 8 this can be acheived using

LocalDate date = LocalDate.now();
Brian Agnew
la source
Le nouveau package java.time de Java 8 propose également une LocalDateclasse similaire à Joda-Time.
Basil Bourque
1
Idéalement, vous DateTimeZonepasseriez un à ce constructeur LocalDate. La détermination de la date actuelle dépend du fuseau horaire, car Paris commence une nouvelle date plus tôt que Montréal. Si vous omettez le fuseau horaire, le fuseau horaire par défaut de votre JVM est appliqué. Il est généralement préférable de spécifier que de se fier à la valeur par défaut.
Basil Bourque
8

C'est une façon simple de le faire:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));
Glen
la source
4
Cette réponse ne répond pas à la question. L'obtention d'une chaîne formatée n'était pas l'objectif.
Basil Bourque
7

Il n'est pas logique de parler d'une date sans horodatage en ce qui concerne les routines Date dans l'exécution Java standard, car elle correspond essentiellement à une milliseconde spécifique et non à une date. Cette milliseconde est intrinsèquement associée à une heure de la journée, ce qui la rend vulnérable aux problèmes de fuseau horaire tels que l'heure d'été et d'autres ajustements de calendrier. Voir Pourquoi soustraire ces deux fois (en 1927) donne-t-il un résultat étrange? pour un exemple intéressant.

Si vous souhaitez travailler avec des dates au lieu de millisecondes, vous devez utiliser autre chose. Pour Java 8, il existe un nouvel ensemble de méthodes fournissant exactement ce que vous demandez. Pour Java 7 et versions antérieures, utilisez http://www.joda.org/joda-time/

Thorbjørn Ravn Andersen
la source
3
Remarque: ces approches indiquant "la date à minuit" ne gèrent pas bien l'heure d'été et les fuseaux horaires multiples.
Thorbjørn Ravn Andersen
Je le confirme, j'augmentais les dates d'un jour dans mon application, et j'ai appris cela avec un rapport de bogue d'utilisateurs dans un fuseau horaire avec DST (mon pays n'utilise pas DST). Le jour où l'heure d'été commence, mon application ajoute 11 heures au lieu de 12. Peut-être qu'il vaut mieux utiliser midi comme heure de non-présentation?
Jose_GD
1
@Jose_GD C'est au mieux encore un hack. Vous pourriez trouver youtube.com/watch?v=-5wpm-gesOY divertissant.
Thorbjørn Ravn Andersen du
@ Thorbjorn, vous avez raison, je voulais juste éviter JodaTime parce que l'ajout d'une bibliothèque pour une seule fonctionnalité son surpasse pour moi. Je connaissais cette vidéo, drôle en effet.
Jose_GD
1
@Jose_GD Le fait était qu'il existe un cas d'utilisation réel dans la vie réelle dans lequel votre approche serait considérée comme un bug. Si vous en avez trouvé un, il pourrait y en avoir plus ... Je ne sais pas comment Joda gère cela, mais vous pourriez jeter un œil. Notez également que Java 8 apporte une nouvelle bibliothèque date-heure (basée sur les expériences avec Joda) que vous voudrez peut-être étudier.
Thorbjørn Ravn Andersen
4

Certainement pas la manière la plus correcte, mais si vous avez juste besoin d'une solution rapide pour obtenir la date sans l'heure et que vous ne souhaitez pas utiliser une bibliothèque tierce, cela devrait faire

    Date db = db.substring(0, 10) + db.substring(23,28);

Je n'avais besoin de la date qu'à des fins visuelles et je ne pouvais pas Joda donc j'ai sous-chaîne.

Bamz
la source
4
// 09/28/2015
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(Calendar.getInstance().getTime()));

// Mon Sep 28
System.out.println( new Date().toString().substring(0, 10) );

// 2015-09-28
System.out.println(new java.sql.Date(System.currentTimeMillis()));

// 2015-09-28
// java 8
System.out.println( LocalDate.now(ZoneId.of("Europe/Paris")) ); // rest zones id in ZoneId class
myrtille0xff
la source
3

Pour autant que je sache, il n'y a pas de moyen plus simple d'y parvenir si vous utilisez uniquement le JDK standard.

Vous pouvez, bien sûr, mettre cette logique dans method2 dans une fonction statique dans une classe d'assistance, comme cela est fait ici dans la méthode toBeginningOfTheDay

Ensuite, vous pouvez raccourcir la deuxième méthode pour:

Calendar cal = Calendar.getInstance();
Calendars.toBeginningOfTheDay(cal);
dateWithoutTime = cal.getTime();

Ou, si vous avez vraiment besoin de la journée en cours dans ce format si souvent, vous pouvez simplement l'envelopper dans une autre méthode d'assistance statique, ce qui en fait une ligne unique.

Enduriel
la source
3

Si tout ce que vous voulez est de voir la date comme "AAAA-MM-JJ" sans tous les autres fouillis, par exemple "jeu 21 mai 12:08:18 EDT 2015", utilisez simplement java.sql.Date. Cet exemple obtient la date actuelle:

new java.sql.Date(System.currentTimeMillis());

Est également java.sql.Dateune sous-classe de java.util.Date.

BigMac66
la source
3

Si vous avez juste besoin de la date actuelle, sans heure, une autre option est:

DateTime.now().withTimeAtStartOfDay()
user3037726
la source
1
La question ne demandait pas d'heure. Votre résultat est un objet date-heure qui a en effet une heure du jour, cette heure étant 00:00:00généralement (peut varier selon le fuseau horaire pour des anomalies telles que l' heure d' été ). Ainsi, comme le notent d'autres réponses, la LocalDateclasse est plus appropriée, à partir de Joda-Time (en supposant que vous faites référence à Joda-Time - que vous devriez noter explicitement lorsque vous citez des classes non fournies avec Java).
Basil Bourque
3

Utilisez LocalDate.now()et convertissez en Datecomme ci-dessous:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
Sahil Chhabra
la source
1
Le fuseau horaire par défaut actuel de la JVM peut changer à tout moment pendant l'exécution. Tout code dans n'importe quel thread de n'importe quelle application de la JVM peut appeler TimeZone.setDefault. Votre code appelle ZoneId.systemDefaultdeux fois, le premier est implicite dans LocalDate.now()et le second est explicite avec atStartOfDay. Entre ces deux moments à l'exécution, la zone par défaut actuelle pourrait changer. Je suggère de capturer la zone dans une variable et de passer aux deux méthodes.
Basil Bourque
2

Si vous avez besoin de la partie date juste pour faire écho, alors

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);
manish_s
la source
1
Je ne pense pas que ce soit convivial pour i18n
Mark Lapasa
2

Et ça?

public static Date formatStrictDate(int year, int month, int dayOfMonth) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, dayOfMonth, 0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}
vitiello.antonio
la source
1

Découvrez l' heure de Veyder . C'est une alternative simple et efficace à la fois à java.util et à Joda-time. Il dispose d'une API et de classes intuitives qui représentent uniquement les dates, sans horodatage.

lonerook
la source
1

La manière la plus directe qui utilise pleinement l'énorme base de données TimeZone de Java et est correcte:

long currentTime = new Date().getTime();
long dateOnly = currentTime + TimeZone.getDefault().getOffset(currentTime);
TomWolk
la source
1

Voici une solution propre sans conversion en chaîne et retour, et elle ne recalcule pas le temps plusieurs fois lorsque vous réinitialisez chaque composant du temps à zéro. Il utilise également %(module) plutôt que de diviser suivi de multiplier pour éviter la double opération.

Elle ne nécessite aucune dépendance tierce et RESPECTE LA FUSEAU HORAIRE DE L'OBJET CALENDRE passé. Cette fonction retourne l'instant à 12 h 00 dans le fuseau horaire de la date (calendrier) que vous passez.

public static Calendar date_only(Calendar datetime) {
    final long LENGTH_OF_DAY = 24*60*60*1000;
    long millis = datetime.getTimeInMillis();
    long offset = datetime.getTimeZone().getOffset(millis);
    millis = millis - ((millis + offset) % LENGTH_OF_DAY);
    datetime.setTimeInMillis(millis);
    return datetime;
}
Brent Larsen
la source
Je ne suis pas très convaincu qu'il respectera la tme d'été (DST)?
Ole VV
0

Préférez ne pas utiliser autant que possible des bibliothèques tierces. Je sais que cette façon est mentionnée auparavant, mais voici une belle façon propre:

  /*
    Return values:
    -1:    Date1 < Date2
     0:    Date1 == Date2
     1:    Date1 > Date2

    -2:    Error
*/
public int compareDates(Date date1, Date date2)
{
    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");

    try
    {
        date1 = sdf.parse(sdf.format(date1));
        date2 = sdf.parse(sdf.format(date2));
    }
    catch (ParseException e) {
        e.printStackTrace();
        return -2;
    }

    Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();

    cal1.setTime(date1);
    cal2.setTime(date2);

    if(cal1.equals(cal2))
    {
        return 0;
    }
    else if(cal1.after(cal2))
    {
        return 1;
    }
    else if(cal1.before(cal2))
    {
        return -1;
    }

    return -2;
}

Eh bien, ne pas utiliser GregorianCalendar est peut-être une option!

hehe
la source
0

Je viens de faire cela pour mon application:

public static Date getDatePart(Date dateTime) {
    TimeZone tz = TimeZone.getDefault();
    long rawOffset=tz.getRawOffset();
    long dst=(tz.inDaylightTime(dateTime)?tz.getDSTSavings():0);
    long dt=dateTime.getTime()+rawOffset+dst; // add offseet and dst to dateTime
    long modDt=dt % (60*60*24*1000) ;

    return new Date( dt
                    - modDt // substract the rest of the division by a day in milliseconds
                    - rawOffset // substract the time offset (Paris = GMT +1h for example)
                    - dst // If dayLight, substract hours (Paris = +1h in dayLight)
    );
}

API Android niveau 1, pas de bibliothèque externe. Il respecte la lumière du jour et la zone horaire par défaut. Aucune manipulation de chaîne, donc je pense que cette méthode est plus efficace que la vôtre, mais je n'ai fait aucun test.

Elloco
la source
0

Vous pouvez utiliser le temps Joda.

private Date dateWitoutTime(Date date){
 return new LocalDate(date).toDate()
}

et vous appelez avec:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
Jesús Sánchez
la source