Java'da bir süre nasıl biçimlendirilir? (örneğin, biçim H: AA: SS)


165

H: MM: SS gibi bir desen kullanarak saniyede bir süreyi biçimlendirmek istiyorum. Java'daki mevcut yardımcı programlar bir zamanı biçimlendirmek için tasarlanmıştır, ancak süreyi değil.

Yanıtlar:


84

8'den önce bir Java sürümü kullanıyorsanız ... Joda Time ve PeriodFormatter. Gerçekten bir süreniz varsa (yani, bir takvim sistemine referans olmadan geçen bir süre), muhtemelen Durationçoğunlukla kullanmalısınız - daha sonra arayabilirsiniz toPeriod( PeriodType25 saatin gerçekleşip gerçekleşmeyeceğini yansıtmak istediğiniz her şeyi belirterek) 1 gün 1 saat ya da değil, vb.)Period Biçimlendirebileceğiniz bir.

Java 8 veya daha yenisini kullanıyorsanız: Normalde java.time.Durationsüreyi göstermek için kullanılmasını öneririm . Daha sonra getSeconds()gerekiyorsa, bobince'nin cevabına göre standart dize biçimlendirmesi için bir tam sayı elde etmek için arayabilir veya benzer bir şey yapabilirsiniz - yine de, çıkış dizesinde tek bir negatif işaret istediğinizden, sürenin negatif olduğu duruma dikkat etmelisiniz. . Yani şöyle bir şey:

public static String formatDuration(Duration duration) {
    long seconds = duration.getSeconds();
    long absSeconds = Math.abs(seconds);
    String positive = String.format(
        "%d:%02d:%02d",
        absSeconds / 3600,
        (absSeconds % 3600) / 60,
        absSeconds % 60);
    return seconds < 0 ? "-" + positive : positive;
}

Bu şekilde biçimlendirme , rahatsız edici bir şekilde manuel ise oldukça basittir. İçin ayrıştırma elbette, isterseniz o daha sert madde genel olarak olur ... Hala bile Java 8 ile Joda Zaman kullanabilirsiniz.


Java 8'i kullanırken yine de Joda Time kitaplığını kullanmanızı tavsiye eder misiniz?
Tim Büthe

1
@ TimBüthe: Hayır, bu durumda java.time kullanmaya başladım. (PeriodFormatter'ı hemen eşdeğer bulamasam da ...)
Jon Skeet

1
PeriodFormatter dahil değildir. Java 8 Date Time API ve Joda Time arasındaki farklardan biri.
Tim Büthe

1
@RexKerr: Tabii eğer isterseniz, hala "Joda Time'ı kullanın". Tekrar düzenleyecek. (Geriye dönüp baktığımda, süresi yine de, sesleriyle tavsiye etmeliydim. Önemli düzenleme gerekli ...)
Jon Skeet

4
Daha kolay @MarkJeronimus kullanmak olacaktır Durationler yöntemleri: duration.toHours(), duration.toMinutesPart()ve duration.toSecondsPart()Java 9. beri hangi Ve mutlak değer birini kullanabilirsiniz almak için duration.abs().
recke96

195

Kitaplıklarda sürüklemek istemiyorsanız, bir Biçimlendirici veya ilgili bir kısayol kullanarak kendinizi kolayca yapabilirsiniz. saniye cinsinden tamsayı s:

  String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));

4
Tam sayı olması gerekmez. İki tarihiniz varsa, date1.getTime () - date2.getTime () öğesini uzun ilkel ve hala çalışan yukarıdaki denkleme takın.
Josh

Zaman farkı 24 saatten uzunsa ne olur?
Rajish

2
@Rajish: OP'ye bu durumda ne istediklerini sormanız gerekir! Tabii ki s/86400, (s%86400)/3600...gerekirse günlerce ayırabilirsiniz ...
bobince

s > 86400 (bir gün) için çözümüm : "\u221E"- sonsuzluk
QED

Zaman farkı 24 saatin üzerindeyse, süreyi saat, dakika ve saniye olarak güzel bir şekilde biçimlendirir. Benim kullanım durumum için bu beklendiği gibi.
Audrius Meskauskas

123

Apache common's DurationFormatUtils şöyle kullanıyorum :

DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);

13
Mümkün olan en kolay yol (apache ortak stilinde). Hatta çoğu zaman kullanacağınız formatDurationHMS yönteminiz bile vardır.
Marko

