Java 8: Birden fazla birimde iki LocalDateTime arasındaki fark


266

İkisi arasındaki farkı hesaplamaya çalışıyorum LocalDateTime .

Çıktının formatta olması gerekir y years m months d days h hours m minutes s seconds. İşte yazdıklarım:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

Aldığım çıktı 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. Sonucumu bu web sitesinden (değerler 12/16/1984 07:45:55ve 09/09/2014 19:46:45) kontrol ettim . Aşağıdaki ekran görüntüsü çıktıyı göstermektedir:

Dönem Dönüştürücü

Ay değerinden sonraki alanların kodumdan yanlış geldiğinden eminim. Herhangi bir öneri çok yararlı olacaktır.

Güncelleme

Sonucumu başka bir web sitesinden test ettim ve aldığım sonuç farklı. İşte: İki tarih arasındaki süreyi hesapla (sonuç: 29 yıl, 8 ay, 24 gün, 12 saat, 0 dakika ve 50 saniye).

Güncelleme

İki farklı siteden iki farklı sonuç aldığım için, hesaplama algoritmamın meşru olup olmadığını merak ediyorum. Aşağıdaki iki LocalDateTimenesneyi kullanırsam:

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Sonra çıktı geliyor: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

Bu linkten olmalı 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Yani algoritmanın negatif sayıları da ele alması gerekiyor.

Soru hangi sitenin bana hangi sonucu verdiğini değil, doğru algoritmayı bilmem ve doğru sonuçlara sahip olmam gerektiğini not edin.


Sadece bir tahmin, ama Period.between()yuvarlama uygulayabilir mi?
Thomas

3
Sadece bir kez daha koda baktım ve web sitesi yanlış görünüyor (Kendinizi hesaplamayı deneyin). Tarihi, yani yıl, ay ve gün içindeki farklılıkları atlarsanız, başlangıç 7:45:55ve bitiş saatlerini 19:46:45(veya 7:46:45PM) alırsınız . Bu iki zaman arasındaki fark 12 saat, 0 dakika ve 50 saniyedir ve asla 23 saat, 34 dakika ve 12 saniyedir. Yani hesaplama gerçekliğiniz en azından zaman kısmında doğru gibi görünüyor.
Thomas

1
Bu web sitesinde ilginç bir fenomen: başlangıç ​​tarihine 10 yıl ekleyin ve saat farkı 23'den 8'e değişir - kesinlikle bir hata işareti.
Thomas

8
Çünkü unutmayın LocalDateTimehiçbir zaman dilimini vardır, benzersiz bir cevap olmayabilir. Başlangıç ​​ve bitiş saat dilimlerinin aynı olduğunu varsaysanız bile, 2014-09-09 gibi bazı bölgelerde Yaz Saati Uygulamasında veya Yaz Saati'nde, diğer bölgelerde ise olmayacaktır. Bu işleri bir saat kadar azaltabilir. Dolayısıyla, ikinciye olan farkı hesaplamak, bu çözümlenmedikçe anlamsızdır.
Stuart Marks

2
LocalDateTimeBu sınıfın bilerek herhangi bir zaman dilimi veya UTC'den sapma kavramından yoksun olduğundan, kullanımın gerçekçi olmayan sonuçlar verdiğini anlıyor musunuz ? Gerçekçi değerler için, üzerinden bir zaman dilimini atamak ZoneIdkullanımına ZonedDateTime.
Basil Bourque

Yanıtlar:


163

Ne yazık ki, zaman da kapsayan bir dönem sınıfı yok gibi görünüyor, bu yüzden hesaplamaları kendi başınıza yapmanız gerekebilir.

Neyse ki, tarih ve saat sınıflarının bunu bir dereceye kadar basitleştiren birçok yararlı yöntemi vardır. En hızlı olmamakla birlikte farkı hesaplamanın bir yolu:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

