2017-07-11 17 views
6

Tôi muốn sử dụng giá trị thời gian MIN/MAX có thể chuyển đổi giữa ZonedDateTimeInstant.toEpochMilli(), để được sử dụng làm giá trị sentinel cho bộ lọc/truy vấn.Giá trị MIN/MAX nào sẽ hoạt động với cả ZonedDateTime và Instant.toEpochMilli?

tôi đã cố gắng:

OffsetDateTime.MIN.toInstant().toEpochMilli(); 
OffsetDateTime.MAX.toInstant().toEpochMilli(); 

nhưng tôi nhận được ngoại lệ này:

java.lang.ArithmeticException: long overflow 

    at java.lang.Math.multiplyExact(Math.java:892) 
    at java.time.Instant.toEpochMilli(Instant.java:1237) 

Và sau đó tôi đã cố gắng này:

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.systemDefault()); 
ZonedDateTime.ofInstant(Instant.MAX, ZoneId.systemDefault()); 

nhưng sau đó tôi nhận được ngoại lệ này:

java.time.DateTimeException: Invalid value for Year (valid values -999999999 - 999999999): -1000000001 

    at java.time.temporal.ValueRange.checkValidIntValue(ValueRange.java:330) 
    at java.time.temporal.ChronoField.checkValidIntValue(ChronoField.java:722) 
    at java.time.LocalDate.ofEpochDay(LocalDate.java:341) 
    at java.time.LocalDateTime.ofEpochSecond(LocalDateTime.java:422) 
    at java.time.ZonedDateTime.create(ZonedDateTime.java:456) 
    at java.time.ZonedDateTime.ofInstant(ZonedDateTime.java:409) 

Tôi cũng đã cố gắng 'Z' ZoneId:

ZonedDateTime.ofInstant(Instant.MIN, ZoneId.of("Z")) 

nhưng đó trả về ngoại lệ tương tự như người cuối cùng.

Cuối cùng tôi đã cố gắng điều sau đây, và có vẻ như để làm việc:

ZonedDateTime.ofInstant(Instant.EPOCH, ZoneId.of("Z")); 
ZonedDateTime.ofInstant(Instant.EPOCH.plusMillis(Long.MAX_VALUE), ZoneId.of("Z")); 

Đó có phải là giải pháp tốt nhất?

Trả lời

6

Instant.EPOCH tương đương 1970-01-01T00:00Z, vì vậy tôi không chắc đó có phải là ứng cử viên tốt cho giá trị tối thiểu hay không (tùy thuộc vào nhu cầu của bạn, tất nhiên - nếu tất cả các ngày của bạn sau năm 1970 thì sẽ ổn).

Chuyển đổi Instant.MINInstant.MAX thành ZonedDateTime không hoạt động mọi lúc vì tùy thuộc vào khoảng trống, trường có thể được đặt thành giá trị vượt ra ngoài ranh giới (như đã xảy ra với năm).

Nếu bạn muốn ngày xa có thể được chuyển đổi thành ZonedDateTimeInstant, bạn không cần sử dụng hằng số MIN/MAX tích hợp, vì chúng sử dụng ngày rất xa (từ năm như -1000000000 đến 1000000000) và các giá trị tương đương epoch milli cho những ngày xa như vậy lớn hơn nhiều (hoặc thấp hơn) so với giới hạn của giá trị long.

Như bạn cần phải sử dụng toEpochMilli() và nó trả về một long, bạn phải ở lại giữa các giới hạn của một giá trị long:

Instant minInstant = Instant.ofEpochMilli(Long.MIN_VALUE); 
Instant maxInstant = Instant.ofEpochMilli(Long.MAX_VALUE); 
ZonedDateTime minZonedDateTime = minInstant.atZone(ZoneOffset.UTC); 
ZonedDateTime maxZonedDateTime = maxInstant.atZone(ZoneOffset.UTC); 

Các giá trị tương ứng là:

minInstant = -292275055- 05-16T16: 47: 04.192Z
maxInstant = + 292278994-08-17T07: 12: 55.807Z
minZonedDateTime = -292275055-05-16T16: 47: 04.192Z
maxZonedDateTime = + 292278994-08-17T07: 12: 55.807Z

Và các giá trị tương ứng cho milli thời đại:

System.out.println("minInstant millis=" + minInstant.toEpochMilli()); 
System.out.println("maxInstant millis=" + maxInstant.toEpochMilli()); 

minInstant millis = -9223372036854775808
maxInstant millis = 9223372036854775807

tôi đã sử dụng ZoneOffset.UTC thay vì một số múi giờ cụ thể, bởi vì những ngày đó cho đến nay trong quá khứ/tương lai, rằng một vài giờ bù đắp sẽ không tạo ra nhiều sự khác biệt. Và tất cả họ sẽ tương đương với cùng một millis ngay lập tức anyway.

Bạn cũng có thể chuyển đổi Instant thành OffsetDateTime bằng phương pháp atOffset (chẳng hạn như minInstant.atOffset(ZoneOffset.UTC)).


Ghi chú:

  • thay vì ZoneId.of("Z"), bạn có thể sử dụng hằng ZoneOffset.UTC. Trên thực tế, nếu bạn kiểm tra ZoneId.of("Z").equals(ZoneOffset.UTC), kết quả là true.
    Thậm chí ZoneId.of("Z") == ZoneOffset.UTC cũng là true, vì vậy cả hai đều thực sự giống nhau.
  • tùy thuộc vào giá trị truy vấn của bạn, bạn không cần phải sử dụng những ngày cực đoan như vậy. Bạn có thể đặt tối thiểu năm 1900 và tối đa là 2900 chẳng hạn. Tất cả phụ thuộc vào tập dữ liệu của bạn. Nhưng việc sử dụng cách tiếp cận ở trên sẽ ổn, nếu cơ sở dữ liệu của bạn có thể xử lý các giá trị lớn như vậy trong năm.
+1

cũng đáng chú ý về phạm vi ngày của bạn. Tất cả các trường hợp được coi là điều này có thể có nghĩa là trước năm 1970 hoặc sau khi tràn của epoch (tôi đã có một trường hợp với phạm vi ngày 100+ năm, bạn không thể sử dụng một kỷ nguyên ms cho điều đó) – Rogue

+1

Thanks @Hugo. Đơn giản và rực rỡ. Bây giờ hoàn toàn có ý nghĩa để sử dụng Long.MIN_VALUE/MAX_VALUE. – jacob

+0

Bạn được chào đón, vui lòng giúp đỡ! Thật vậy, việc sử dụng các giá trị Long min và max mang lại cho bạn một phạm vi tốt (hơn 200 triệu năm, đủ cho hầu hết các trường hợp, tôi giả sử). –

Các vấn đề liên quan