wake-up-neo.com

Wie kann ich eine Zeitspanne in Java berechnen und die Ausgabe formatieren?

Ich möchte zwei Mal (in Sekunden seit Epoche) nehmen und den Unterschied zwischen den beiden in Formaten wie zeigen:

  • 2 Minuten 
  • 1 Stunde 15 Minuten 
  • 3 Stunden, 9 Minuten 
  • Vor 1 Minute 
  • Vor 1 Stunde, 2 Minuten

Wie kann ich das erreichen?

40
Jeremy Logan

Da ruft jeder "YOODAA !!!" aber niemand schreibt ein konkretes Beispiel, hier ist mein Beitrag.

Sie können dies auch mit Joda-Time tun. Verwenden Sie Period , um einen Zeitraum darzustellen. Um die Periode in der gewünschten menschlichen Darstellung zu formatieren, verwenden Sie PeriodFormatter das Sie mit PeriodFormatterBuilder erstellen können.

Hier ist ein Kickoff-Beispiel:

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");

Viel klarer und prägnanter, nicht wahr? 

Das ist jetzt gedruckt 

 32 Jahre, 1 Monat, 1 Woche, 5 Tage, 6 Stunden, 56 Minuten, 24 Sekunden zuvor 

(Husten, alt, Husten)

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 hat die Toten geweckt, die ich habe, aber hier ist meine verbesserte Implementierung basierend auf @mtim veröffentlichtem Code, da dieser Thread fast über den Suchvorgängen steht, also bin ich mit der verschlafenen Mulde verwirrt.

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

Es kann offensichtlich verbessert werden. Im Grunde versucht es, die Zeitspanne freundlicher zu gestalten, es gibt jedoch einige Einschränkungen, dh es würde sich merkwürdig verhalten, wenn die Zeit (Parameter) in der Zukunft vergangen ist, und es ist auf die Tage, Stunden und Sekunden beschränkt (Monate und Jahre nicht) gehandhabt, damit jemand anders kann ;-).

beispielausgaben sind:

  • vor etwa einer Sekunde 
  • Vor 8 Minuten und 34 Sekunden
  • vor einer Stunde und 4 Minuten
  • vor einem Tag
  • Vor 29 Tagen
  • vor einem Jahr und 3 Monaten

Prost: D

EDIT: unterstützt jetzt Monate und Jahre: P

18

Ich würde empfehlen, dass Sie einen Blick auf HumanTime werfen.

12
Peter Lindholm

Vermeiden Sie ältere Datums- und Zeitklassen

Die anderen Antworten sind möglicherweise korrekt, aber veraltet. Die lästigen alten Datum-Uhrzeit-Klassen in Java) sind jetzt Legacy, ersetzt durch die Java.time-Klassen.

Ebenso empfiehlt das Joda-Time -Projekt, das sich jetzt im Wartungsmodus befindet, die Migration zu den Java.time -Klassen.

Java.time verwenden

Instant

zweimal (in Sekunden seit Epoche)

In Java.time repräsentieren wir Momente auf der Timeline in UTC als Instant. Ich gehe davon aus, dass Ihre Epoche dieselbe ist wie die von Java.time, dem ersten Moment von 1970 in UTC (1970-01-01T00:00:00Z). Beachten Sie, dass ein Instant eine Auflösung von Nanosekunden hat. Eine Convenience-Factory-Methode erstellt aus ganzen Sekunden ein Instant, wie in der Frage angegeben.

Instant start = Instant.ofEpochSecond( … );
Instant stop = Instant.ofEpochSecond( … );

Hier nutzen wir den aktuellen Moment und einige Minuten später.

Instant start = Instant.now() ;
Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ;  // Seven minutes as a number of seconds.

Duration

In Java.time wird eine Zeitspanne, die nicht mit der Zeitachse verbunden ist, auf zwei Arten dargestellt. Für Jahre-Monate-Tage haben wir Period. Für Stunden, Minuten und Sekunden haben wir Duration.

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

Halb offen

Die verstrichene Zeit wird mit dem Half-Open-Ansatz berechnet. Bei diesem Ansatz ist der Anfang inklusive, während das Ende exklusiv ist. Dieser Ansatz wird häufig in der Datums- und Uhrzeitarbeit verwendet. Ich glaube, dass die konsequente Anwendung dieses Ansatzes in Ihrer gesamten Codebasis dazu beitragen wird, Fehler und Missverständnisse aufgrund von Mehrdeutigkeiten zu beseitigen und die kognitive Belastung Ihrer Programmierung zu verringern.

ISO 8601

Die Norm ISO 8601 definiert viele praktische Formate für die Darstellung von Datums- und Uhrzeitwerten als Text. Diese Formate wurden entwickelt, um Mehrdeutigkeiten zu vermeiden, maschinell leicht zu analysieren und von Menschen in verschiedenen Kulturen intuitiv zu lesen.

Die Java.time-Klassen verwenden diese Formate standardmäßig beim Parsen und Generieren von Zeichenfolgen.

Für eine Zeitspanne, die nicht an die Timeline gebunden ist, definiert der Standard ein Format von PnYnMnDTnHnMnS, wobei P den Anfang markiert und T alle Jahre voneinander trennt. monate-tage von stunden-minuten-sekunden. Also eineinhalb Stunden ist PT1H30M.

In unserem Beispielcode mit sieben Minuten:

String outputStandard = duration.toString();

PT7M

Siehe obiges Beispiel Code läuft live auf IdeOne.com .

Ich empfehle, wann immer möglich an diesen Formaten festzuhalten, insbesondere beim Austausch oder der Serialisierung von Datums- und Uhrzeitdaten. Sie sollten jedoch gegebenenfalls auch die Verwendung in einer Benutzeroberfläche in Betracht ziehen, damit Ihre Benutzer geschult werden können, diese zu verwenden.

Ich empfehle nie das Stundenformat zu verwenden (zB 01:30 für eineinhalb Stunden), da dieses Format mit der Uhrzeit völlig unklar ist.

Teile abrufen, um einen String zu erstellen

Wenn Sie die in der Frage angegebene Zeitspanne angeben müssen, müssen Sie den Text selbst erstellen.

  • Für Period rufen Sie getYears , getMonths und getDays auf, um jeden Teil abzurufen.
  • Seltsamerweise fehlten der Klasse Duration solche Getter in Java 8 , aber sie wurden in Java 9 und später gewonnen: toDaysPart , toHoursPart, toMinutesPart, toSecondsPart und toNanosPart.

Ein Beispielcode, einfach und grundlegend, um Ihnen den Einstieg zu erleichtern.

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

Oder vielleicht könnten Sie mit DateTimeFormatterBuilder einen glatteren Code schreiben, wie mit Joda-Time in die Antwort von Balus C gezeigt.


Über Java.time

Das Java.time Framework ist in Java 8 und höher. Diese Klassen ersetzen die lästigen alten Legacy Datum-Uhrzeit-Klassen wie - Java.util.Date , Calendar , & SimpleDateFormat .

Das Joda-Time -Projekt, das sich jetzt im Wartungsmodus befindet, rät zur Migration in die Java.time -Klassen.

Weitere Informationen finden Sie im Oracle Tutorial . Durchsuchen Sie Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 31 .

Woher bekommen Sie die Java.time-Klassen?

Das ThreeTen-Extra Projekt erweitert Java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von Java.time. Hier finden Sie möglicherweise einige nützliche Klassen wie Interval , YearWeek , YearQuarter , andfz more .

9
Basil Bourque

Ich bin kein Experte für Java, aber Sie können t1-t2 = t3 (in Sekunden) tun, dann teilen Sie das durch 60, würde Ihnen Minuten geben, durch weitere 60 würden Sie Sekunden geben. Dann müssen Sie nur wissen, wie viele Abteilungen Sie benötigen.