Temel fikir şudur: geçici bir başlangıç ​​tarihi oluşturun ve tüm yılları sonuna kadar getirin. Ardından, başlangıç ​​tarihinin bitiş tarihinden bir yıldan az olması için bu tarihi yıl sayısına göre ayarlayın. Bunu her zaman birimi için azalan sırada tekrarlayın.

Sonunda bir feragatname : Farklı zaman dilimlerini hesaba katmadım (her iki tarih de aynı saat diliminde olmalıdır) ve ayrıca gün ışığından yararlanma saatinin veya bir takvimdeki diğer değişikliklerin (Samoa'daki saat dilimi değişiklikleri gibi) nasıl test edip kontrol etmedim bu hesaplamayı etkiler. Bu yüzden dikkatli kullanın.


1
Aynı temel fikre sahipsiniz, bu yüzden benim oyum, ancak lütfen aynı girişi kullanmaya çalışın, aksi takdirde farklı sonuç kafa karıştırıcıdır.
Meno Hochschild

@MenoHochschild o olduğunu sadece OP negatif süreleri ile sorunları vardır güncelleme alınan aynı giriş. ;)
Thomas

1
İyi algoritma, ancak yanlış tip (bkz. Thomas sorumluluk reddi). Hesaplama yapmadan önce, örneğin varsayılan saat dilimini (veya ihtiyacınız olan herhangi bir saat dilimini) kullanarak LocalDateTime değişkenlerinizi ZonedDateTime'a dönüştürmelisiniz: ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan

2
@Thomas Örneğiniz de Java 8 kullanıyor ve soru java-8 olarak etiketleniyor. Aslında örneğiniz bile ChronoUnit:) kullanıyor ancak "elle" işini yapıyor.
Eugene Beresovsky

3
@EugeneBeresovsky oh evet, haklısın. Tamamen kaçırdı;) - Bunun yanı sıra, örneğin long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);en az 1 saatlik herhangi bir aralık için 59'dan büyük bir sayı döndüreceği için daha büyük birimleri aralıktan çıkarmanız gerekir - ve OP'nin istediği bu değildir. Bunu göz önünde bulundurarak, sadece 6 çağrı yapamazsınız ChronoUnit#between()ve yapamazsınız .
Thomas

503

Bunu yapmanın en iyi yolunu ChronoUnit ile buldum.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

Ek belgeler burada: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html


8
Gerçek bir gelişme görmüyorum. Sadece yerine Kabul Thomas'ın cevap ile karşılaştırıldığında tempDateTime.until( toDateTime, ChronoUnit.YEARS)ile ChronoUnit.YEARS.between(fromDate, toDate). Ancak tempDateTime.plusYears( years )vb. Gibi önemli ek satırlar cevabınızda tamamen eksik olduğundan OP'ye yardımcı olmaz. Komple algoritma önemlidir!
Meno Hochschild

9
Daha özlü ve daha okunabilir olduğu için bunu daha çok seviyorum. İki tarih arasındaki farkı bulmanın en iyi yolu budur.
Somaiah Kumbera

7
@SomaiahKumbera Hayır, kritik noktayı tamamen özlüyorsunuz. OP sadece bir birimde değil, birden fazla birimde bir süre istemez ve bu nedenle bu cevap hiç de gerçek bir cevap değildir. OP'nin endişesi basitçe ele alınmıyor. Lütfen soruyu tekrar okumak için çok nazik olun. (Birçok upvoters soruyu yanlış anlamış görünüyor).
Meno Hochschild

125
@MenoHochschild, bence aslında kritik noktayı kaçırıyorsun. OP cevaplarını bir yıl önce aldı. Bu soruyu inceleyen 36 bin kişi OP'nin özel sorusunu umursamıyor. Burada google tarafından yönetildiler ve cevabım onlara aradıkları şeyi sağladı - iki tarih arasındaki farkı elde etmek için temiz ve basit bir çözüm.
satnam

10
İki tarih arasındaki saniye farkına ihtiyacım vardı ve kendi çözümümü uygulamaya başladım. Kısaca karmaşık görünüyor ve ben google aldı. satnam cevabı OP sorusuna cevap vermeyebilir ama kesin olarak bana çok yardımcı oldu ve benim gibi birçok kişiye bahse girerim.
Julian

