web-dev-qa-db-fra.com

Comment calculer un intervalle de temps en Java et formater la sortie?

Je veux prendre deux fois (en secondes depuis Epoch) 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??

40
Jeremy Logan

Depuis que tout le monde crie "YOODAA !!!" mais personne ne poste un exemple concret, voici ma contribution.

Vous pouvez également le faire avec Joda-Time . Utilisez Period pour représenter une période. Pour formater la période dans la représentation humaine souhaitée, utilisez PeriodFormatter que vous pouvez construire avec 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 

 Il y a 32 ans, 1 mois, 1 semaine, 5 jours, 6 heures, 56 minutes, 24 secondes 

(Toux, vieux, toux)

66
BalusC
    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" : ""));
44
Timour

Yup a réveillé les morts que j'ai, mais voici mon implémentation améliorée basée sur le code posté de @mtim, car ce fil vient presque au-dessus des recherches, donc je m'amuse avec le creux assoupi,

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

Cela peut évidemment être amélioré. fondamentalement, il essaie de rendre le laps de temps plus convivial, il y a quelques limitations cependant, c’est-à-dire qu’il se comporterait étrangement si le temps passé (paramètre) était à l’avenir, et limité aux jours, heures et secondes manipulé, pour que quelqu'un d'autre puisse ;-).

les exemples de résultats 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

, acclamations: D

EDIT: supporte maintenant les mois et les années: P

18

Je vous recommande de regarder HumanTime

12
Peter Lindholm

Évitez les anciennes classes date-heure

Les autres réponses peuvent être correctes mais sont obsolètes. Les anciennes classes de date-heure problématiques en Java sont désormais héritées, supplantées par les classes Java.time.

De même, le projet Joda-Time , désormais en mode { maintenance) , conseille de migrer vers les classes Java.time .

Utiliser Java.time

Instant

deux fois (en secondes depuis Epoch) 

En Java.time, nous représentons des moments sur la ligne de temps en UTC sous la forme Instant. Je suppose que votre époque est la même que celle de Java.time, le premier moment de 1970 en UTC (1970-01-01T00:00:00Z). Notez qu'une Instant a une résolution de nanosecondes. Une méthode de fabrique de commodité construit une Instant à partir de secondes entières, comme indiqué 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

Dans Java.time, un intervalle de temps non attaché à la timeline est représenté de deux manières. Pour années-mois-jours, nous avons Period. Pour heures-minutes-secondes, nous avons Duration

Duration duration = Duration.between( start , stop );

À moitié ouvert

Le temps écoulé est calculé avec l'approche Half-Open. Dans cette approche, le début est inclusif tandis que la fin est exclusif. Cette approche est couramment utilisée dans le travail date-heure. Je crois que l’utilisation systématique de cette approche dans l’ensemble de votre code contribuera à éliminer les erreurs et les incompréhensions dues aux ambiguïtés et à alléger la 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 les ambiguïtés, être faciles à analyser par une machine et intuitifs à lire par des humains de différentes cultures.

Les classes Java.time utilisent ces formats par défaut lors de l'analyse et de la génération de chaînes.

Pendant un laps de temps non lié à la chronologie, le norme définit un format de PnYnMnDTnHnMnSP marque le début et T sépare les années-mois-jours des heures-minutes-secondes. Donc, une heure et demie est PT1H30M

Dans notre exemple de code utilisant sept minutes:

String outputStandard = duration.toString();

PT7M

Voir l'exemple ci-dessus code exécuté en direct sur IdeOne.com .

Je suggère de conserver ces formats autant que possible, certainement lors de l'échange ou de la sérialisation des données date-heure, mais envisagez également d'utiliser une interface utilisateur, le cas échéant, afin que vos utilisateurs puissent être formés à leur utilisation. 

Je recommande jamais en utilisant le format d'horloge (ex: 01:30 pour une heure et demie) car ce format est complètement ambigu avec l'heure.

Récupération de pièces pour construire une chaîne

Si vous devez préciser le laps de temps indiqué dans la question, vous devrez créer le texte vous-même. 

  • Pour Period , appelez getYears , getMonths et getDays pour récupérer chaque partie. 
  • Bizarrement, la classe Duration n'avait pas de tels accesseurs dans Java 8 , mais les gagnait dans Java 9 et plus tard: toDaysPart , toHoursPart, toMinutesPart, toSecondsPart et toNanosPart

