web-dev-qa-db-fra.com

Calculer le temps écoulé en Java/Groovy

J'ai...


Date start = new Date()

...
...
...

Date stop = new Date()

J'aimerais avoir les années, les mois, les jours, les heures, les minutes et les secondes écoulés entre ces deux dates.

-

Je vais préciser la question.

Je veux juste obtenir le temps écoulé, en tant que mesure absolue, sans tenir compte des années bissextiles, des jours de chaque mois, etc.

Ainsi, je pense qu'il est impossible de connaître les années et les mois écoulés. Tout ce que je peux obtenir, ce sont des jours, des heures, des minutes et des secondes.

Plus précisément, je veux dire qu’une tâche a duré, par exemple. 

20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec

Alors s'il vous plaît pardonnez mon manque de précision.

38
opensas

Je viens de découvrir cette solution rapide basée sur Groovy:

import groovy.time.TimeCategory 
import groovy.time.TimeDuration

TimeDuration td = TimeCategory.minus( stop, start )
println td
90
pd.

Vous pouvez faire tout cela avec division et mod.

long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;

long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;

long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;

Cela devrait vous donner toutes les informations que vous avez demandées.

EDIT: Puisque les gens semblent confus, non, cela ne prend pas en compte des choses telles que les années bissextiles ou les changements d’heure. C’est purement passé time , c’est ce que demande openas.

25
Sebastian Celis

Pas si facile avec l'API Date standard.

Vous voudrez peut-être regarder Joda Time , ou JSR-310 à la place.

Je ne suis pas un expert en Joda, mais je pense que le code serait:

Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());
19
toolkit

En ce qui concerne JodaTime, je viens de commencer; merci au répondant qui l’a suggéré. Voici une version plus condensée du code Joda suggérée:

Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

(Je ne sais pas si cela aide la question initiale mais certainement les chercheurs).

10
Fletch

tl; dr

Duration.between( then , Instant.now() )

Utiliser Java.time

La méthode moderne utilise les classes Java.time qui supplantent les anciennes classes gênantes de date et d’heure.

Au lieu de Date, utilisez Instant. La classe Instant représente un moment sur la ligne temporelle en UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale). 

Instant then = Instant.now();
…
Instant now = Instant.now();

Utilisez la classe Duration pendant un laps de temps non lié à la chronologie, avec une résolution jour-heures-minutes-secondes-nanos. 

Duration d = Duration.between( then , now );

Pendant un laps de temps avec une résolution années-mois-jours, utilisez la classe Period .

La génération d'une chaîne est conforme à la norme ISO 8601 format pour les durées : PnYnMnDTnHnMnS. La P marque le début. La T sépare les années, les mois, les jours et les heures, les minutes, les secondes. Donc, deux heures et demie, c'est PT2H30M

String output = d.toString();

Dans Java 9 et versions ultérieures, vous pouvez accéder aux différentes pièces à l'aide des méthodes toDaysPart, toHoursPart, etc.


À 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 _ et plus _.

6
Basil Bourque

Depuis Java 1.5, vous devriez utiliser TimeUnit.

Voici un exemple simple et clair pour cela. Je pense qu'en groovy, il pourrait être plus court (comme toujours). 

/**
 * Formats a given {@link Date} to display a since-then timespan.
 * @param created
 * @return String with a format like "3 minutes ago"
 */
public static String getElapsedTime(Date created) {
    long duration = System.currentTimeMillis() - created.getTime();
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    long days = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    if (days > 0) {
        return days + " days";
    }
    if (hours > 0) {
        return hours + " hrs";
    }
    if (minutes > 0) {
        return minutes + " minutes";
    }

    return seconds + " seconds";
}

Oh et éviter les retours multiples s'il vous plaît;)

6
dhesse

En fait, en ce qui concerne les réponses ci-dessus à propos de Joda-Time .

Il existe un moyen plus simple de procéder avec Joda-Time’s Period class:

Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period));

Pour personnaliser la sortie, consultez les classes PeriodFormat , PeriodFormatter et PeriodFormatterBuilder .

6
simao

Mis à part l'excellent JodaTime API mentionné ci-dessus que je fais recommande, la meilleure alternative Java standard que vous pouvez avoir est le Java.util.Calendar . Il est fastidieux de travailler avec cela (c'est un euphémisme .. regardez les exemples JodaTime sur une seule ligne ici), mais vous pouvez aussi calculer le temps écoulé. La clé importante est que vous devez utiliser Calendar#add() dans une boucle pour obtenir la valeur écoulée pour les années, les mois et les jours et prendre en compte les jours bissextiles, les années et les siècles. Vous ne devriez pas les calculer à partir des (millièmes) secondes.