Mükemmel! Kesme işareti içine başka metin de ekleyebilirsiniz: DurationFormatUtils.formatDuration (durationInMillis, "m 'dakika', s 'saniye'")
mihca

29

Java 9'dan beri bu daha kolaydır. A Durationhala biçimlendirilemez, ancak saati, dakikayı ve saniyeleri elde etmek için yöntemler eklenir, bu da görevi biraz daha basit hale getirir:

    LocalDateTime start = LocalDateTime.of(2019, Month.JANUARY, 17, 15, 24, 12);
    LocalDateTime end = LocalDateTime.of(2019, Month.JANUARY, 18, 15, 43, 33);
    Duration diff = Duration.between(start, end);
    String hms = String.format("%d:%02d:%02d", 
                                diff.toHours(), 
                                diff.toMinutesPart(), 
                                diff.toSecondsPart());
    System.out.println(hms);

Bu snippet'in çıktısı:

24:19:21


26
long duration = 4 * 60 * 60 * 1000;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
log.info("Duration: " + sdf.format(new Date(duration - TimeZone.getDefault().getRawOffset())));

14
Hah! Bu yöntemi kullandığınızda zaman dilimi normalizasyonu ile duvara çarpmanız yeterlidir. İşlevi sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));kullanmadan önce eklemeniz gerekir format.
Rajish

7

Bu biraz kibirli olabilir, ancak Java 8'leri kullanarak bunu başarmak için bükülmüşse iyi bir çözümdür java.time:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;

public class TemporalDuration implements TemporalAccessor {
    private static final Temporal BASE_TEMPORAL = LocalDateTime.of(0, 1, 1, 0, 0);

    private final Duration duration;
    private final Temporal temporal;

    public TemporalDuration(Duration duration) {
        this.duration = duration;
        this.temporal = duration.addTo(BASE_TEMPORAL);
    }

    @Override
    public boolean isSupported(TemporalField field) {
        if(!temporal.isSupported(field)) return false;
        long value = temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
        return value!=0L;
    }

    @Override
    public long getLong(TemporalField field) {
        if(!isSupported(field)) throw new UnsupportedTemporalTypeException(new StringBuilder().append(field.toString()).toString());
        return temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
    }

    public Duration getDuration() {
        return duration;
    }

    @Override
    public String toString() {
        return dtf.format(this);
    }

    private static final DateTimeFormatter dtf = new DateTimeFormatterBuilder()
            .optionalStart()//second
            .optionalStart()//minute
            .optionalStart()//hour
            .optionalStart()//day
            .optionalStart()//month
            .optionalStart()//year
            .appendValue(ChronoField.YEAR).appendLiteral(" Years ").optionalEnd()
            .appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral(" Months ").optionalEnd()
            .appendValue(ChronoField.DAY_OF_MONTH).appendLiteral(" Days ").optionalEnd()
            .appendValue(ChronoField.HOUR_OF_DAY).appendLiteral(" Hours ").optionalEnd()
            .appendValue(ChronoField.MINUTE_OF_HOUR).appendLiteral(" Minutes ").optionalEnd()
            .appendValue(ChronoField.SECOND_OF_MINUTE).appendLiteral(" Seconds").optionalEnd()
            .toFormatter();

}

Sadece bu çalıştı ve ben "ss: dd: ss" biçimini denilen eğer fark ne zaman yoktu herhangi bir saati ya da biçimine (örn dakika var Duration.ofSeconds(20)), sonra bir alırdım UnsupportedTemporalTypeException). Ben sadece fark olup olmadığını kontrol kod kaldırdım == 01. 01Tam olarak anlamadığım bir çeşit maskeleme değeri olduğunu düşündüm , açıklayabilir misiniz?
Groostav

Bu aslında çok iyi çalıştı. Benim durumumda milisaniye bile ekledim ... isSupportedYönteme gelince , insan tarafından okunabilir dizede gösterilecek geçerli bir alan varsa bilgileri döndürmesi. Her neyse, "maskeleme" aslında bir maske değildir. Kod gösterileri return value!=0ldeğil return value!=01. Lütfen bir dahaki sefere kopyala-yapıştır yöntemini kullanın.
MrJames

1
Arabirimin TemporalAccessorsüreler boyunca yanlış kullanılması gerekmez. JSR-310 TemporalAmountbu amaç için arayüzü tasarlamıştır .
Meno Hochschild

