簡體   English   中英

在 java.time.LocalDateTime 和 java.util.Date 之間轉換

[英]Converting between java.time.LocalDateTime and java.util.Date

Java 8 有一個全新的日期和時間 API。 此 API 中最有用的類之一是LocalDateTime ,用於保存與時區無關的日期時間值。

為此,可能有數百萬行代碼使用遺留類java.util.Date 因此,當連接新舊代碼時,需要在兩者之間進行轉換。 由於似乎沒有直接的方法來實現這一點,如何做到這一點?

簡短的回答:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

解釋:(基於這個關於LocalDate 問題

盡管它的名字, java.util.Date代表時間線上的一個瞬間,而不是“日期”。 對象中存儲的實際數據是自 1970-01-01T00:00Z(格林威治標准時間 1970/UTC 開始時的午夜)以來的long計數。

JSR-310 java.util.Date的等效類是Instant ,因此有方便的方法來提供來回轉換:

Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);

java.util.Date實例沒有時區的概念。 如果您在java.util.Date上調用toString() ,這可能看起來很奇怪,因為toString是相對於時區的。 然而,該方法實際上使用 Java 的默認時區即時提供字符串。 時區不是java.util.Date的實際狀態的一部分。

Instant也不包含有關時區的任何信息。 因此,要將Instant轉換為本地日期時間,必須指定時區。 這可能是默認區域 - ZoneId.systemDefault() - 或者它可能是您的應用程序控制的時區,例如來自用戶首選項的時區。 LocalDateTime有一個方便的工廠方法,可以同時使用即時和時區:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

相反,時區的LocalDateTime是通過調用atZone(ZoneId)方法指定的。 ZonedDateTime然后可以直接轉換為Instant

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

請注意,從LocalDateTimeZonedDateTime的轉換可能會引入意外行為。 這是因為由於夏令時,並非每個本地日期時間都存在。 在秋季/秋季,本地時間線重疊,同一本地日期時間出現兩次。 在春天,有一個缺口,一個小時消失了。 有關轉換將執行的操作的更多定義,請參閱atZone(ZoneId)的 Javadoc。

總結,如果您將java.util.Date往返到LocalDateTime並返回到java.util.Date ,由於夏令時,您最終可能會得到不同的時刻。

附加信息:還有另一個差異會影響非常舊的日期。 java.util.Date使用在 1582 年 10 月 15 日更改的日歷,在此之前的日期使用儒略歷而不是公歷。 相比之下, java.time.*使用 ISO 日歷系統(相當於公歷)。 在大多數用例中,ISO 日歷系統正是您想要的,但在比較 1582 年之前的日期時,您可能會看到奇怪的效果。

這是我想出的(和所有日期時間難題一樣,它可能會根據一些奇怪的時區-閏年-日光調整而被否定:D)

往返: Date <<->> LocalDateTime

鑒於: Date date = [some date]

(1) LocalDateTime << Instant << Date

    Instant instant = Instant.ofEpochMilli(date.getTime());
    LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

(2) Date << Instant << LocalDateTime

    Instant instant = ldt.toInstant(ZoneOffset.UTC);
    Date date = Date.from(instant);

例子:

鑒於:

Date date = new Date();
System.out.println(date + " long: " + date.getTime());

(1) LocalDateTime << Instant << Date

Date創建Instant

Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);

Instant創建Date (不是必需的,但為了說明):

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

Instant創建LocalDateTime

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);

(2) Date << Instant << LocalDateTime

LocalDateTime創建Instant

instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);

Instant創建Date

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

輸出是:

Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

Instant from Date:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

LocalDateTime from Instant:
2013-11-01T14:13:04.574

Instant from LocalDateTime:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

如果您確定需要默認時區,則使用更方便的方法:

Date d = java.sql.Timestamp.valueOf( myLocalDateTime );

LocalDateTime -> Date的最快方法是:

Date.from(ldt.toInstant(ZoneOffset.UTC))

從新的 API LocalDateTime 轉換為 java.util.date 時,以下內容似乎有效:

Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());

可以(希望)以類似的方式實現反向轉換......

希望能幫助到你...

如果您使用的是 android 並使用Threetenbp ,則可以改用DateTimeUtils

前任:

Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

您不能使用Date.from因為它僅在 api 26+ 上受支持

一切都在這里: http : //blog.progs.be/542/date-to-java-time

“往返”的答案並不准確:當你這樣做時

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

如果您的系統時區不是 UTC/GMT,請更改時間!

我不確定這是最簡單還是最好的方法,或者是否有任何陷阱,但它有效:

static public LocalDateTime toLdt(Date date) {
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(date);
    ZonedDateTime zdt = cal.toZonedDateTime();
    return zdt.toLocalDateTime();
}

static public Date fromLdt(LocalDateTime ldt) {
    ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
    GregorianCalendar cal = GregorianCalendar.from(zdt);
    return cal.getTime();
}

我認為以下方法將在不考慮時區的情況下解決轉換問題。 如果有任何陷阱,請發表評論。

    LocalDateTime datetime //input
    public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
    Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output

暫無
暫無

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

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