Voici un exemple de base:

import Java.util.Calendar;

public class Test {

    public static void main(String[] args) throws Exception {
        Calendar start = Calendar.getInstance();
        start.set(1978, 2, 26, 12, 35, 0); // Just an example.
        Calendar end = Calendar.getInstance();

        Integer[] elapsed = new Integer[6];
        Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
        elapsed[0] = elapsed(clone, end, Calendar.YEAR);
        clone.add(Calendar.YEAR, elapsed[0]);
        elapsed[1] = elapsed(clone, end, Calendar.MONTH);
        clone.add(Calendar.MONTH, elapsed[1]);
        elapsed[2] = elapsed(clone, end, Calendar.DATE);
        clone.add(Calendar.DATE, elapsed[2]);
        elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
        clone.add(Calendar.HOUR, elapsed[3]);
        elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
        clone.add(Calendar.MINUTE, elapsed[4]);
        elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;

        System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
    }

    private static int elapsed(Calendar before, Calendar after, int field) {
        Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
        int elapsed = -1;
        while (!clone.after(after)) {
            clone.add(field, 1);
            elapsed++;
        }
        return elapsed;
    }

}

Il devrait imprimer mon âge dès maintenant =)

Oh, je devrais ajouter, vous pouvez "convertir" Date en Calendar en utilisant Calendar#setTime().

3
BalusC

Hmm, si je comprends ce que vous demandez, vous voulez savoir que si:

début = le 1 janvier 2001 à 10h00 et 00h00

arrêt = le 6 janvier 2003 à 12 h 01 min.

vous voulez une réponse de 2 ans, 0 mois, 5 jours, 2 heures, 1 minute

Malheureusement, cette réponse est spécieuse. Et si les dates étaient le 2 janvier et le 31 janvier? Serait-ce 29 jours? Ok, mais du 2 février au 2 mars est de 28 (29) jours, mais serait indiqué comme 1 mois?

La durée, autre que quelques secondes ou éventuellement plusieurs jours, est variable sans connaître le contexte puisque les mois et les années ont des durées différentes. La différence entre 2 dates doit être exprimée en unités statiques, facilement calculables à partir de stop.getTime () - start.getTime () (qui correspond à la différence en millisecs).

3
billjamesdev

C'est facile; Vous devez définir le bon fuseau horaire

import Java.util.TimeZone;
import Java.util.logging.Logger;

import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class ImportData {

    private final static Logger log = Logger.getLogger(ImportData.class.getName());
    private final static DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final static DateTimeFormatter dtfh = DateTimeFormat.forPattern("HH:mm:ss.SSS");

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
       TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
       DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
       // Quotes connection=Quotes.getInstance();
       final long start  = System.currentTimeMillis();
       // do something here ...
       // connection.importTickdata();
       Thread.currentThread().sleep(2000);
       final long end  = System.currentTimeMillis();
       log.info("[start]    " + dtf.print(start));
       log.info("[end]      " + dtf.print(end));
       TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
       DateTimeZone.setDefault(DateTimeZone.forID("UTC"));
       log.info("[duration] " + dtfh.print(end - start));
       // connection.logOff();
       // System.exit(0);
    }

résultats:

 10.11.2010 00:08:12 ImportData main
INFO: [début] 2010-11-10 00: 08: 10.306 
 10.11.2010 00:08:12 ImportData main
INFO: [ fin] 2010-11-10 00: 08: 12.318 
 10.11.2010 00:08:12 ImportData main
INFO: [durée] 00: 00: 02.012 
1
udoline

C’est une autre fonction similaire, elle n’affichera pas les jours, heures, minutes, etc. si elle n’est pas nécessaire, changez ses littéraux si nécessaire.

public class ElapsedTime {

    public static void main(String args[]) {

        long start = System.currentTimeMillis();
        start -= (24 * 60 * 60 * 1000 * 2);
        start -= (60 * 60 * 1000 * 2);
        start -= (60 * 1000 * 3);
        start -= (1000 * 55);
        start -= 666;
        long end = System.currentTimeMillis();
        System.out.println(elapsedTime(start, end));

    }

