Cách nhận mili giây từ LocalDateTime trong Java 8


285

Tôi tự hỏi nếu có một cách để có được mili giây hiện tại kể từ 1970/01/01 (thời đại) bằng cách sử dụng mới LocalDate, LocalTimehoặc LocalDateTimecác lớp của Java 8.

Cách được biết là dưới đây:

long currentMilliseconds = new Date().getTime();

hoặc là

long currentMilliseconds = System.currentTimeMillis();

6
Có chuyện gì với bạn System.currentTimeMillis()vậy?
Dawood ibn Kareem

16
@DavidWallace Anh ấy đang cố gắng để có được thời gian của một Ngày, không phải là thời gian hiện tại?
Anubian Noob

2
"... một cách để có được mili giây hiện tại ..."
Dawood ibn Kareem

mili giây tính từ 1-1-1970. Tôi đã đi lang thang nếu có một phương pháp để có được chúng bằng cách sử dụng các lớp mới của Java 8 LocalDate, LocalTime và LocalDateTime, vì tôi đã không tìm thấy.
George Siggouroglou

1
Sự hiểu biết của tôi về mục đích cho các lớp đó là nó là sự hiểu biết "tập trung vào con người" về thời gian, và currentTimeMillissẽ không liên quan trong bối cảnh đó. Hãy suy nghĩ Lịch + Đồng hồ treo tường với độ chính xác thực sự tốt và không phải lo lắng về múi giờ và địa phương. Vì vậy, không có cách nào để quay lại "Thời gian UTC" từ LocalTime
Gus

Câu trả lời:


325

Tôi không hoàn toàn chắc chắn ý của bạn về "mili giây hiện tại" nhưng tôi sẽ cho rằng đó là số mili giây kể từ "kỷ nguyên", cụ thể là nửa đêm, ngày 1 tháng 1 năm 1970 UTC.

Nếu bạn muốn tìm số mili giây kể từ kỷ nguyên ngay bây giờ, thì hãy sử dụng System.currentTimeMillis()như Anubian Noob đã chỉ ra . Nếu vậy, không có lý do gì để sử dụng bất kỳ API java.time mới nào để làm điều này.

Tuy nhiên, có thể bạn đã có một LocalDateTimehoặc đối tượng tương tự từ một nơi nào đó và bạn muốn chuyển đổi nó thành mili giây kể từ thời đại. Không thể thực hiện điều đó một cách trực tiếp, vì LocalDateTimegia đình của các đối tượng không có khái niệm về múi giờ họ đang ở. Do đó, thông tin múi giờ cần được cung cấp để tìm thời gian liên quan đến kỷ nguyên, trong UTC.

Giả sử bạn có một cái LocalDateTimenhư thế này:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

Bạn cần áp dụng thông tin múi giờ, đưa ra a ZonedDateTime. Tôi ở cùng múi giờ với Los Angeles, vì vậy tôi sẽ làm một cái gì đó như thế này:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Tất nhiên, điều này làm cho các giả định về múi giờ. Và có những trường hợp cạnh có thể xảy ra, ví dụ, nếu giờ địa phương xảy ra để đặt tên thời gian gần thời gian chuyển đổi Ánh sáng ban ngày (Giờ mùa hè). Hãy đặt chúng sang một bên, nhưng bạn nên biết rằng những trường hợp này tồn tại.

Dù sao, nếu bạn có thể có được một giá trị ZonedDateTime, bạn có thể chuyển đổi số này thành số mili giây kể từ thời đại, như vậy:

long millis = zdt.toInstant().toEpochMilli();

5
Lưu ý rằng ZonedDateTime đã các getEpochSecondphương pháp (thông qua ChronoZonedDateTime mặc định ). Không cần cho Instant.
mabi

13
Chắc chắn, nếu tất cả những gì bạn cần là giây, không phải mili giây.
Stuart Marks

18
Tránh các phép toán trên nanos bằng cách sử dụng zdt.get (ChronoField.MILLI_OF_SECOND). Tránh tất cả các phép toán bằng cách sử dụng zdt.toInstant () .EpochMilli ()
JodaStephen

