Différence de jours entre deux dates en Java?
j'ai besoin de trouver la nombre de jours entre deux dates : l'un est à partir d'un rapport et un est la date actuelle. Mon extrait de:
int age=calculateDifference(agingDate, today);
ici calculateDifference
est une méthode privée, agingDate
et today
sont des objets Date
, juste pour votre clarification. J'ai suivi deux articles d'un forum Java, Thread 1 / Thread 2 .
Il fonctionne très bien dans un programme autonome bien que lorsque je l'inclus dans ma logique de lire à partir du rapport, je reçois une différence inhabituelle dans les valeurs.
pourquoi cela se produit - il et comment puis-je le réparer?
EDIT:
je reçois un plus grand nombre de jours par rapport à la quantité réelle de jours.
public static int calculateDifference(Date a, Date b)
{
int tempDifference = 0;
int difference = 0;
Calendar earlier = Calendar.getInstance();
Calendar later = Calendar.getInstance();
if (a.compareTo(b) < 0)
{
earlier.setTime(a);
later.setTime(b);
}
else
{
earlier.setTime(b);
later.setTime(a);
}
while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR))
{
tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR));
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR))
{
tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR);
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
return difference;
}
Note:
malheureusement, aucune des réponses m'a aidé à résoudre le problème. J'ai accompli ce problème avec l'aide de Joda-time bibliothèque.
20 réponses
je vous suggérerais d'utiliser l'excellente bibliothèque Joda Time à la place du java défectueux.util.Date et amis. Vous pouvez simplement écrire
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.Days;
Date past = new Date(110, 5, 20); // June 20th, 2010
Date today = new Date(110, 6, 24); // July 24th
int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34
il est peut-être trop tard pour me joindre au jeu, mais qu'est-ce qui se passe? :)
pensez-vous qu'il s'agit d'un problème de threading? Comment utilisez-vous la sortie de cette méthode, par exemple? Ou
Peut-on changer votre code pour faire quelque chose d'aussi simple que:
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(<your earlier date>);
calendar2.set(<your current date>);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffSeconds = diff / 1000;
long diffMinutes = diff / (60 * 1000);
long diffHours = diff / (60 * 60 * 1000);
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("\nThe Date Different Example");
System.out.println("Time in milliseconds: " + diff
+ " milliseconds.");
System.out.println("Time in seconds: " + diffSeconds
+ " seconds.");
System.out.println("Time in minutes: " + diffMinutes
+ " minutes.");
System.out.println("Time in hours: " + diffHours
+ " hours.");
System.out.println("Time in days: " + diffDays
+ " days.");
}
la différence / (24 * etc) ne prend pas en compte le fuseau horaire, donc si votre fuseau horaire par défaut contient un DST, il peut annuler le calcul.
Ce lien a une jolie petite mise en œuvre.
Voici la source du lien ci-dessus au cas où le lien descend:
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
//assert: startDate must be before endDate
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
et
/** Using Calendar - THE CORRECT (& Faster) WAY**/
public static long daysBetween(final Calendar startDate, final Calendar endDate)
{
//assert: startDate must be before endDate
int MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
long endInstant = endDate.getTimeInMillis();
int presumedDays =
(int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY);
Calendar cursor = (Calendar) startDate.clone();
cursor.add(Calendar.DAY_OF_YEAR, presumedDays);
long instant = cursor.getTimeInMillis();
if (instant == endInstant)
return presumedDays;
final int step = instant < endInstant ? 1 : -1;
do {
cursor.add(Calendar.DAY_OF_MONTH, step);
presumedDays += step;
} while (cursor.getTimeInMillis() != endInstant);
return presumedDays;
}
de java.temps
en Java 8 et plus tard, utilisez le java.cadre de temps ( Tutoriel ).
Duration
la classe Duration
représente un intervalle de temps en nombre de secondes plus une fraction de seconde. Il peut compter les jours, les heures, les minutes et les secondes.
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println(duration.toDays());
ChronoUnit
si tout ce que vous avez besoin est le nombre de jours, vous pouvez également utiliser le ChronoUnit
enum . Notez que les méthodes de calcul renvoient un long
au lieu de int
.
long days = ChronoUnit.DAYS.between( then, now );
Cela dépend de ce que vous définissez comme la différence. Pour comparer deux dates à minuit, vous pouvez le faire.
long day1 = ...; // in milliseconds.
long day2 = ...; // in milliseconds.
long days = (day2 - day1) / 86400000;
import java.util.Calendar;
import java.util.Date;
public class Main {
public static long calculateDays(String startDate, String endDate)
{
Date sDate = new Date(startDate);
Date eDate = new Date(endDate);
Calendar cal3 = Calendar.getInstance();
cal3.setTime(sDate);
Calendar cal4 = Calendar.getInstance();
cal4.setTime(eDate);
return daysBetween(cal3, cal4);
}
public static void main(String[] args) {
System.out.println(calculateDays("2012/03/31", "2012/06/17"));
}
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
}
Solution utilisant la différence entre le temps millisecondes, avec arrondissement correct pour les dates D'heure D'été:
public static long daysDiff(Date from, Date to) {
return daysDiff(from.getTime(), to.getTime());
}
public static long daysDiff(long from, long to) {
return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24
}
Une remarque: bien sûr, les dates doivent être dans une certaine fuseau horaire.
le code important:
Math.round( (to - from) / 86400000D )
Si vous ne voulez pas rond, vous pouvez utiliser dates UTC,
Illustration du problème: (mon code calcule delta en semaines, mais la même question s'applique avec delta en jours)
Voici une mise en œuvre très raisonnable:
public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L;
static public int getDeltaInWeeks(Date latterDate, Date earlierDate) {
long deltaInMillis = latterDate.getTime() - earlierDate.getTime();
int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK);
return deltaInWeeks;
}
mais ce test échouera:
public void testGetDeltaInWeeks() {
delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23);
assertEquals("weeks between Feb23 and Mar09", 2, delta);
}
la raison est:
Lun Mar 09 00:00:00 HAE 2009 = 1,236,571,200,000
Lun Feb 23 00:00:00 EST 2009 = 1,235,365,200,000
MillisPerWeek = 604,800,000
Thus,
(Mar09 - Feb23) / MillisPerWeek =
1,206,000,000 / 604,800,000 = 1.994...
mais quiconque regarde un calendrier serait d'accord que la réponse est 2.
j'utilise cette fonction:
DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days
ma fonction:
import java.util.Date;
public long DATEDIFF(String date1, String date2) {
long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000;
long days = 0l;
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss");
Date dateIni = null;
Date dateFin = null;
try {
dateIni = (Date) format.parse(date1);
dateFin = (Date) format.parse(date2);
days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY;
} catch (Exception e) { e.printStackTrace(); }
return days;
}
Regardez de la getFragmentInDays méthodes dans cet apache commons-lang classe DateUtils
.
basé sur la réponse de @Mad_Troll, j'ai développé cette méthode.
j'ai couru environ 30 cas de test contre elle, est la seule méthode qui traite correctement des fragments de temps de sous-journée.
exemple: si vous passez maintenant et maintenant + 1 milliseconde qui est encore le même jour.
Faire 1-1-13 23:59:59.098
à 1-1-13 23:59:59.099
retourne 0 jours, correctement; allot des autres méthodes postées ici ne fera pas cela correctement.
mérite de noter qu'il ne se soucie pas de quelle façon vous les mettez, si votre date de fin est avant votre date de début, il comptera à l'envers.
/**
* This is not quick but if only doing a few days backwards/forwards then it is very accurate.
*
* @param startDate from
* @param endDate to
* @return day count between the two dates, this can be negative if startDate is after endDate
*/
public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) {
//Forwards or backwards?
final boolean forward = startDate.before(endDate);
// Which direction are we going
final int multiplier = forward ? 1 : -1;
// The date we are going to move.
final Calendar date = (Calendar) startDate.clone();
// Result
long daysBetween = 0;
// Start at millis (then bump up until we go back a day)
int fieldAccuracy = 4;
int field;
int dayBefore, dayAfter;
while (forward && date.before(endDate) || !forward && endDate.before(date)) {
// We start moving slowly if no change then we decrease accuracy.
switch (fieldAccuracy) {
case 4:
field = Calendar.MILLISECOND;
break;
case 3:
field = Calendar.SECOND;
break;
case 2:
field = Calendar.MINUTE;
break;
case 1:
field = Calendar.HOUR_OF_DAY;
break;
default:
case 0:
field = Calendar.DAY_OF_MONTH;
break;
}
// Get the day before we move the time, Change, then get the day after.
dayBefore = date.get(Calendar.DAY_OF_MONTH);
date.add(field, multiplier);
dayAfter = date.get(Calendar.DAY_OF_MONTH);
// This shifts lining up the dates, one field at a time.
if (dayBefore == dayAfter && date.get(field) == endDate.get(field))
fieldAccuracy--;
// If day has changed after moving at any accuracy level we bump the day counter.
if (dayBefore != dayAfter) {
daysBetween += multiplier;
}
}
return daysBetween;
}
vous pouvez supprimer les annotations @NotNull
, celles-ci sont utilisées par Intellij pour faire l'analyse de code à la volée
vous dites qu'il" fonctionne bien dans un programme autonome, "mais que vous obtenez" des valeurs de différence inhabituelles "quand vous"inclure dans ma logique de lire à partir du rapport". Cela suggère que votre rapport a certaines valeurs pour lesquelles il ne fonctionne pas correctement, et votre programme autonome n'a pas ces valeurs. Au lieu d'un programme autonome, je suggère un cas d'essai. Écrivez un cas de test comme vous le feriez pour un programme autonome, subclassing de la classe TestCase de JUnit. Maintenant, vous pouvez exécuter une très spécifiques par exemple, savoir quelle valeur vous attendez (et ne pas la donner aujourd'hui pour la valeur de test, parce qu'aujourd'hui change avec le temps). Si vous mettez les valeurs que vous avez utilisées dans le programme autonome, vos tests seront probablement réussis. C'est génial - vous voulez que ces affaires continuent de fonctionner. Maintenant, ajoute une valeur de ton rapport, qui ne fonctionne pas correctement. Votre nouveau test échouera probablement. Découvrez pourquoi il échoue, réparez-le et passez au vert (tous les tests réussis). Exécuter votre rapport. Voir ce qui est encore cassé; écrire un test; le faire passer. Bientôt, vous verrez que votre rapport fonctionne.
cent lignes de code pour cette fonction de base???
Juste une méthode simple:
protected static int calculateDayDifference(Date dateAfter, Date dateBefore){
return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24);
// MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
}
public static int getDifferenceIndays(long timestamp1, long timestamp2) {
final int SECONDS = 60;
final int MINUTES = 60;
final int HOURS = 24;
final int MILLIES = 1000;
long temp;
if (timestamp1 < timestamp2) {
temp = timestamp1;
timestamp1 = timestamp2;
timestamp2 = temp;
}
Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
endDate.setTimeInMillis(timestamp1);
startDate.setTimeInMillis(timestamp2);
if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
int day1 = endDate.get(Calendar.DAY_OF_MONTH);
int day2 = startDate.get(Calendar.DAY_OF_MONTH);
if (day1 == day2) {
return 0;
} else {
return 1;
}
}
int diffDays = 0;
startDate.add(Calendar.DAY_OF_MONTH, diffDays);
while (startDate.before(endDate)) {
startDate.add(Calendar.DAY_OF_MONTH, 1);
diffDays++;
}
return diffDays;
}
ThreeTen-Extra
la réponse de Vitalii Fedorenko est correcte, décrivant comment effectuer ce calcul d'une manière moderne avec java.classes de temps ( Duration
& ChronoUnit
) intégré à Java 8 et plus tard (et rétroporté à Java 6 & 7 et à Android ).
Days
si vous utilisez un certain nombre de jours de manière routinière dans votre code, vous pouvez remplacer de simples entiers par l'utilisation d'une classe. La classe Days
se trouve dans le projet ThreeTen-Extra , une extension de java.temps et terrain d'essai pour d'éventuelles futures additions à java.temps. Le Days
classe fournit un moyen sûr de représenter un nombre de jours de votre demande. La classe comprend pratique constantes pour ZERO
et ONE
.
étant donné les anciens objets java.util.Date
, convertissez-les d'abord en objets modernes java.time.Instant
. Les anciennes classes date-heure ont ajouté de nouvelles méthodes pour faciliter la conversion en java.le temps, un tel java.util.Date::toInstant
.
Instant start = utilDateStart.toInstant(); // Inclusive.
Instant stop = utilDateStop.toInstant(); // Exclusive.
Pass tous les deux Instant
objets à la méthode d'usine pour org.threeten.extra.Days
.
dans l'implémentation actuelle (2016-06) ceci est un wrapper appelant java.time.temporal.ChronoUnit.DAYS.between
, lisez la classe ChronoUnit
doc pour plus de détails. Pour être clair: toute la majuscule DAYS
est dans l'enum ChronoUnit
tandis que le premier-cap Days
est une classe de ThreeTen-Extra.
Days days = Days.between( start , stop );
vous pouvez passer ces Days
les objets autour de votre propre code. Vous pouvez sérialiser à une chaîne de caractères dans le format standard ISO 8601 en appelant toString
. Ce format de PnD
utilise un P
pour marquer le début et D
signifie" jours", avec un nombre de jours entre les deux. Les deux java.les classes de temps et ThreeTen-Extra utilisent ces formats standards par défaut pour générer et analyser des chaînes représentant des valeurs date-heure.
String output = days.toString();
P3D
Days days = Days.parse( "P3D" );
ce code calcule les jours entre 2 chaînes de date:
static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24;
static final String DATE_FORMAT = "dd-MM-yyyy";
public long daysBetween(String fromDateStr, String toDateStr) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
Date fromDate;
Date toDate;
fromDate = format.parse(fromDateStr);
toDate = format.parse(toDateStr);
return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY;
}
si vous cherchez une solution qui retourne le nombre approprié ou les jours entre par exemple 11/30/2014 23:59
et 12/01/2014 00:01
voici la solution en utilisant Joda Time.
private int getDayDifference(long past, long current) {
DateTime currentDate = new DateTime(current);
DateTime pastDate = new DateTime(past);
return currentDate.getDayOfYear() - pastDate.getDayOfYear();
}
cette implémentation renverra 1
en jours différents. La plupart des solutions présentées ici calculent la différence en millisecondes entre deux dates. Cela signifie que 0
serait retourné parce qu'il n'y a que 2 minutes de différence entre ces deux dates.
j'ai déjà écrit à ce sujet. Il S'agit d'un report de calculant la différence entre deux instances de date Java .
public int getDiffernceInDays(long timeAfter, long timeBefore) {
Calendar calendarAfter = Calendar.getInstance();
calendarAfter.setTime(new Date(timeAfter));
Calendar calendarNewAfter = Calendar.getInstance();
calendarNewAfter.set(calendarAfter.get(Calendar.YEAR), calendarAfter.get(Calendar.MONTH), calendarAfter.get(Calendar.DAY_OF_MONTH));
Calendar calendarBefore = Calendar.getInstance();
calendarBefore.setTime(new Date(timeBefore));
Calendar calendarNewBefore = Calendar.getInstance();
calendarNewBefore.set(calendarBefore.get(Calendar.YEAR), calendarBefore.get(Calendar.MONTH), calendarBefore.get(Calendar.DAY_OF_MONTH));
return (int) ((calendarNewAfter.getTime().getTime() - calendarNewBefore.getTime().getTime()) / (24 * 60 * 60 * 1000));
}
vous devez utiliser la bibliothèque Joda Time Car Java Util Date renvoie parfois des valeurs erronées.
Joda vs Java Util Date
par exemple les jours entre hier (JJ-mm-AAAA, 12-07-2016) et le premier jour de l'année en 1957 (JJ-mm-AAAA, 01-01-1957):
public class Main {
public static void main(String[] args) {
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date date = null;
try {
date = format.parse("12-07-2016");
} catch (ParseException e) {
e.printStackTrace();
}
//Try with Joda - prints 21742
System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date));
//Try with Java util - prints 21741
System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date));
}
private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) {
DateTime jodaDateTime = new DateTime(date);
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy");
DateTime y1957 = formatter.parseDateTime("01-01-1957");
return Days.daysBetween(y1957 , jodaDateTime).getDays();
}
private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) {
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date y1957 = null;
try {
y1957 = format.parse("01-01-1957");
} catch (ParseException e) {
e.printStackTrace();
}
return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS);
}
donc je vous conseille vraiment D'utiliser la bibliothèque Joda Time.
Je l'ai fait comme ça. c'est facile :)
Date d1 = jDateChooserFrom.getDate();
Date d2 = jDateChooserTo.getDate();
Calendar day1 = Calendar.getInstance();
day1.setTime(d1);
Calendar day2 = Calendar.getInstance();
day2.setTime(d2);
int from = day1.get(Calendar.DAY_OF_YEAR);
int to = day2.get(Calendar.DAY_OF_YEAR);
int difference = to-from;