簡體   English   中英

Java 8 java.time:在Instant vs LocalDateTime中添加TemporalUnit

[英]Java 8 java.time: Adding TemporalUnit in Instant vs LocalDateTime

我正在使用Java 8中的新java.time包。我有一個遺留數據庫,它給了我java.util.Date ,我轉換為Instant

我想要做的是添加一段基於另一個數據庫標志的時間。 我可以添加幾天,幾周,幾個月或幾年。 我不想關心我要添加的內容,我希望將來能夠添加更多選項。

我的第一個想法是Instant.plus() ,但是對於超過一天的值,這給了我一個UnsupportedTemporalTypeException Instant顯然不支持大單位時間的操作。 無論如何, LocalDateTime都可以。

所以這給了我這個代碼:

private Date adjustDate(Date myDate, TemporalUnit unit){
    Instant instant = myDate.toInstant();
    LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    dateTime = dateTime.plus(1, unit);
    Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
    return new Date(dueInstant.toEpochMilli());
}

現在,這是我第一次使用新的時間API,所以我可能在這里錯過了一些東西。 但是我必須離開這似乎很笨重:

Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.

即使我不必使用Date部分,我仍然認為它有點尷尬。 所以我的問題是,我這樣做完全錯了,最好的辦法是什么?


編輯 :擴展評論中的討論。

我想我現在更好地了解了LocalDateTime和Instant如何使用java.util.Date和java.sql.Timestamp。 感謝大家。

現在,更實際的考慮。 假設用戶向我發送了他們在世界任何地方的日期,任意時區。 他們發送給我2014-04-16T13:00:00我可以解析為LocalDateTime。 然后我將它直接轉換為java.sql.Timestamp並在我的數據庫中保留。

現在,我沒有做任何其他事情,我從我的數據庫中提取java.sql.timestamp,使用timestamp.toLocalDateTime()轉換為LocalDateTime 都好。 然后我使用ISO_DATE_TIME格式將此值返回給我的用戶。 結果是2014-04-16T09:00:00

我認為這種差異是因為某種類型的隱式轉換到/來自UTC。 我認為我的默認時區可能會應用於該值(EDT,UTC-4),這可以解釋為什么數字關閉4小時。

新問題。 從本地時間到UTC的隱式轉換在哪里? 保留時區的更好方法是什么。 我不應該直接從本地時間作為字符串(2014-04-16T13:00:00)到LocalDateTime嗎? 我應該期待用戶輸入的時區嗎?

我將繼續根據我的最終解決方案發布一個答案,並對這個很長的評論鏈進行總結。

首先,整個轉換鏈:

Date --> Instant --> LocalDateTime --> Do stuff --> Instant --> Date

有必要保留時區信息,並仍然在Date上執行操作,比如知道日歷及其中所有上下文的對象。 否則我們冒着隱式轉換到本地時區的風險,如果我們試圖將其置於人類可讀的日期格式中,那么時間可能因此而改變。

例如, java.sql.Timestamp類上的toLocalDateTime()方法隱式轉換為默認時區。 這對我的目的來說是不可取的,但不一定是壞行為。 但是,重要的是要意識到這一點。 這是將遺留的Java日期對象直接轉換為LocalDateTime對象的問題。 由於傳統對象通常假定為UTC,因此轉換使用本地時區偏移量。

現在,假設我們的程序接受2014-04-16T13:00:00的輸入並作為java.sql.Timestamp保存到數據庫。

//Parse string into local date. LocalDateTime has no timezone component
LocalDateTime time = LocalDateTime.parse("2014-04-16T13:00:00");

//Convert to Instant with no time zone offset
Instant instant = time.atZone(ZoneOffset.ofHours(0)).toInstant();

//Easy conversion from Instant to the java.sql.Timestamp object
Timestamp timestamp = Timestamp.from(instant);

現在我們采用時間戳並為其添加一些天數:

Timestamp timestamp = ...

//Convert to LocalDateTime. Use no offset for timezone
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));

//Add time. In this case, add one day.
time = time.plus(1, ChronoUnit.DAYS);

//Convert back to instant, again, no time zone offset.
Instant output = time.atZone(ZoneOffset.ofHours(0)).toInstant();

Timestamp savedTimestamp = Timestamp.from(output);

現在我們只需要輸出ISO_LOCAL_DATE_TIME格式的人類可讀字符串。

Timestamp timestamp = ....
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));
String formatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(time);

暫無
暫無

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

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