43

Burada 'ss: dd: ss' biçimini almak için Duration ve TimeUnit kullanan tek bir örnek.

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

2
Böyle yapmak aslında mümkün: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Parça yöntemleri, bir dize oluşturmak için doğru sayıları verir. Bence daha okunaklı.
Daantie

Önceki açıklamamın yan notu: parça yöntemleri yalnızca JDK 9 ve sonraki sürümlerden edinilebilir.
Daantie

40

Daha basit olmalı!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();

1
Bunun aslında Java 8'den başlayarak anlamsal olarak doğru bir çözüm olduğuna inanıyorum. Ve bu sürümden önce JodaTime aynı şeyi yapıyor.
Vrakfall

9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

ve ardından yöntemleri kullanmak period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Genişletilmiş cevap

Orijinal soruyu cevaplayacağım, yani LocalDateTimesfarklı birimler için tüm değerlerin "toplamı (aşağıdaki nota bakın)" zamansal fark ve her bir ünitedeki değer bir sonraki büyük üniteden daha küçük olacak şekilde, yani minutes < 60, hours < 24vb.

İki Verilen LocalDateTimes startve end, örneğin

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

Durationikisinin arasındaki mutlak zaman aralığını bir - belki de kullanarak Duration.between(start, end). Ancak, ayıklayabileceğimiz en büyük birim Durationgünlerdir (24 saate eşdeğer bir geçici birim olarak) - bir açıklama için aşağıdaki nota bakın. Daha büyük birimler (aylar, yıllar) kullanmak için bunu Durationbir çift ( Period, Duration) ile temsil edebiliriz , burada Periodölçümler gün hassasiyetine kadar olan farkı ölçer Durationve geri kalanını temsil eder:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Şimdi tek tek birimleri tanımlamak Periodve Durationtek tek birimleri ayıklamak için basitçe kullanabiliriz :

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

veya varsayılan biçimi kullanarak:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Yıllar, aylar ve günler hakkında not

Not içinde, o java.time'ın anlayışına, 'ay' veya 'Yılın' gibi 'birimleri' temsil etmemektedir sabit, mutlak zamansal değer-Onlar Tarih-ve takvim bağımlı, aşağıdaki örnekte gösterildiği gibi:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365

5

Tapas Bose kodu ve Thomas kodu için bir sorun var. Zaman farkı negatifse, dizi negatif değerleri alır. Örneğin,

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

0 yıl 0 ay 1 gün -1 saat 0 dakika 0 saniye döndürür.

Bence doğru çıktı: 0 yıl 0 ay 0 gün 23 saat 0 dakika 0 saniye.

LocalDate ve LocalTime örneklerinde LocalDateTime örneklerini ayırmayı öneririm. Bundan sonra Java 8 Dönemi ve Süresi örneklerini edinebiliriz. Süre örneği, gün sayısına ve gün boyunca zaman değerine (<24 saat) sonra dönem değerinin düzeltilmesi ile ayrılır. İkinci LocalTime değeri firstLocalTime değerinden önce olduğunda, süreyi bir gün azaltmak gerekir.

İşte LocalDateTime farkını hesaplamanın yolu:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

Yukarıdaki yöntem, herhangi bir yerel tarih ve saat değerinin farkını hesaplamak için kullanılabilir, örneğin:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

Yukarıdaki yöntem için bir birim testi yazmak uygundur (her ikisi de PeriodDuration sınıf üyeleridir). İşte kod:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

İlk LocalDateTime değerinin herhangi bir LocalTime değerinden önce ve sonra olsun tüm testler başarılı olur.


Yukarıdaki girişinizi kullanarak Thomas kodunun karışık işaretler ürettiğini ifade edemem. Çıktılarım: "0 yıl 0 ay 0 gün 23 saat 0 dakika 0 saniye." Ve şimdi test ettim.
Meno Hochschild