1
LBir longdeğeri belirtmek için her zaman büyük harf kullanmanızı öneririz . Daha lönce gösterildiği gibi, basamak 1 için küçük harfleri yanlış okumak çok kolaydır .
Ole VV

6

Burada sürenin nasıl biçimlendirileceği ile ilgili bir örnek daha verilmiştir. Bu örneğin hem pozitif hem de negatif süreyi pozitif süre olarak gösterdiğine dikkat edin.

import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;

import java.time.Duration;

public class DurationSample {
    public static void main(String[] args) {
        //Let's say duration of 2days 3hours 12minutes and 46seconds
        Duration d = Duration.ZERO.plus(2, DAYS).plus(3, HOURS).plus(12, MINUTES).plus(46, SECONDS);

        //in case of negative duration
        if(d.isNegative()) d = d.negated();

        //format DAYS HOURS MINUTES SECONDS 
        System.out.printf("Total duration is %sdays %shrs %smin %ssec.\n", d.toDays(), d.toHours() % 24, d.toMinutes() % 60, d.getSeconds() % 60);

        //or format HOURS MINUTES SECONDS 
        System.out.printf("Or total duration is %shrs %smin %sec.\n", d.toHours(), d.toMinutes() % 60, d.getSeconds() % 60);

        //or format MINUTES SECONDS 
        System.out.printf("Or total duration is %smin %ssec.\n", d.toMinutes(), d.getSeconds() % 60);

        //or format SECONDS only 
        System.out.printf("Or total duration is %ssec.\n", d.getSeconds());
    }
}

5

Bu yanıt yalnızca Durationyöntemleri kullanır ve Java 8 ile çalışır:

public static String format(Duration d) {
    long days = d.toDays();
    d = d.minusDays(days);
    long hours = d.toHours();
    d = d.minusHours(hours);
    long minutes = d.toMinutes();
    d = d.minusMinutes(minutes);
    long seconds = d.getSeconds() ;
    return 
            (days ==  0?"":days+" jours,")+ 
            (hours == 0?"":hours+" heures,")+ 
            (minutes ==  0?"":minutes+" minutes,")+ 
            (seconds == 0?"":seconds+" secondes,");
}

4

Bu, çalışan bir seçenektir.

public static String showDuration(LocalTime otherTime){          
    DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_TIME;
    LocalTime now = LocalTime.now();
    System.out.println("now: " + now);
    System.out.println("otherTime: " + otherTime);
    System.out.println("otherTime: " + otherTime.format(df));

    Duration span = Duration.between(otherTime, now);
    LocalTime fTime = LocalTime.ofNanoOfDay(span.toNanos());
    String output = fTime.format(df);

    System.out.println(output);
    return output;
}

Yöntemi şununla çağırın:

System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));

Şuna benzer bir şey üretir:

otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463

2
Bu 23: 59: 59.999'dan daha uzun süreler için başarısız olacaktır.
Michel Jung

4

+ H: MM: SS veya + H: MM: SS.sss döndüren aşağıdaki işleve ne dersiniz?

public static String formatInterval(final long interval, boolean millisecs )
{
    final long hr = TimeUnit.MILLISECONDS.toHours(interval);
    final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
    final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
    final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
    if( millisecs ) {
        return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
    } else {
        return String.format("%02d:%02d:%02d", hr, min, sec );
    }
}

4

En azından 24 saatten daha kısa süreler için oldukça basit ve (IMO) zarif bir yaklaşım var:

DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))

Biçimlendiricilerin biçimlendirmek için geçici bir nesneye ihtiyacı vardır, böylece LocalTime'a 00:00 (yani gece yarısı) süresini ekleyerek bir nesne oluşturabilirsiniz. Bu, gece yarısından o zamana kadar olan süreyi temsil eden ve daha sonra standart SS: dd: sn gösterimlerinde biçimlendirmek için kolay olan bir LocalTime verecektir. Bu, harici bir kütüphaneye ihtiyaç duymama avantajına sahiptir ve hesaplama için saatleri, dakikaları ve saniyeleri manuel olarak hesaplamak yerine java.time kütüphanesini kullanır.


