簡體   English   中英

如何確定Java之間的現在和任意未來日期之間的時間

[英]How to determine the time between now and an arbitrary future date in Java

我目前正在嘗試確定兩個日期之間的時間量(其中一個是當前日期/時間,另一個是任意未來日期)。 我只使用原生Java和Android API,但我遇到GregorianCalendar的一些問題。 到目前為止,我的代碼可以在下面看到,但我遇到的問題是兩個日期之間的時間非常不准確。 你可以看到我在這個例子中將未來的日期設定為聖誕節,但它告訴我在那之前有超過62天,這顯然是錯誤的。

    date = new GregorianCalendar();
    currentTime = date.getTimeInMillis();
    calendar = new GregorianCalendar();
    calendar.set(2011, 12, 25, 0, 0, 0);
    long difference = calendar.getTimeInMillis()-currentTime;

    long x = difference / 1000;
    seconds = x % 60;
    x /= 60;
    minutes = x % 60;
    x /= 60;
    hours = x % 24;
    x /= 24;
    days = x;

調試時我添加了date.set(2011,11,23,13,1,15); 哪個更准確,但是當我相信正確的天數是31天時它仍然顯示32天。

非常感謝您的任何幫助,非常感謝。

您的代碼中的問題是方法calendar.set(2011, 12, 25, 0, 0, 0); 你想要的是calendar.set(2011, 11, 25, 0, 0, 0);

你也可以使用Calendar.DECEMBER

javadoc對於這種方法很清楚:

  • @param month用於設置MONTH日歷字段的值。 *月值基於0。 例如,1月份為0。

java.time

Java 8及更高版本中內置的新java.time框架取代了舊的令人困惑的java.util.Date/.Calendar類

教程演示了如何將一段時間定義為總天數以及期間,邏輯年數,月數和天數。

LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);

Period p = Period.between(birthday, today);
long p2 = ChronoUnit.DAYS.between(birthday, today);
System.out.println("You are " + p.getYears() + " years, " + p.getMonths() +
               " months, and " + p.getDays() +
               " days old. (" + p2 + " days total)");

代碼生成類似於以下內容的輸出:

你有53歲零4個月29天。 (總共19508天)

我會通過將時區傳遞給now來改進Tutorial的示例,而不是隱含地依賴於JVM當前的默認時區,該時區可以隨時改變。 雖然LocalDate沒有分配時區(這就是本地的意思),但在確定時區是至關重要的。 例如,巴黎的新日早些時候比蒙特利爾早。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

要獲得直到下一個生日的日子,請通過替換年份來構建未來日期。 Java.time框架使用不可變對象,因此顯示的語法基於原始值創建新對象,同時保持原始完整且不受影響。

LocalDate birthdayThisYear = birthday.withYear( today.getYear() );
if ( birthdayThisYear.isBefore( today ) ) {
    birthdayThisYear.plusYears( 1 );
}
long daysUntilBirthday = ChronoUnit.DAYS.between( today , birthdayThisYear );

喬達時間

Joda-Time庫為java.time提供了靈感。 當Java 8技術不可用時使用Joda-Time,例如在Android中。 對於Android,你可以從其他來源找到Joda-Time的特殊版本來調解Dalvik中的一些緩慢加載問題。

在這種情況下,Joda-Time和java.time之間的代碼類似。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
LocalDate today = LocalDate.now( zone );
LocalDate birthdate  = new LocalDate( 1966 , 1 , 2 );
LocalDate nextBirthday = birthdate.withYear( today.getYear() );
if ( nextBirthday.isBefore( today ) ) {
    nextBirthday = nextBirthday.plusYears( 1 );
}
int daysUntilBirthday = Days.daysBetween( today , nextBirthday ).getDays();

Joda-Time還提供Period類。 但是,此類處理部分天,而java.time Period僅處理整天。 因此,我們需要將LocalDate實例轉換為DateTime實例以提供給Period構造函數。

