[英]Get precise difference between two dates in java
我正在尋找一種方法來獲取兩個日期之間的差異,正如標題所說,在 Java 中。 例如,如果d1 = 2017-01-23 05:25:00
和d2 = 2018-03-20 07:29:50
,某些方法會打印
Years: 1
Months: 1
Days: 25
Hours: 2
Minutes: 4
Seconds: 50
我嘗試使用 LocalDateTime 對象來做到這一點,但我找不到一種方法來獲得它們之間的月份。 我認為不需要包含該代碼,但如果需要,我可以。 我不在乎日期是什么類型,但我不想使用 Joda 時間或其他外部庫。 預先感謝您的幫助。
我們必須解析你的字符串。 java.time 類在解析/生成字符串時默認使用標准 ISO 8601 格式。 您的輸入接近合規; 我們只需要用T
替換中間的 SPACE 。
String inputStart = "2017-01-23 05:25:00".replace ( " " , "T" );
String inputStop = "2018-03-20 07:29:50".replace ( " " , "T" );
LocalDateTime
您的輸入缺少與 UTC 或時區偏移的任何指示。 因此,他們不會在時間線中,在時間軸上的時刻,可能只有模糊的概念上代表實際的時刻。 所以我們將其解析為LocalDateTime
對象。 我們將執行的用於確定時間跨度的數學計算將基於通用的 24 小時制,並且將忽略諸如夏令時 (DST) 之類的異常情況。
LocalDateTime start = LocalDateTime.parse ( inputStart );
LocalDateTime stop = LocalDateTime.parse ( inputStop );
Period
和Duration
java.time 類將與時間線無關的時間跨度定義為兩部分。 Period
類代表年-月-日,而Duration
類代表時-分-秒。
將時間跨度分成這兩部分可以避免某些問題,我們必須解決這些問題才能解決您的請求。 您究竟想如何處理第一天可能不完整的一天和最后一天可能不完整的一天? 一天中午到第二天中午是一天還是24小時? 如果我們將第一天的小時數與最后一天的小時數相加,如果該數字超過 24 小時,我們是否應該擠出一整天?
這里我采用全天數的方法,忽略第一天和最后一天。 然后我將第一天的小時數與最后一天的小時數相加。 正如我們在您的示例數據中看到的那樣,這可能會導致我們的Duration
超過 24 小時。 這種方法可能會也可能不會滿足您未說明的意圖/定義。
Period p = Period.between ( start.toLocalDate () , stop.toLocalDate () ).minusDays ( 1 ); // Subtract one, as we account for hours of first day.
// Get the Duration of first day's hours-minutes-seconds.
LocalDateTime startNextDay = start.toLocalDate ().plusDays ( 1 ).atStartOfDay ();
Duration dStart = Duration.between ( start , startNextDay );
// Get the Duration of first day's hours-minutes-seconds.
LocalDateTime stopStartOfDay = stop.toLocalDate ().atStartOfDay ();
Duration dStop = Duration.between ( stopStartOfDay , stop );
// Combine the pair of partial days into a single Duration.
Duration d = dStart.plus ( dStop );
轉儲到控制台。 Period
& Duration
類上的toString
方法以 ISO 8601 的標准持續時間格式生成字符串: PnYnMnDTnHnMnS
,其中P
標記開始, T
將年-月-日與時-分-秒分開。
System.out.println ( "start/stop: " + start + "/" + stop );
System.out.println ( "p: " + p );
System.out.println ( "dStart: " + dStart + " and dStop: " + dStop );
System.out.println ( "d: " + d );
開始/停止:2017-01-23T05:25/2018-03-20T07:29:50
p: P1Y1M24D
dStart:PT18H35M 和 dStop:PT7H29M50S
d:PT26H4M50S
要獲得所需的文本輸出,您需要詢問Period
每個部分和Duration
每個部分。
int years = p.getYears ();
int months = p.getMonths ();
int days = p.getDays ();
Java 8 莫名其妙地缺少從Duration
方便地獲取每個小時、分鍾或秒部分的方法。 Java 9 添加了這樣的方法。 有關更多討論,請參閱此問題。
long durationDays = d.toDaysPart();
long hours = d.toHoursPart();
long minutes = d.toMinutesPart();
long seconds = d.toSecondsPart();
int nanos = d.toNanosPart();
請參閱在 IdeOne.com 中實時運行的示例代碼。
ZonedDateTime
上面的討論是針對通用 24 小時制的,忽略了與 UTC/時區偏移的問題。
相反,如果您打算跟蹤時間線上的實際時刻,則必須應用適用於這些日期時間字符串的時區。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = start.atZone( z );
…
其余代碼將類似,但將ZoneId
傳遞給atStartOfDay
調用以生成ZonedDateTime
對象而不是LocalDateTime
對象。
請記住,當使用ZonedDateTime
對象而不是LocalDateTime
對象時,您可能會得到不同的結果。
請參閱IdeOne.com 中的示例代碼。
String inputStart = "2017-01-23 05:25:00".replace ( " " , "T" );
String inputStop = "2018-03-20 07:29:50".replace ( " " , "T" );
LocalDateTime ldtStart = LocalDateTime.parse ( inputStart ); // LocalDateTime used only briefly here, to parse inputs. Then we switch to `ZonedDateTime`.
LocalDateTime ldtStop = LocalDateTime.parse ( inputStop );
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = ldtStart.atZone( z ); // Invalid values may be adjusted, such as during the hour of a "Spring-forward" Daylight Saving Time (DST) switch-over.
ZonedDateTime zdtStop = ldtStop.atZone( z );
Period p = Period.between ( zdtStart.toLocalDate () , zdtStop.toLocalDate () ).minusDays ( 1 ); // Subtract one, as we account for hours of first day.
// Get the Duration of first day's hours-minutes-seconds.
ZonedDateTime zdtStartNextDay = zdtStart.toLocalDate ().plusDays ( 1 ).atStartOfDay ( z );
Duration dStart = Duration.between ( zdtStart , zdtStartNextDay );
// Get the Duration of first day's hours-minutes-seconds.
ZonedDateTime zdtStopStartOfDay = zdtStop.toLocalDate ().atStartOfDay ( z );
Duration dStop = Duration.between ( zdtStopStartOfDay , zdtStop );
// Combine the pair of partial days into a single Duration.
Duration d = dStart.plus ( dStop );
System.out.println ( "zdtStart: " + zdtStart );
System.out.println ( "zdtStop: " + zdtStop );
System.out.println ( "p: " + p );
System.out.println ( "dStart: " + dStart + " and dStop: " + dStop );
System.out.println ( "d: " + d );
int years = p.getYears ();
int months = p.getMonths ();
int days = p.getDays ();
System.out.println( "Years: " + years + "\nMonths: " + months + "\nDays: " + days );
// Enable if in Java 9 or later (but not in Java 8)
// long durationDays = d.toDaysPart();
// long hours = d.toHoursPart();
// long minutes = d.toMinutesPart();
// long seconds = d.toSecondsPart();
// int nanos = d.toNanosPart();
提示: ThreeTen-Extra庫提供了一個Interval
類來跟蹤一對Instant
對象。 Instant
是 UTC 時間線上的時刻。 您可以通過調用toInstant
從ZonedDateTime
提取Instant
。
java.time框架內置於 Java 8 及更高版本中。 這些類取代麻煩的老傳統日期時間類,如java.util.Date
, Calendar
,和SimpleDateFormat
。
現在處於維護模式的Joda-Time項目建議遷移到java.time類。
要了解更多信息,請參閱Oracle 教程。 並在 Stack Overflow 上搜索許多示例和解釋。 規范是JSR 310 。
從哪里獲得 java.time 類?
ThreeTen-Extra項目用額外的類擴展了 java.time。 該項目是未來可能添加到 java.time 的試驗場。 您可以在這里找到一些有用的類,比如Interval
, YearWeek
, YearQuarter
,和更多。
包 com.mkyong.date;
導入 java.text.SimpleDateFormat; 導入 java.util.Date;
公共類 DateDifferentExample {
public static void main(String[] args) {
String dateStart = "01/14/2012 09:29:58";
String dateStop = "01/15/2012 10:31:48";
//HH converts hour in 24 hours format (0-23), day calculation
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
java.util.Date d1 = null;
java.util.Date d2 = null;
try {
d1 = format.parse(dateStart);
d2 = format.parse(dateStop);
//in milliseconds
long diff = d2.getTime() - d1.getTime();
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.print(diffDays + " days, ");
System.out.print(diffHours + " hours, ");
System.out.print(diffMinutes + " minutes, ");
System.out.print(diffSeconds + " seconds.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
結果
1天1小時1分50秒。
我只會將您想要的兩個日期和時間放入 SimpleDateFormat 中。 然后您可以執行 date.getTime() 並以毫秒為單位返回距離,然后可以將其轉換回天數、年數或月數。 這是我寫的一個例子:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;
public class DateTest{
public static void main(String[] args) throws ParseException{
System.out.println("Current time in milliseconds: " + System.currentTimeMillis());
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss MM/dd/yyyy");
String dateAndTime1 = "2:30:00 1/23/2017";
String dateAndTime2 = "1:45:00 5/23/2015";
Date date1 = format.parse(dateAndTime1);
Date date2 = format.parse(dateAndTime2);
long difference = date1.getTime() - date2.getTime();
System.out.println("The difference in milliseconds is " + difference);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.