2
String duration(Temporal from, Temporal to) {
    final StringBuilder builder = new StringBuilder();
    for (ChronoUnit unit : new ChronoUnit[]{YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
        long amount = unit.between(from, to);
        if (amount == 0) {
            continue;
        }
        builder.append(' ')
                .append(amount)
                .append(' ')
                .append(unit.name().toLowerCase());
        from = from.plus(amount, unit);
    }
    return builder.toString().trim();
}

1

bu fontu kullanarak

private static String strDuration(long duration) {
    int ms, s, m, h, d;
    double dec;
    double time = duration * 1.0;

    time = (time / 1000.0);
    dec = time % 1;
    time = time - dec;
    ms = (int)(dec * 1000);

    time = (time / 60.0);
    dec = time % 1;
    time = time - dec;
    s = (int)(dec * 60);

    time = (time / 60.0);
    dec = time % 1;
    time = time - dec;
    m = (int)(dec * 60);

    time = (time / 24.0);
    dec = time % 1;
    time = time - dec;
    h = (int)(dec * 24);
    
    d = (int)time;
    
    return (String.format("%d d - %02d:%02d:%02d.%03d", d, h, m, s, ms));
}

Bu işlevin paketlenmiş bir sürümünü edinmek için github.com/ipserc/duration adresine gidin
ipserc

Aradığım kod
buydu

0

Kütüphanem Time4J , desen tabanlı bir çözüm sunuyor (buna benzer Apache DurationFormatUtilsancak daha esnek):

Duration<ClockUnit> duration =
    Duration.of(-573421, ClockUnit.SECONDS) // input in seconds only
    .with(Duration.STD_CLOCK_PERIOD); // performs normalization to h:mm:ss-structure
String fs = Duration.formatter(ClockUnit.class, "+##h:mm:ss").format(duration);
System.out.println(fs); // output => -159:17:01

Bu kod, saat taşması ve işaret işlemeyi işleme yeteneklerini gösterir, ayrıca kalıba dayalı süre biçimlendiricisinin API'sına bakın .


0

Skala'da (başka denemeler gördüm ve etkilenmedim):

def formatDuration(duration: Duration): String = {
  import duration._ // get access to all the members ;)
  f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}

Korkunç görünüyor evet? İşte bu yüzden metodu çağırmak için IDE'leri kullanıyoruz.$toHoursPart vb.) Farklı bir renk .

f"..."Bir olan printf/ String.format(mümkün kılan budur tarzı dize interpolator $bir çıkış Verilen işe yerleştirilen kodu) 1 14:06:32.583, fara değerli dize eşdeğer olacaktırString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)


-1

Scala'da YourBestBet'in çözümünü temel alıyor ancak basitleştirilmiş:

def prettyDuration(seconds: Long): List[String] = seconds match {
  case t if t < 60      => List(s"${t} seconds")
  case t if t < 3600    => s"${t / 60} minutes" :: prettyDuration(t % 60)
  case t if t < 3600*24 => s"${t / 3600} hours" :: prettyDuration(t % 3600)
  case t                => s"${t / (3600*24)} days" :: prettyDuration(t % (3600*24))
}

val dur = prettyDuration(12345).mkString(", ") // => 3 hours, 25 minutes, 45 seconds

-2

scala'da kütüphane gerekmez:

def prettyDuration(str:List[String],seconds:Long):List[String]={
  seconds match {
    case t if t < 60 => str:::List(s"${t} seconds")
    case t if (t >= 60 && t< 3600 ) => List(s"${t / 60} minutes"):::prettyDuration(str, t%60)
    case t if (t >= 3600 && t< 3600*24 ) => List(s"${t / 3600} hours"):::prettyDuration(str, t%3600)
    case t if (t>= 3600*24 ) => List(s"${t / (3600*24)} days"):::prettyDuration(str, t%(3600*24))
  }
}
val dur = prettyDuration(List.empty[String], 12345).mkString("")

3
Bu Scala için harika bir ilan değil mi? Kütüphaneye gerek yok, ama kod kadar ...?
Adam

Özyinelemeli yaklaşımı seviyorum, ancak çok basitleştirilebilir: stackoverflow.com/a/52992235/3594403
dpoetzsch

-2

Bunu görmedim, bu yüzden ekleyeceğimi düşündüm:

Date started=new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
task
long duration=new Date().getTime()-started.getTime();
System.out.println(format.format(new Date(duration));

Sadece 24 saat çalışıyor ama genelde bu süreyi istiyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.