Ich hoffe es hilft.

1
TuxMeister

Wenn Ihre Zeitspanne über die Sommerzeit hinausgeht, möchten Sie die Anzahl der Tage angeben? 

Beispielsweise ist der nächste Tag von 23:00 Uhr bis 23:00 Uhr immer ein Tag, kann jedoch 23, 24 oder 25 Stunden betragen, je nachdem, ob Sie einen Sommerzeit-Wechsel durchlaufen. 

Wenn Sie sich darum kümmern, stellen Sie sicher, dass Sie es in Ihre Wahl einbeziehen.

1
Adrian Pronk

etwas Code, der mit Datumsformatierung und vor einiger Zeit spielt.

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

Diese Frage ist alt und hat bereits eine Antwort, aber ich habe eine bessere Lösung. Verwenden Sie relativeSpan von Date utils

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

es braucht Argumente: lange/int Zeit, aktuelle Zeit und wie Sie es wollen, _Monat, Minute, Sekunde etc

0
Lucem

Ich beginne immer mit Joda Time . Das Arbeiten mit Datums- und Uhrzeitangaben in Java ist immer "Spaß", aber Joda Time entlastet. 

Sie haben Intervall- und Dauerunterricht, die die Hälfte von dem erfüllen, wonach Sie suchen. Nicht sicher, ob sie über eine Funktion zur Ausgabe in lesbarem Format verfügen. Ich werde weiter suchen.

HTH

0
mr_urf

Die Calendar Klasse kann die meisten mathematischen Daten verarbeiten. Sie müssen das Ergebnis von compareTo erhalten und das Format selbst ausgeben. Es gibt keine Standardbibliothek, die genau das tut, wonach Sie suchen, obwohl es auch eine Bibliothek von Drittanbietern gibt.

0
Ben S

Vor kurzem habe ich die gleiche Anforderung, bei der ich eine grundlegende Methode für die Druckdauer benötige. Ich hatte keine Möglichkeit, eine Bibliothek von Drittanbietern zu verwenden. Also habe ich die Idee von @mtim weiter verfeinert. 

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

Die Ausgabe wird eine Zeitlücke (Dauer) sein, die in Worten gedruckt wird, z. B. .1 day 2 hours 51 mins 41 secs ago.

0
i_am_zero

OK, nach einer kurzen Überprüfung der API scheint es, dass Sie Folgendes tun könnten: -

  1. erstellen Sie einige ReadableInstants, die die Start- und Endzeit darstellen.
  2. Verwenden Sie Hours.hoursBetween, um die Anzahl der Stunden zu ermitteln
  3. verwenden Sie Minutes.minutesBetween, um die Anzahl der Minuten zu ermitteln
  4. verwenden Sie Mod 60 für die Minuten, um die verbleibenden Minuten zu erhalten
  5. und voila!

HTH

0
mr_urf

Die Lösung von "Abduliam Rehmanius" scheint ziemlich nett zu sein, oder Sie können einige obige Bibliothek verwenden oder Sie können neue einfache Dinge erstellen. Die JS-Lösung finden Sie hier: http://www.datejs.com/ . Es ist nicht schwer in Java umzuwandeln :-)

Hoffe, dass mein Link für Sie nützlich ist!

0
Tam Vo

Die Formatierungszeit in Java wird für mich häufig in ETL- oder DB-Pulls angezeigt. Der folgende Code-Ausschnitt zeigt, wie ich den Impuls der Operation bekomme.

    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

Ich denke, Sie suchen nach etwas wie PrettyTime
PrettyTime ist eine OpenSource-Zeitformatierungsbibliothek. Vollständig anpassbar, erstellt es für Menschen lesbar, relative Zeitstempel wie auf Digg, Twitter und Facebook.
link: https://github.com/ocpsoft/prettytime

Kann auch in Android verwendet werden 

Zum Beispiel

System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
        //prints: "10 minutes from now"
0
Habel Philip