Làm cách nào tôi có thể tạo Java 8 LocalDate từ thời gian dài Epoch tính bằng mili giây?


218

Tôi có một API bên ngoài trả về ngày của tôi là long s, được biểu thị bằng mili giây kể từ khi bắt đầu Đại Kỷ Nguyên.

Với API Java kiểu cũ, tôi chỉ cần tạo một Datetừ nó với

Date myDate = new Date(startDateLong)

Tương đương trong Java 8's LocalDate/ LocalDateTimeclass là gì?

Tôi quan tâm đến việc chuyển đổi điểm theo thời gian được biểu thị longthành a LocalDatetrong múi giờ địa phương hiện tại của tôi.


6
Vâng, bạn phải bắt đầu bằng cách tìm ra múi giờ bạn quan tâm. Giá trị "mili giây kể từ kỷ nguyên" cung cấp cho bạn thời gian tức thì ... có thể đề cập đến các ngày khác nhau trong các múi giờ khác nhau. Hãy nhớ rằng đó java.util.Datechưa bao giờ thực sự là một cuộc hẹn theo cách đó LocalDate- đó cũng là một thời điểm ngay lập tức.
Jon Skeet

2
Kiểm tra câu hỏi này: stackoverflow.com/questions/21242110/ , bao gồm việc chuyển đổi java.util.DatethànhLocalDate
hotzst

3
Lưu ý: Câu hỏi và trả lời này cũng có giá trị đối với những người đang cố gắng chuyển đổi File.lastModified()(epoch millis) sang LocalDate(Time).
kevinarpe

Câu trả lời:


403

Nếu bạn có mili giây kể từ Kỷ nguyên và muốn chuyển đổi chúng thành ngày cục bộ bằng múi giờ địa phương hiện tại, bạn có thể sử dụng

LocalDate date =
    Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();

nhưng hãy nhớ rằng ngay cả múi giờ mặc định của hệ thống cũng có thể thay đổi, do đó, cùng một longgiá trị có thể tạo ra kết quả khác nhau trong các lần chạy tiếp theo, ngay cả trên cùng một máy.

Hơn nữa, hãy nhớ rằng LocalDate, không giống như java.util.Date, thực sự đại diện cho một ngày, không phải là một ngày và thời gian.

Nếu không, bạn có thể sử dụng LocalDateTime:

LocalDateTime date =
    LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());

2
+1 từ tôi để giải thích chi tiết hơn. Nhân tiện, ngay cả một khu vực phi hệ thống cũng có thể thay đổi (bởi tzupdater-tool hoặc jdk-change) và do đó tạo ra các kết quả khác nhau trước và sau.
Meno Hochschild

2
@Meno Hochschild: Tôi không tập trung vào các múi giờ được mã hóa cứng mà chỉ so sánh với các múi giờ do người dùng chỉ định, đọc từ tệp cấu hình hoặc các biến môi trường, nơi lập trình viên tự nhiên cho rằng có thể thay đổi. Các múi giờ được mã hóa cứng thực sự giống như mặc định của hệ thống; lập trình viên bị cho rằng họ không bao giờ thay đổi
Holger

2
@Demigod LocalDateTime.ofEpochSecond(…)yêu cầu thực tế ZoneOffset, nhưng ZoneId.systemDefault()trả về a ZoneId. A ZoneIdcó thể ánh xạ tới các độ lệch khác nhau, tùy thuộc vào thời điểm bạn đề cập đến. Đó là những gì LocalDateTime.ofInstantlàm cho bạn, chuyển đổi các chỉ định ZoneIdtheo quy định Instant.
Holger

2
Epoch được định nghĩa là UTC và do đó phải độc lập với múi giờ, do đó, ZoneId phải luôn là UTC.
PlexQ

2
@PlexQ Múi giờ được chỉ định không liên quan đến Epoch, thực sự độc lập với múi giờ, nhưng đối với ngữ nghĩa của kết quả LocalDatehoặc LocalDateTime. Bạn có thể chỉ định bất kỳ múi giờ nào bạn muốn, miễn là nó phù hợp với việc sử dụng tiếp theo của các đối tượng kết quả này. Hãy nghĩ về những gì xảy ra khi bạn đối phó với nhiều đối tượng được tạo bởi các phương thức khác nhau. Các trường hợp sử dụng điển hình cho địa phương ngày hoặc datetimes kết hợp các múi giờ mặc định của hệ thống, ví dụ như LocalDateTime.now()LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault())...
Holger

37

Bạn có thể bắt đầu với Instant.ofEpochMilli (dài) :

LocalDate date =
  Instant.ofEpochMilli(startDateLong)
  .atZone(ZoneId.systemDefault())
  .toLocalDate();

5
+1 vì rõ ràng về múi giờ. Nếu được bỏ qua, múi giờ mặc định hiện tại của JVM hoàn toàn được áp dụng để xác định ngày. Đối với bất kỳ thời điểm nào, ngày thay đổi trên toàn thế giới theo múi giờ là một ngày mới bắt đầu sớm hơn ở phía đông.
Basil Bourque

12

Tôi nghĩ rằng tôi có một câu trả lời tốt hơn.

new Timestamp(longEpochTime).toLocalDateTime();

Dấu thời gian mới (ts) .toLocalDateTime (). toLocalDate ()
Stepan Yakovenko