2
Lưu ý rằng zdt.toInstant().toEpochMilli();sẽ cung cấp cho bạn mili giây cho giá trị UTC tương ứng , không phải cho thời gian ngày được khoanh vùng của bạn. Tôi thấy điều này một cách khó khăn. toInstant()cung cấp cho bạn một UTC ngay lập tức. Nếu bạn muốn giờ địa phương tính bằng mili, điều này sẽ không cung cấp cho bạn những gì bạn mong đợi . Vì vậy, nếu bạn đang sử dụng thời gian được khoanh vùng +02: 00, thời gian trả về của bạn sẽ ít hơn 3600 * 2 * 1000 mili giây so với những gì bạn mong đợi.
Per Lundberg

2
@PerLundberg Tôi chỉ so ZonedDateTime.now().toInstant().toEpochMilli(), LocalDateTime.now().toInstant(OffsetDateTime.now().getOffset()).toEpochMilli(), LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), Calendar.getInstance().getTime().getTime(), new Date().getTime()System.currentTimeMillis(). Phương pháp duy nhất có vẻ "tắt" là phương pháp bạn đề xuất: LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()cung cấp cho bạn millis cho ngày địa phương của bạn như thể đó là một ngày UTC , tức là nếu ngày địa phương là UTC + 2 thì phương pháp của bạn sẽ cung cấp cho millis trong 2 giờ trong tương lai .
walen

81

Những gì tôi làm vì vậy tôi không chỉ định múi giờ là,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

cho

ldt 1424812121078 
ctm 1424812121281

Như bạn có thể thấy các con số là như nhau ngoại trừ thời gian thực hiện nhỏ.

Chỉ trong trường hợp bạn không thích System.cienTimeMillis, hãy sử dụng Instant.now().toEpochMilli()


3
Không, Epoch có liên quan đến UTC nhưng bạn có được thời gian hiện tại từ khu vực địa phương của bạn.
Rafael Membrive

2
@ Christoffer Hammarström số lượng mili giây đã trôi qua kể từ thời đại này là một thực tế độc lập với múi giờ. Đó là cùng một phần nghìn giây, bất kể thời gian nào trong ngày bạn gọi nó. Hai kết quả khác nhau vì máy của brian mất 203 mili giây để thực hiện lệnh thứ hai.
Fletch

Sử dụng UTC có ổn không khi người dùng có thể ở múi giờ khác
GilbertS

2
@GilbertS có lẽ bạn không bao giờ nên sử dụng mã chính xác này, hãy sử dụng API như dự định. Ngày giờ phải luôn là UTC khi được lưu trữ trên máy tính hoặc được truyền cho người dùng khác. Nó thường được trình bày cho người dùng dưới dạng thời gian ngày địa phương bằng cách sử dụng cài đặt múi giờ của riêng họ.
brian

20

Để tránh ZoneId bạn có thể làm:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

Lấy 0 làm giá trị, điều đó đúng!


8
ZoneOffset.ofTotalSeconds(0)nó giống nhưZoneOffset.UTC
Anton Novopashin

1
Vâng, đó là tôi nâng cao nhận xét @ AntonNovopashin. Vì bạn cần UTC, bạn vẫn ổn (bạn có thể muốn đề cập đến điều đó trong câu trả lời). BTW ZoneOffsetlà một lớp con của ZoneId, vì vậy tôi không nói chính xác là bạn đã tránh nó, nhưng miễn là bạn vui vẻ
Ole VV

Nhận xét đầu tiên của tôi là một chút khắc nghiệt, nhưng không có nghĩa là xúc phạm. Bạn đã phạm tội. Tôi xin lỗi. Tôi đã xóa nó. Cho phép tôi hỏi cách khác: lý do của chúng tôi muốn tránh là ZoneIdgì?
Ole VV

@ OleV.V Sử dụng UTC có ổn không. Không chỉ dành cho những người sống ở múi giờ UTC.
GilbertS