    public static String elapsedTime(long start, long end) {

        String auxRet = "";

        long aux = end - start;
        long days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
        // days
        if (aux > 24 * 60 * 60 * 1000) {
            days = aux / (24 * 60 * 60 * 1000);
        }
        aux = aux % (24 * 60 * 60 * 1000);
        // hours
        if (aux > 60 * 60 * 1000) {
            hours = aux / (60 * 60 * 1000);
        }
        aux = aux % (60 * 60 * 1000);
        // minutes
        if (aux > 60 * 1000) {
            minutes = aux / (60 * 1000);
        }
        aux = aux % (60 * 1000);
        // seconds
        if (aux > 1000) {
            seconds = aux / (1000);
        }
        milliseconds = aux % 1000;

        if (days > 0) {
            auxRet = days + " days ";
        }
        if (days != 0 || hours > 0) {
            auxRet += hours + " hours ";
        }
        if (days != 0 || hours != 0 || minutes > 0) {
            auxRet += minutes + " minutes ";
        }
        if (days != 0 || hours != 0 || minutes != 0 || seconds > 0) {
            auxRet += seconds + " seconds ";
        }
        auxRet += milliseconds + " milliseconds ";

        return auxRet;
    }

}
0
jcgonzalez

C’est une fonction complète que j’ai implémentée à partir de Sebastian Celis answer. Et encore une fois, de son poste - cela ne prend pas en compte des choses telles que les années bissextiles ou les commutations d’heures d’été. C'est pur le temps écoulé.

La sortie est adaptée à mes besoins. Cela ne produit que trois sections significatives. Au lieu de revenir

4 mois, 2 semaines, 3 jours, 7 heures, 28 minutes, 43 secondes

Il retourne juste les 3 premiers blocs (voir plus d’échantillons à la fin du post):

4 mois, 2 semaines, 3 jours

Voici le code source complet de la méthode:

/**
 * Format milliseconds to elapsed time format
 * 
 * @param time difference in milliseconds
 * @return Human readable string representation - eg. 2 days, 14 hours, 5 minutes
 */
public static String formatTimeElapsedSinceMillisecond(long milisDiff) {
    if(milisDiff<1000){ return "0 second";}

    String formattedTime = "";
    long secondInMillis = 1000;
    long minuteInMillis = secondInMillis * 60;
    long hourInMillis = minuteInMillis * 60;
    long dayInMillis = hourInMillis * 24;
    long weekInMillis = dayInMillis * 7;
    long monthInMillis = dayInMillis * 30;

    int timeElapsed[] = new int[6];
    // Define time units - plural cases are handled inside loop
    String timeElapsedText[] = {"second", "minute", "hour", "day", "week", "month"};
    timeElapsed[5] = (int) (milisDiff / monthInMillis); // months
    milisDiff = milisDiff % monthInMillis;
    timeElapsed[4] = (int) (milisDiff / weekInMillis); // weeks
    milisDiff = milisDiff % weekInMillis;
    timeElapsed[3] = (int) (milisDiff / dayInMillis); // days
    milisDiff = milisDiff % dayInMillis;
    timeElapsed[2] = (int) (milisDiff / hourInMillis); // hours
    milisDiff = milisDiff % hourInMillis;
    timeElapsed[1] = (int) (milisDiff / minuteInMillis); // minutes
    milisDiff = milisDiff % minuteInMillis;
    timeElapsed[0] = (int) (milisDiff / secondInMillis); // seconds

    // Only adds 3 significant high valued units
    for(int i=(timeElapsed.length-1), j=0; i>=0 && j<3; i--){
        // loop from high to low time unit
        if(timeElapsed[i] > 0){
            formattedTime += ((j>0)? ", " :"") 
                + timeElapsed[i] 
                + " " + timeElapsedText[i] 
                + ( (timeElapsed[i]>1)? "s" : "" );
            ++j;
        }
    } // end for - build string

    return formattedTime;
} // end of formatTimeElapsedSinceMillisecond utility method

Voici un exemple de déclaration de test:

System.out.println(formatTimeElapsedSinceMillisecond(21432424234L));
// Output: 8 months, 1 week, 1 day

System.out.println(formatTimeElapsedSinceMillisecond(87724294L));
// Output: 1 day, 22 minutes, 4 seconds

System.out.println(formatTimeElapsedSinceMillisecond(123434L));
// Output: 2 minutes, 3 seconds
0
Hossain Khan

Il ne sert à rien de créer un objet Date car il ne fait qu'emballer System.currentTimeMillis (). La fonction getTime () ouvre simplement l'objet Date. Je vous suggère simplement d'utiliser cette fonction pour obtenir un long. 

Si vous avez seulement besoin d'une seconde précision, c'est très bien. Cependant, si vous voulez une précision inférieure à une milliseconde, utilisez System.nanoTime () pour obtenir le temps écoulé.

0
Peter Lawrey