Quelques exemples de code, simples et basiques 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 plus lisse en utilisant DateTimeFormatterBuilder de la même manière que Joda-Time dans la réponse de Balus C .


À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciennes classes gênantes héritées _ date-heure telles que Java.util.Date , Calendar _, & SimpleDateFormat .

Le projet Joda-Time , désormais en mode maintenance , conseille de migrer vers les classes Java.time .

Pour en savoir plus, consultez le Tutoriel 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 et SE 9 et versions ultérieures
    • Intégré. 
    • Une partie de l'API Java standard avec une implémentation fournie.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 et 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 d’éventuels ajouts à Java.time. Vous pouvez y trouver des classes utiles telles que Interval _, YearWeek , YearQuarter _, andfz plus _.

9
Basil Bourque

Je ne suis pas un expert en Java, mais vous pouvez faire t1-t2 = t3 (en secondes), puis diviser par 60, vous donnerait des minutes, par 60 autres, vous donnerait des secondes. Ensuite, il suffit de déterminer le nombre de divisions nécessaires.

J'espère que ça aide.

1
TuxMeister

Si votre plage horaire dépasse les limites de l'heure d'été, souhaitez-vous indiquer le nombre de jours? 

Par exemple, le lendemain, de 23h00 à 23h00 est toujours un jour, mais il peut durer 23, 24 ou 25 heures, selon que vous traversiez ou non une transition heure avancée. 

Si cela vous tient à cœur, assurez-vous de le prendre en compte dans votre choix.

1
Adrian Pronk

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

Cette question est ancienne et a déjà une réponse mais j'ai une meilleure solution . Utilisez relativeSpan à partir de date utils

                dateHere.setText(DateUtils.getRelativeTimeSpanString(timeInMillis,
                        System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));

il faut des arguments: long/int time, heure actuelle et comment vous le voulez, _month, minute, seconde, etc.

0
Lucem

Je commence toujours par Joda Time . Travailler avec des dates et des heures en Java est toujours "amusant", mais Joda Time vous facilite la tâche. 

Ils ont des classes d'intervalle et de durée qui font la moitié de ce que vous recherchez. Je ne sais pas si elles ont une fonction permettant d’afficher dans un format lisible. Je vais continuer à chercher.

HTH

0
mr_urf

La classe Calendar peut gérer la plupart des calculs liés aux dates. Vous devrez cependant obtenir le résultat de compareTo et sortir le format vous-même. Aucune bibliothèque standard ne fait exactement ce que vous recherchez, bien qu'une bibliothèque tierce puisse le faire.

0
Ben S

Récemment, j'ai eu la même exigence, où il me fallait une méthode de base pour imprimer la durée. Je n'avais pas la possibilité d'utiliser une bibliothèque tierce. Je viens donc de préciser l’idée de @mtim. 

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é avec des mots, par exemple, .1 day 2 hours 51 mins 41 secs ago

0
i_am_zero

OK, après une brève lecture de l'API, il semble que vous puissiez faire ce qui suit: -

  1. créez des ReadableInstants représentant l’heure de début et l’heure de fin.
  2. Utilisez Heures.heuresBetween pour obtenir le nombre d'heures
  3. utilisez Minutes.minutesBetween pour obtenir le nombre de minutes
  4. utilisez le mod 60 sur les minutes pour obtenir les minutes restantes
  5. et voilà!

HTH

0
mr_urf

La solution de "Abduliam Rehmanius" semble assez jolie, vous pouvez en utiliser une autre ou créer de nouvelles choses simples, consultez la solution JS à l'adresse suivante: http://www.datejs.com/ . Il n'est pas difficile de transformer en langage Java :-)

J'espère que mon lien vous sera utile!

0
Tam Vo

Les durées de formatage dans Java me sont fréquentes dans les extractions ETL ou DB. L'extrait de code suivant explique comment obtenir l'impulsion 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++;
    }
0
teserecter

Je pense que vous cherchez quelque chose comme PrettyTime
PrettyTime est une bibliothèque de formatage d’heure OpenSource. Entièrement personnalisable, il crée lisible par l'homme _, _ {horodatage relatif comme ceux que l'on voit sur Digg, Twitter et Facebook.
link: 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"
0
Habel Philip