1
@GilbertS Tôi không nghĩ có ai sống theo múi giờ UTC. Sử dụng UTC cho thời gian được sử dụng trên các múi giờ được khuyến nghị là một cách thực hành tốt. Xem ví dụ Thực tiễn tốt nhất về Java cho Thao tác / lưu trữ ngày cho người dùng đa dạng về địa lý . Hoặc có lẽ tôi đã không hiểu câu hỏi của bạn?
Ole VV

15

Kể từ Java 8, bạn có thể gọi java.time.Instant.toEpochMilli().

Ví dụ như cuộc gọi

final long currentTimeJava8 = Instant.now().toEpochMilli();

cho bạn kết quả tương tự như

final long currentTimeJava1 = System.currentTimeMillis();

1
"Cho bạn kết quả tương tự như" ... nhưng tốn nhiều năng lượng CPU hơn và làm căng bộ thu gom rác nhiều hơn.
VasiliNovikov

Tôi muốn xem số lượng ở trên (đặc biệt là cho sử dụng bình thường - ví dụ: không phải cho một số ứng dụng thời gian thực quan trọng về hiệu suất ...)
Brian Agnew

11

Bạn cũng có thể sử dụng java.sql.Timestampđể có được mili giây.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

Bạn đang bỏ qua nhu cầu quan trọng cho một múi giờ. Tôi không khuyên bạn nên làm theo cách này. Ngoài ra, Timestamplớp đã lỗi thời và chứa đầy các vấn đề về thiết kế, vì vậy tôi muốn tránh nó, đặc biệt là khi chúng ta có thể sử dụng các lớp từ java.timethích LocalDateTime.
Ole VV

@ OleV.V. Chỉ tò mò về các vấn đề thiết kế của Timestamp, Bạn có thể chia sẻ một số bài viết về điều đó? Nó cũng giúp tôi tránh sử dụng Timestamptừ mã của mình. Cảm ơn!
Nalam

1
Nói ngắn gọn, nó được triển khai như một lớp con của Datenhưng thường không thể được xử lý như một Date. Hầu hết các phương thức được kế thừa từ Datevà một hàm tạo đều không được dùng nữa. toStringPhương thức của nó sử dụng múi giờ của JVM, khiến nhiều người nhầm lẫn vì cùng Timestampđược in khác nhau trên các máy tính khác nhau ( ví dụ ).
Ole VV

Điều này là hoàn hảo cho thử nghiệm đơn vị. Chỉ cần thay thế ngay bây giờ bằngLocalDate.of(year, month, day)
G_V

Đây phải là câu trả lời được chấp nhận để giải quyết các giá trị "luôn luôn UTC".
LeYAUable

9

Để có được thời gian hiện tại tính bằng mili giây (kể từ kỷ nguyên), hãy sử dụng System.currentTimeMillis().


3

Nếu bạn có Đồng hồ Java 8, thì bạn có thể sử dụng clock.millis()(mặc dù nó khuyên bạn nên sử dụng clock.instant()để nhận Java 8 Instant, vì nó chính xác hơn).

Tại sao bạn sẽ sử dụng đồng hồ Java 8? Vì vậy, trong khung DI của bạn, bạn có thể tạo một bean Clock:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

và sau đó trong các thử nghiệm của bạn, bạn có thể dễ dàng Mock nó:

@MockBean private Clock clock;

hoặc bạn có thể có một loại đậu khác:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

giúp kiểm tra xác nhận ngày và thời gian vô cùng.


1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}

0

Tại sao không ai đề cập đến phương pháp này LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

Điều này dường như ngắn hơn mà nhiều câu trả lời được đề xuất ở trên ...


đây là những gì tôi đang tìm kiếm Đó là câu trả lời được chấp nhận đã cho tôi các di chúc.
Brill Pappin

Chấp nhận nó chỉ có sẵn trong API 26: {
Brill Pappin

1
Bởi vì nó chỉ cho vài giây. Thật kỳ lạ khi không có toEpochMilliphương pháp, tính đến thực tế là bạn có thể chỉ định ngay cả nano giây trong LocalDateTime: có một phương pháp LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif
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.