DateTime start = today.toDateTimeAtStartOfDay( zone );
DateTime stop = nextBirthday.toDateTimeAtStartOfDay( zone );
Period period = new Period( start , stop );

默認格式化程序使用ISO 8601標准格式。 因此,調用period.toString()這樣的內容呈現三個月和兩天:

P3M2D

而不是這樣做:

 long x = difference / 1000;
seconds = x % 60;
x /= 60;
minutes = x % 60;
x /= 60;
hours = x % 24;
x /= 24;
days = x;

使用兩個日期之間的差異(長值)構建一個Date對象。 然后,您可以在Calendar對象上執行setDate(Date)並解析它。

或者,你可以看一下相對容易使用的Joda Time Api。

首先,我建議您使用庫方法進行計算。 首先,你不應該重新發明輪子。 其次,一些計算可能會變得棘手,例如,如果您還想報告數月或數年,並且需要考慮不同的月份長度和閏年。 尤其是,雖然在編寫代碼時很容易將60除以從秒轉換為分鍾,但在讀取代碼時,其中包含“分鍾”或“秒”的方法名稱將更清楚地表達為什么要除以60。

這些天Java有兩個類的時間量:

  • Duration是指時鍾時間之間的時間,例如2小時46分30秒(它也可以處理數天,但不知道數周或數月)。
  • Period是指日期之間的時間,例如2個月9天。

對於一般解決方案,我將展示如何將兩者用於您的任務。 我第一次發現Period之間的日期。 如果那是從今天下午2點到后天上午10點,你將得到兩天,我們想要1天20小時,所以我們需要在計算Duration之前減去1天進行調整。

    LocalDateTime dateTimeOne = LocalDateTime.of(2016, Month.APRIL, 25, 9, 5, 30);
    LocalDateTime dateTimeTwo = LocalDateTime.of(2017, Month.MAY, 15, 9, 10, 50);

    Period p = Period.between(dateTimeOne.toLocalDate(), dateTimeTwo.toLocalDate());
    LocalDateTime dtOnePlusPeriod = dateTimeOne.plus(p);
    if (dtOnePlusPeriod.isAfter(dateTimeTwo)) { // too far
        p = p.minusDays(1);
    }
    Duration d = Duration.between(dateTimeOne.plus(p), dateTimeTwo);

    long hours = d.toHours();
    d = d.minusHours(hours);
    long minutes = d.toMinutes();
    d = d.minusMinutes(minutes);
    long seconds = d.getSeconds();

    if (p.isZero() && d.isZero()) {
        System.out.println("0 seconds");
    } else {
        if (p.getYears() != 0) {
            System.out.print("" + p.getYears() + " years ");
        }
        if (p.getMonths() != 0) {
            System.out.print("" + p.getMonths() + " months ");
        }
        if (p.getDays() != 0) {
            System.out.print("" + p.getDays() + " days ");
        }
        if (hours != 0) {
            System.out.print("" + hours + " hours ");
        }
        if (minutes != 0) {
            System.out.print("" + minutes + " minutes ");
        }
        if (seconds != 0) {
            System.out.print("" + seconds + " seconds");
        }
        System.out.println();
    }

這打印

1 years 20 days 5 minutes 20 seconds

通過使用LocalDateTime我忽略了夏令時(DST)的變化。 如果您需要考慮這些因素,請使用ZonedDateTime

所有類都在java.time包中。 我將在底部包含指向Oracle教程的鏈接。

如果你想在Android上使用java.time ,你可以在ThreeTenABP中獲得它們。 以下更多鏈接。

使用Java 9將在DurationtoHoursPart()toMinutesPart()toSecondsPart()中提供一些新方法,它們將為我們提供我們想要的小時,分​​鍾和秒,就像我已經使用Period完成的那樣。 然后我們將不再需要在計算單個字段時先減去小時數然后再減去分鍾數。

鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM