Comment puis-je calculer un laps de temps en Java et formater la sortie?
Je veux prendre deux fois (en secondes depuis l'époque) et montrer la différence entre les deux dans des formats comme:
- 2 minutes
- 1 heure, 15 minutes
- 3 heures, 9 minutes
- Il y a 1 minute
- Il y a 1 heure, 2 minutes
Comment puis-je accomplir cela??
17 réponses
puisque tout le monde crie " YOODAA!!!"mais personne ne publie un exemple concret, voici ma contribution.
Vous pouvez également le faire avec Joda-Time . Utilisation Period
pour représenter une période. Pour formater la période souhaitée dans la représentation humaine, l'utilisation PeriodFormatter
lequel vous pouvez construire par PeriodFormatterBuilder
.
Voici un exemple de coup d'envoi:
DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0);
DateTime now = new DateTime();
Period period = new Period(myBirthDate, now);
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendYears().appendSuffix(" year, ", " years, ")
.appendMonths().appendSuffix(" month, ", " months, ")
.appendWeeks().appendSuffix(" week, ", " weeks, ")
.appendDays().appendSuffix(" day, ", " days, ")
.appendHours().appendSuffix(" hour, ", " hours, ")
.appendMinutes().appendSuffix(" minute, ", " minutes, ")
.appendSeconds().appendSuffix(" second", " seconds")
.printZeroNever()
.toFormatter();
String elapsed = formatter.print(period);
System.out.println(elapsed + " ago");
Beaucoup plus clair et concis, n'est-ce pas?
Cela imprime maintenant
32 years, 1 month, 1 week, 5 days, 6 hours, 56 minutes, 24 seconds ago
(de la Toux, de vieux, de la toux)
Date start = new Date(1167627600000L); // JANUARY_1_2007
Date end = new Date(1175400000000L); // APRIL_1_2007
long diffInSeconds = (end.getTime() - start.getTime()) / 1000;
long diff[] = new long[] { 0, 0, 0, 0 };
/* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
/* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
/* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
/* days */diff[0] = (diffInSeconds = (diffInSeconds / 24));
System.out.println(String.format(
"%d day%s, %d hour%s, %d minute%s, %d second%s ago",
diff[0],
diff[0] > 1 ? "s" : "",
diff[1],
diff[1] > 1 ? "s" : "",
diff[2],
diff[2] > 1 ? "s" : "",
diff[3],
diff[3] > 1 ? "s" : ""));
Yup a réveillé les morts que j'ai, Mais voici mon implémentation améliorée basée sur le code posté par @mtim, car ce fil vient presque au-dessus des recherches, donc je joue avec le Sleepy hollow,
public static String getFriendlyTime(Date dateTime) {
StringBuffer sb = new StringBuffer();
Date current = Calendar.getInstance().getTime();
long diffInSeconds = (current.getTime() - dateTime.getTime()) / 1000;
/*long diff[] = new long[]{0, 0, 0, 0};
/* sec * diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
/* min * diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
/* hours * diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
/* days * diff[0] = (diffInSeconds = (diffInSeconds / 24));
*/
long sec = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
long min = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
long hrs = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
long days = (diffInSeconds = (diffInSeconds / 24)) >= 30 ? diffInSeconds % 30 : diffInSeconds;
long months = (diffInSeconds = (diffInSeconds / 30)) >= 12 ? diffInSeconds % 12 : diffInSeconds;
long years = (diffInSeconds = (diffInSeconds / 12));
if (years > 0) {
if (years == 1) {
sb.append("a year");
} else {
sb.append(years + " years");
}
if (years <= 6 && months > 0) {
if (months == 1) {
sb.append(" and a month");
} else {
sb.append(" and " + months + " months");
}
}
} else if (months > 0) {
if (months == 1) {
sb.append("a month");
} else {
sb.append(months + " months");
}
if (months <= 6 && days > 0) {
if (days == 1) {
sb.append(" and a day");
} else {
sb.append(" and " + days + " days");
}
}
} else if (days > 0) {
if (days == 1) {
sb.append("a day");
} else {
sb.append(days + " days");
}
if (days <= 3 && hrs > 0) {
if (hrs == 1) {
sb.append(" and an hour");
} else {
sb.append(" and " + hrs + " hours");
}
}
} else if (hrs > 0) {
if (hrs == 1) {
sb.append("an hour");
} else {
sb.append(hrs + " hours");
}
if (min > 1) {
sb.append(" and " + min + " minutes");
}
} else if (min > 0) {
if (min == 1) {
sb.append("a minute");
} else {
sb.append(min + " minutes");
}
if (sec > 1) {
sb.append(" and " + sec + " seconds");
}
} else {
if (sec <= 1) {
sb.append("about a second");
} else {
sb.append("about " + sec + " seconds");
}
}
sb.append(" ago");
/*String result = new String(String.format(
"%d day%s, %d hour%s, %d minute%s, %d second%s ago",
diff[0],
diff[0] > 1 ? "s" : "",
diff[1],
diff[1] > 1 ? "s" : "",
diff[2],
diff[2] > 1 ? "s" : "",
diff[3],
diff[3] > 1 ? "s" : ""));*/
return sb.toString();
}
, Il peut évidemment être amélioré. fondamentalement, il essaie d'obtenir la période de temps plus amicale, il y a quelques limitations, c'est-à-dire qu'il se comporterait étrangement si le temps passé (paramètre) est à l'avenir, et son limité jusqu'aux jours, heures et secondes seulement (mois et années non traitées, donc que quelqu'un d'autre ;-).
Les exemples de sorties sont:
- Il y a environ une seconde
- il y a 8 minutes et 34 secondes
- Il y a une heure et 4 minutes
- Il y a un jour
- il y a 29 jours
- Il y a un an et 3 mois
, cheers: D
EDIT: supporte maintenant les mois et les années: p
Évitez les classes date-heure héritées
Les autres réponses peuvent être correctes mais sont obsolètes. Les anciennes classes date-heure gênantes en Java sont maintenant héritées, supplantées par java.les classes de temps.
De même, le projetJoda-Time , maintenant en mode de maintenance , conseille la migration vers le java .temps classes.
Utilisation de java.temps
Instant
Deux fois (en secondes depuis l'époque)
En java.le temps, nous représenter les moments sur la timeline en UTC comme Instant
. Je suppose que votre époque est la même que celle de java.temps, le premier moment de 1970 en UTC (1970-01-01T00:00:00Z
). Notez qu'un Instant
a une résolution de nanosecondes. Une méthode d'usine de commodité construit un Instant
à partir de secondes entières, comme demandé dans la Question.
Instant start = Instant.ofEpochSecond( … );
Instant stop = Instant.ofEpochSecond( … );
Ici, nous utilisons le moment actuel et quelques minutes plus tard.
Instant start = Instant.now() ;
Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ; // Seven minutes as a number of seconds.
Duration
En java.temps, une période de temps non attachée à la timeline est représentée en deux façon. Pour les années-mois-jours, nous avons Period
. Pour les heures-minutes-secondes, nous avons Duration
.
Duration duration = Duration.between( start , stop );
Demi-Ouvert
Le temps écoulé est calculé avec L'approche semi-ouverte. Dans cette approche, le début est inclusive, tandis que la fin est exclusive. Cette approche est couramment utilisée dans le travail date-heure. Je crois que l'utilisation de cette approche de manière cohérente dans votre base de code aidera à éliminer les erreurs et les malentendus dus aux ambiguïtés, et facilitera le charge cognitive de votre programmation.
ISO 8601
La norme ISO 8601 définit de nombreux formats pratiques pour représenter les valeurs date-heure sous forme de texte. Ces formats sont conçus pour éviter toute ambiguïté, être faciles à analyser par machine et être intuitifs à lire par les humains à travers les cultures.
Le java.les classes de temps utilisent ces formats par défaut lors de l'analyse et de la génération de chaînes.
Pour un laps de temps non attaché à la timeline, la norme définit un format de PnYnMnDTnHnMnS
où P
marque le début et T
sépare les années-mois-jours de toutes les heures-minutes-secondes. Donc, une heure et demie est PT1H30M
.
Dans notre exemple de code en utilisant sept minutes:
String outputStandard = duration.toString();
PT7M
Voir l'exemple ci-dessus code en cours d'exécution en direct à IdeOne.com .
Je suggère de coller avec ces formats autant que possible, certainement lors de l'échange ou de la sérialisation des données date-heure, mais aussi envisager d'utiliser dans un interface utilisateur le cas échéant et vos utilisateurs peuvent être formés pour les utiliser.
Je recommande jamais en utilisant le format horloge-heure (ex: 01:30 pour une heure et demie) car ce format est complètement ambigu avec une heure de la journée.
Récupération de pièces pour construire une chaîne
Si vous devez préciser la période de temps comme on le voit dans la Question, vous devrez construire le texte vous-même.
- Pour
Period
, appelgetYears
,getMonths
, etgetDays
pour récupérer chaque partie. - Curieusement, la
Duration
classe n'avaient pas ces accesseurs dans Java 8, mais acquise dans Java 9 et plus tard:toDaysPart
,toHoursPart
,toMinutesPart
,toSecondsPart
, ettoNanosPart
.
Un exemple de code, simple et basique pour vous aider à démarrer.
int days = duration.toDaysPart() ;
int hours = duration.toHoursPart() ;
int minutes = duration.toMinutesPart() ;
int seconds = duration.toSecondsPart() ;
int nanos = duration.toNanosPart() ;
StringBuilder sb = new StringBuilder( 100 );
if( days != 0 ) {
sb.append( days + " days" ) ;
};
if( hours != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( hours + " hours" ) ;
};
if( minutes != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( minutes + " minutes" ) ;
};
if( seconds != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( seconds + " seconds" ) ;
};
if( nanos != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( nanos + " nanos" ) ;
};
String output = sb.toString();
Ou peut-être pourriez-vous écrire du code slicker en utilisant DateTimeFormatterBuilder
d'une manière montrée avec Joda-Time dans la réponse de Balus C.
À propos Java.temps
Le java.le framework time est intégré à Java 8 et versions ultérieures. Ces classes permettent d'éviter la pénible vieux héritage date-heure classes telles que java.util.Date
, Calendar
, & SimpleDateFormat
.
Le projetJoda-Time , maintenant en mode de maintenance , conseille la migration vers le java .temps classes.
Pour en savoir plus, consultez le tutoriel Oracle. Et débordement de pile de recherche pour de nombreux exemples et des explications. La spécification est JSR 310 .
Où obtenir le java.les classes de temps?
-
Java SE 8 et SE 9 et plus tard
- intégré.
- fait partie de L'API Java standard avec une implémentation groupée.
- Java 9 ajoute quelques fonctionnalités et corrections mineures.
-
Java SE 6 et SE 7
- une grande partie de java.la fonctionnalité time est de nouveau portée sur Java 6 et 7 dans ThreeTen-Backport.
-
Android
- Le Troisetenabp Projet adapte ThreeTen-Backport (mentionné ci-dessus) pour Android spécifiquement.
- Voir Comment utiliser ThreeTenABP....
Le ThreeTen-Extra Projet étend java.temps avec des classes supplémentaires. Ce projet est un terrain d'essai pour les futurs ajouts possibles à java.temps. Vous pouvez trouver quelques classes utiles ici comme Interval
, YearWeek
, YearQuarter
, andfz plus.
Je ne suis pas un expert en Java, mais vous pouvez faire t1-t2=t3 (en secondes) puis diviser cela par 60, vous donnerait des minutes, par un autre 60 vous donnerait des secondes. Ensuite, il est juste une question de déterminer combien de divisions vous avez besoin.
J'espère que ça aide.
Si vos plages horaires dépassent les limites de l'heure d'été, voulez-vous indiquer le nombre de jours?
Par exemple, 23:00 à 23:00 le lendemain est toujours un jour, mais peut être 23, 24 ou 25 heures selon que vous traversez une transition d'heure d'été.
Si vous vous souciez de cela, assurez-vous de le prendre en compte dans votre choix.
Du code qui joue avec le formatage de date... et il y a le temps.
SimpleDateFormat curFormater = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss");
try {
Date dateObj = curFormater.parse(pubDate);
SimpleDateFormat postFormater = new SimpleDateFormat("MMMM dd, yyyy ss:mm:hh");
String newDateStr = postFormater.format(dateObj);
Log.v("THE NEW DATE IS",newDateStr);
long pubdateinmilis = dateObj.getTime();
pubDate = (String) DateUtils.getRelativeTimeSpanString(pubdateinmilis, System.currentTimeMillis(),DateUtils.HOUR_IN_MILLIS,DateUtils.FORMAT_ABBREV_RELATIVE);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Je commence toujours par Joda Time . Travailler avec des dates et des heures en Java est toujours "amusant", mais le temps Joda prend la souche au large.
Ils ont des classes D'intervalle et de durée qui font la moitié de ce que vous cherchez. Je ne sais pas s'ils ont une fonction pour sortir en format lisible. Je vais continuer à chercher.
HTH
La classe Calendar peut gérer la plupart des mathématiques liées à la date. Vous devrez obtenir le résultat de compareTo et sortir le format vous-même. Il n'y a pas une bibliothèque standard qui fait exactement ce que vous cherchez, bien qu'il puisse y avoir une bibliothèque tierce qui le fait.
OK, après une brève lecture de L'API, il semble que vous pourriez faire ce qui suit: -
- Créez des ReadableInstants représentant l'Heure de début et l'Heure de fin.
- Heures D'Utilisation.hoursBetween pour obtenir le nombre d'heures
- Utilisez Minutes.minutesBetween pour obtenir le nombre de minutes
- Utilisez le mod 60 sur les minutes pour obtenir les minutes restantes
- et voilà!
HTH
La solution de "Abduliam Rehmanius" semble assez agréable, ou vous pouvez utiliser une bibliothèque ci-dessus ou vous pouvez créer de nouvelles choses simples, référez-vous à la solution js ici: http://www.datejs.com/. Il n'est pas difficile de se transformer en Java lang: -)
J'espère que mon lien vous sera utile!
Le formatage des intervalles de temps en java apparaît fréquemment dans les pulls ETL ou DB. L'extrait de code suivant est la façon dont j'obtiens le pouls de l'opération.
SimpleDateFormat ymdhms=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DecimalFormat formatter = new DecimalFormat("#,###"); /* ("#,###.00"); gives you the decimal fractions */
int counter=0;
Date beginTime0=new Date();
while (<some end condition>) {
<some time consuming operation>
/*// uncomment this section durring initial exploration of the time consumer
if(counter>100000){
System.out.println("debug exiting due to counter="+counter);
System.exit(0);
}
*/
if(0==counter%1000){
Date now = new Date();
long diffInSeconds = (now.getTime() - beginTime0.getTime()) / 1000;
long diff[] = new long[] { 0, 0, 0, 0 };
diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); /* sec */
diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* min */
diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* hours */
diff[0] = (diffInSeconds = (diffInSeconds / 24)); /* days */
String delta = String.format(
"%s%s%s%s"
,(diff[0]>0?String.format("%d day%s " ,diff[0],(diff[0]!=1?"s":"")):"")
,(diff[1]>0?String.format("%2d hour%s " ,diff[1],(diff[1]!=1?"s":" ")):"")
,(diff[2]>0?String.format("%2d minute%s ",diff[2],(diff[2]!=1?"s":" ")):"")
, String.format("%2d second%s ",diff[3],(diff[3]!=1?"s":" "))
);
System.out.println(String.format(
"%12s %s delta= %s"
,formatter.format(counter)
,ymdhms.format(new Date())
,delta
)
);
}
counter++;
}
Je pense que vous cherchez quelque chose comme PrettyTime
PrettyTime est une bibliothèque de formatage de temps OpenSource. Entièrement personnalisable, il crée lisible par l'homme, horodatages relatifs comme ceux vus sur Digg, Twitter et Facebook.Son disponible dans plus de 30 langues!
lien:
https://github.com/ocpsoft/prettytime
Peut être utilisé dans android aussi
Par exemple
System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
//prints: "10 minutes from now"
Récemment, j'ai eu la même exigence où j'ai besoin d'une méthode de base pour imprimer la durée. Je n'avais pas la possibilité d'utiliser une bibliothèque tierce. Donc, je viens de peaufiner l'idée de @mtim plus loin.
public static void main(String[] args) throws IOException, ParseException {
String since = "2017-02-24T04:44:05.601Z";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
TimeZone utc = TimeZone.getTimeZone("UTC");
dateFormat.setTimeZone(utc);
Date sinceDate = dateFormat.parse(since);
Date now = new Date();
long durationInSeconds = TimeUnit.MILLISECONDS.toSeconds(now.getTime() - sinceDate.getTime());
long SECONDS_IN_A_MINUTE = 60;
long MINUTES_IN_AN_HOUR = 60;
long HOURS_IN_A_DAY = 24;
long DAYS_IN_A_MONTH = 30;
long MONTHS_IN_A_YEAR = 12;
long sec = (durationInSeconds >= SECONDS_IN_A_MINUTE) ? durationInSeconds % SECONDS_IN_A_MINUTE : durationInSeconds;
long min = (durationInSeconds /= SECONDS_IN_A_MINUTE) >= MINUTES_IN_AN_HOUR ? durationInSeconds%MINUTES_IN_AN_HOUR : durationInSeconds;
long hrs = (durationInSeconds /= MINUTES_IN_AN_HOUR) >= HOURS_IN_A_DAY ? durationInSeconds % HOURS_IN_A_DAY : durationInSeconds;
long days = (durationInSeconds /= HOURS_IN_A_DAY) >= DAYS_IN_A_MONTH ? durationInSeconds % DAYS_IN_A_MONTH : durationInSeconds;
long months = (durationInSeconds /=DAYS_IN_A_MONTH) >= MONTHS_IN_A_YEAR ? durationInSeconds % MONTHS_IN_A_YEAR : durationInSeconds;
long years = (durationInSeconds /= MONTHS_IN_A_YEAR);
String duration = getDuration(sec,min,hrs,days,months,years);
System.out.println(duration);
}
private static String getDuration(long secs, long mins, long hrs, long days, long months, long years) {
StringBuffer sb = new StringBuffer();
String EMPTY_STRING = "";
sb.append(years > 0 ? years + (years > 1 ? " years " : " year "): EMPTY_STRING);
sb.append(months > 0 ? months + (months > 1 ? " months " : " month "): EMPTY_STRING);
sb.append(days > 0 ? days + (days > 1 ? " days " : " day "): EMPTY_STRING);
sb.append(hrs > 0 ? hrs + (hrs > 1 ? " hours " : " hour "): EMPTY_STRING);
sb.append(mins > 0 ? mins + (mins > 1 ? " mins " : " min "): EMPTY_STRING);
sb.append(secs > 0 ? secs + (secs > 1 ? " secs " : " secs "): EMPTY_STRING);
sb.append("ago");
return sb.toString();
}
La sortie sera un intervalle de temps (durée) imprimé en mots, par exemple
1 day 2 hours 51 mins 41 secs ago
Cette question est ancienne et a déjà une réponse, mais j'ai une meilleure solution. Utiliser relativeSpan from date utils
dateHere.setText(DateUtils.getRelativeTimeSpanString(timeInMillis,
System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));
, Il prend comme arguments: longue/int temps, le temps actuel et comment vous le voulez, _month,minute,deuxième, etc
long time1, time2;
time1 = System.currentMillis();
.. drink coffee
time2 = System.currentMillis();
long difference = time2 - time1 // millies between time1 and time2
java.util.Date differneceDate = new Date(difference);
Pour créer une chaîne comme "2 Minutes", vous devez utiliser DateFormatter / DateFormat. Vous pouvez trouver plus de détails à ce sujet dans la spécification de L'API Java (java.sun.com).