5
Ý tôi là - nếu bạn không phiền khi nhập javal.sql.Timestamp, với bản chất nguyên khối của Java, tôi cho là ổn vì nó chỉ là một phần của JVM ... nhưng tôi cảm thấy hơi khó chịu, nhưng tôi vẫn thích nó hơn kỷ nguyên được công nhận là về cơ bản trong UTC.
PlexQ

1
Các Timestamplớp học là thiết kế kém và lâu lỗi thời. Mã của bạn sẽ sử dụng cài đặt múi giờ của JVM, nhưng vì cài đặt này có thể được thay đổi bởi một phần khác trong chương trình của bạn hoặc một chương trình khác đang chạy trong cùng một JVM, chúng tôi không thể chắc chắn đó là gì.
Ole VV

1
Luôn luôn tốt hơn để rõ ràng về múi giờ được sử dụng. Việc sử dụng java.sql.Timestamp cũ có nhược điểm là việc áp dụng múi giờ hệ thống ngầm, điều này thường gây ra sự nhầm lẫn giữa các nhà phát triển.
Ruslan

3

Các múi giờ và những thứ sang một bên, một sự thay thế rất đơn giản new Date(startDateLong)có thể làLocalDate.ofEpochDay(startDateLong / 86400000L)


6
Tôi nghĩ bạn ít nhất nên giải thích 86400000L là viết tắt của từ gì.
BAERUS

3
Tôi nghĩ rằng rất dễ để nhận ra rằng đó là số mili giây trong một ngày.
Michael Piefel

7
Đối với một số người, và tôi đoán rằng chỉ có điều đó mới có ý nghĩa, nhưng không tính toán lại bao nhiêu ms một ngày thực sự có, tôi sẽ không chắc chắn. Chỉ nói cho bản thân tôi, tôi không biết con số này tốt đến mức tôi tự động biết nó đại diện cho cái gì.
BAERUS

Cũng lưu ý rằng câu trả lời được chấp nhận thực sự là câu trả lời tốt nhất, nó chỉ có vẻ quá sức. Hack đơn giản của tôi chỉ là của tôi là đủ trong nhiều trường hợp. Thật đáng tiếc java.timekhông bao gồm DateTimeConstantsnhư Joda đã làm.
Michael Piefel

2
java.util.concurrent.TimeUnit.MILLISECONDS.toDays(startDateLong)
Vadzim

1

thay thế now.getTime () bằng giá trị dài của bạn.

//GET UTC time for current date
        Date now= new Date();
        //LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
        LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
        DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));

-6

Trong một trường hợp cụ thể trong đó dấu thời gian epoch giây của bạn đến từ SQL hoặc bằng cách nào đó có liên quan đến SQL, bạn có thể có được nó như thế này:

long startDateLong = <...>

LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();

2
Điều này thực sự không liên quan nhiều đến câu hỏi được hỏi
Ketan R

@KetanR, tôi không đồng ý. Câu hỏi là "làm thế nào để có được LocalDatetừ epoch-millis" và tôi chỉ ra cách sử dụng java.sql.Datecho tốc ký. Cách tiếp cận này có ý nghĩa trong mã đã xử lý JDBC ở một số khả năng và nó hoạt động tốt. Nếu bạn vẫn không bị thuyết phục, hãy giải thích nó không liên quan đến câu hỏi ban đầu.
M. Prokhorov

2
Nếu bạn đọc câu hỏi, nó cho biết "API bên ngoài trả về ngày của tôi là dài" và bạn đang giải thích cách chuyển đổi này có thể được thực hiện nếu bạn nhận được ngày dài từ SQL. Câu trả lời của bạn không giải thích một trường hợp rất cụ thể về chuyển đổi ngày nhưng nó không thực sự phù hợp với câu hỏi đã được hỏi ed. Giải thích của bạn có thể là một câu trả lời hợp lệ cho một số câu hỏi liên quan khác.
Ketan R

@KetanR, nếu một người nhận được ngày dài từ SQL, tôi khuyên bạn nên thay đổi lược đồ của mình để anh ta không còn nhận được ngày ở dạng như vậy nữa. Tuy nhiên, nếu một người nhận được ngày dưới dạng dấu thời gian từ các nơi khác (API bên ngoài) và ngay lập tức sử dụng các ngày này để thực hiện các truy vấn JDBC, thì java.sql.Datecách tiếp cận là một trong những cách ngắn nhất có sẵn, thông thái về mã và tôi nói rằng nó không hữu ích lắm để đi mặc dù Instantvới tất cả các đối tượng thời gian trung gian khi kết quả cuối cùng là như nhau.
M. Prokhorov

2
Như tôi đã nói và hiển nhiên từ lời giải thích mới nhất của bạn, câu trả lời của bạn là đúng nhưng không phải là câu hỏi trong tay Câu hỏi cho biết: "Tôi quan tâm đến việc chuyển đổi điểm theo thời gian được biểu thị bằng LocalDate trong múi giờ địa phương hiện tại của tôi. "Câu trả lời của bạn cho biết:" nhận ngày dưới dạng dấu thời gian, và ngay lập tức sử dụng những ngày này để thực hiện truy vấn JDBC ". Tôi không hiểu những gì không rõ ràng ở đây?
Ketan R
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.