Yorum için teşekkürler. Thomas kodunu iyice test ettim, gerçekten doğru çalışıyor! Sihir, krono birimlerini düzelten yöntem kadar LocalDateTime tarafından yapılır. İlk DateTime ikinciden sonraysa, Thomas kodundaki negatif değerler görünür. Ancak bu, yukarıdaki kodda yaptığım gibi kolayca düzeltilebilir. Tekrar teşekkürler.
Gennady Kolomoets

Eh, Thomas kodu ve süreleri hesaplamak için aynı algoritmayı kullanan kütüphanem Time4J negatif işaretler üretebilir, ancak sadece bütün süre boyunca. Bu çok önemli bir nokta! İşaret tüm süre ile ilgilidir ve bu nedenle başlangıcın sondan sonra olup olmadığını ve hiçbir zaman tek süreli bileşenlerle ilişkili olup olmadığını açıklar. Burada karışık işaretler mümkün değildir ve sonuna göre böyle bir başlangıç ​​yorumunu önleyecektir (karşı örnek Joda-Time dönemidir veya java.time.Periodkullanıcıların farklı iç tasarım nedeniyle bu tür karışık işaretleri uygulayabileceği / üretebileceği yerler).
Meno Hochschild

5

Ve içinde @Thomas sürümü Groovy ile yerine değerlerini hardcoding listesinde istenen birimler sürer. Bu uygulama (kolayca Java'ya taşınabilir - fonksiyon bildirimini açık hale getirdim) Thomas yaklaşımını daha yeniden kullanılabilir hale getirir.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

Bu yazı yazılırken, yukarıdaki kod geri döner 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. Ve @Gennady Kolomoets girişi için kod geri döner 23 Hours.

Birimler listesi sağladığınızda, birimlerin boyutuna göre sıralanması gerekir (önce en büyük):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours

4

İşte sorunuza çok basit bir cevap. İşe yarıyor.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}

1
Bunun doğru olmadığını söylemeliyim. bununla deneyin. 1 dakika fark diyor. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Mark Amabile

Dün gece bir saat girdim ve girdim Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. İstenilenin bu olduğunu düşünmüyorum.
Ole VV

@ OleV.V. O sorunu düzeltildi
SavedBeau

1

Joda-Time

Cevapların çoğu API 26 desteği ve min API'm 23 olduğundan, aşağıdaki kodla çözdüm:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days

1
Joda-Time proje onun yaratıcısı Stephen Colebourne oluşturmak için gitmiş olan, bakım-modundayken java.time çoğu JSR 310 'da tanımlanan sınıfları java.time işlevselliği Java 6 ve 7 geri portlu olan ThreeTen- Backport projesi. ThreeTenABP projesinde erken Android için daha da uyarlandı .
Basil Bourque

1

Beş yıldan fazla bir süre sonra soruma cevap veriyorum. Negatif süreyle ilgili sorunun basit bir düzeltme ile çözülebileceğini düşünüyorum:

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Not: https://www.epochconverter.com/date-difference sitesi artık zaman farkını doğru bir şekilde hesaplamaktadır.

Tartışma ve önerileriniz için hepinize teşekkür ederim.


Cevap için teşekkürler. Saat ve daha küçükler için toHours, toMinutesve toSecondsyöntemlerinden yararlanabilirsiniz Duration. Java 9 toMinutesPart()ve daha beri toSecondsPart(). Ve saatleri, dakikaları ve saniyeleri sadece tekrar çıkarmak için bir diziye sarma noktasını görmüyorum. Yine de genellikle iyi bir cevap.
Ole VV

Beş yıldan fazla bir süre sonra soruma cevap veriyorum. Soru farklı bir ad, unvan ve konuma sahip bir hesaptan gönderildi, çok fazla benzemiyor mu? Merak etmenin bir önemi olmadığı için değil.
Ole VV

"Beş yıldan fazla bir süre sonra sorumu cevaplıyorum" Ben OP olduğunu sanırım :)
Tapas Bose
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.