Làm thế nào để lấy ZoneOffset mặc định trong java8?


80

Với java8 chúng ta biết sử dụng ZoneId.default()có thể lấy mặc định hệ thống ZoneId, nhưng làm thế nào để lấy mặc định ZoneOffset?

Tôi thấy rằng a ZoneIdcó một số "quy tắc" và mỗi quy tắc có một ZoneOffset, điều đó có nghĩa là a ZoneIdcó thể có nhiều hơn một ZoneOffset?


thửZoneOffset.systemDefault()
Shubham Chaurasia

2
Nhiều múi giờ có hiệu số khác nhau do thời gian tiết kiệm ánh sáng ban ngày.
Marc Philipp

15
ZoneOffset.systemDefault()trả về a ZoneId, mặc dù.
Marc Philipp

3
ZoneOffset hiện tại là một chức năng của ZoneId và Instant. ZoneOffset current = zone.getRules().getOffset(instant)
Alexander Yanyshin

3
@FredSuvn Tôi tin rằng yanys đang có khái niệm rằng việc yêu cầu bù trừ mà không chỉ định múi giờ và thời điểm (giá trị ngày-giờ) là vô nghĩa. Ví dụ: Thời gian tiết kiệm ánh sáng ban ngày trong America/Los_Angelesnguyên nhân là -08:00hiện tại, nhưng thay đổi thành -07:00vào mùa hè. Vì vậy, bạn không thể yêu cầu bù trừ mà không nói khi nào có hiệu lựcmúi giờ nào . Xem Câu trả lời của tôi để thảo luận thêm.
Basil Bourque

Câu trả lời:


186

tl; dr

OffsetDateTime.now().getOffset()

Nhưng bạn có thể nên sử dụng múi giờ thay vì chỉ chênh lệch từ UTC.

ZoneId.systemDefault() 

Chênh lệch so với Múi giờ

Phần bù từ UTC chỉ đơn thuần là một số giờ, phút và giây - không có gì hơn. Ví dụ: -08:00có nghĩa là chậm hơn UTC tám giờ và +05:45có nghĩa là trước UTC năm giờ bốn mươi lăm phút .

Một múi giờ là một lịch sử của quá khứ, hiện tại, và những thay đổi trong tương lai để bù đắp được sử dụng bởi những người của một khu vực cụ thể. Các hiện tượng bất thường như Giờ tiết kiệm ánh sáng ban ngày (DST) gây ra sự thay đổi trong khoảng thời gian cụ thể được theo dõi theo thời gian, trong quá khứ khi chúng xảy ra và trong tương lai khi các chính trị gia công bố các thay đổi theo kế hoạch.

Vì vậy, tốt hơn là sử dụng một khu vực khi được biết đến.

Phần bù cho bất kỳ vùng nào cũng thay đổi theo thời gian. Ví dụ: DST ở Hoa Kỳ thay đổi mức bù một giờ trong khoảng nửa năm và sau đó khôi phục giờ đó trở lại mức bù trong nửa năm còn lại. Toàn bộ mục đích của múi giờ là để ghi lại những thay đổi đó theo hướng bù đắp.

Vì vậy, thực sự không có ý nghĩa gì khi yêu cầu bù trừ mà không có ngày-giờ . Trong America/Los_Angeles, ví dụ như trong một phần của năm nay bù đắp là -08:00nhưng trong một phần khác của năm đó là -07:00trong DST.

OffsetDateTime

Vì vậy, hãy xác định một khoảnh khắc như một OffsetDateTime, và sau đó giải nén ZoneOffset.

OffsetDateTime odt = OffsetDateTime.now ();
ZoneOffset zoneOffset = odt.getOffset ();

odt.toString (): 2017-01-02T15: 19: 47.162-08: 00

zoneOffset.toString (): -08: 00

nowPhương pháp đó thực sự đang áp dụng ngầm múi giờ mặc định hiện tại của JVM. Tôi khuyên bạn nên luôn làm rõ điều đó bằng cách chỉ định múi giờ mong muốn / dự kiến ​​của bạn. Ngay cả khi bạn muốn vùng mặc định hiện tại, hãy nói rõ ràng như vậy để làm rõ ý định của bạn. Loại bỏ sự mơ hồ về việc bạn dự định mặc định hay không xem xét múi giờ như thường xảy ra với các lập trình viên. Gọi điện thoại ZoneId.systemDefault.

OffsetDateTime odt = OffsetDateTime.now ( ZoneId.systemDefault () );
ZoneOffset zoneOffset = odt.getOffset ();

ZoneId.systemDefault (). ToString (): America / Los_Angeles

odt: 2017-01-02T15: 19: 47.162-08: 00

zoneOffsetOfOdt: -08: 00

Lưu ý về việc tùy thuộc vào vùng mặc định: Mặc định này có thể được thay đổi bất kỳ lúc nào bằng bất kỳ mã nào trong bất kỳ chuỗi nào trong JVM. Nếu quan trọng, hãy hỏi người dùng về múi giờ dự định của họ.

Bạn có thể yêu cầu phần bù cho lượng thời gian của nó dưới dạng tổng số giây.

int offsetSeconds = zoneOffset.getTotalSeconds ();

offsetSeconds: -28800

ZonedDateTime

Một ví dụ khác: Có lẽ bạn muốn biết mức bù đắp vào Ngày Giáng sinh năm nay ở Québec. Chỉ định múi giờ America/Montreal, lấy a ZonedDateTime, yêu cầu độ lệch của nó như một ZoneOffsetđối tượng.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2017 , 12 , 25 );
ZonedDateTime zdtXmas = ld.atStartOfDay( z );
ZoneOffset zoneOffsetXmas = zdtXmas.getOffset();

zdtXmas.toString (): 2017-12-25T00: 00-05: 00 [Mỹ / Montreal]

zoneOffsetXmas.toString (): -05: 00

zoneOffsetXmas.getTotalSeconds (): -18000

Bảng các kiểu ngày-giờ trong Java, cả hiện đại và kế thừa.

ZoneId

Như được đề xuất trong nhận xét của yanys, bạn có thể thẩm vấn a ZoneIdcho một cụ thể ZoneOffsetbằng cách chuyển một thời điểm dưới dạng một Instant. Các Instantlớp đại diện cho một thời điểm trên Timeline trong UTC với độ phân giải nano giây (lên đến chín (9) chữ số của một phân số thập phân).

Đây chỉ là một tuyến đường khác đến cùng một điểm đến. Cũng giống như với OffsetDateTimeZonedDateTimethảo luận ở trên, chúng tôi đang chỉ định (a) múi giờ và (b) một thời điểm.

Instant instant = zdtXmas.toInstant();
ZoneOffset zo = z.getRules().getOffset( instant );

Đối với ZoneId: America / Montreal vào thời điểm tức thì: 2017-12-25T05: 00: 00Z ZoneOffset là: -05: 00

Xem tất cả của các ví dụ này trực tiếp tại IdeOne.com .

ZoneOffset.systemDefault - Lỗi hoặc tính năng?

Các ZoneOffsetlớp, một lớp con của ZoneId, là tài liệu như kế thừa các systemDefaultphương pháp. Tuy nhiên, điều này không thực sự hoạt động.

ZoneOffset zoneOffset = ZoneOffset.systemDefault() ;  // Fails to compile.

lỗi: các loại không tương thích: Không thể chuyển đổi ZoneId thành ZoneOffset

Không chắc liệu lỗi biên dịch này là lỗi hay một tính năng. Như đã thảo luận ở trên, dường như tôi không bao giờ yêu cầu bù đắp mặc định với ngày-giờ, vì vậy có lẽ ZoneOffset.systemDefaultthực tế sẽ không thành công. Nhưng tài liệu sẽ nói như vậy, kèm theo lời giải thích.

Tôi đã cố gắng gửi một lỗi về lỗi tài liệu không giải quyết được vấn đề này, nhưng đã bỏ cuộc, không thể xác định vị trí và cách gửi một báo cáo lỗi như vậy.

Giờ mặt trời so với giờ chính trị

Thông tin thêm về hiệu số và múi giờ…

Thời gian Mặt trời đã được sử dụng từ trước lịch sử, theo dõi mỗi ngày bằng cách ghi lại thời điểm mặt trời ở trên cao. Chọc một cây gậy xuống đất, và quan sát bóng của nó. Khi bóng tối ngắn nhất, khi bóng bắt đầu lớn hơn chứ không phải nhỏ lại, thì bạn biết bây giờ là buổi trưa. Chính thức hóa điều đó bằng đồng hồ mặt trời để theo dõi thời gian trôi qua.

Với thời gian mặt trời, khi bạn đi từ thị trấn này sang thị trấn khác di chuyển về phía tây, buổi trưa sẽ đến muộn hơn một chút. Di chuyển về phía đông, buổi trưa đến sớm hơn một chút. Vì vậy, mỗi thị trấn đều có buổi trưa riêng, chỉ dùng chung với các thị trấn ở phía bắc và nam dọc theo cùng một kinh độ.

Thời gian mặt trời phần lớn đã bị bỏ rơi trong kỷ nguyên hiện đại. Khi xe lửa, điện tín và điện thoại đến, nhu cầu phối hợp tạm thời cũng vậy. Vì vậy, một điểm được chọn cho thời gian mặt trời gần của buổi trưa, và một vùng đất rộng lớn rất nhiều dặm về phía tây và phía đông được công bố cho tất cả các cổ phiếu cùng 12:00 vào đồng hồ, cùng một số giờ bù đắp trước hay đằng sau Greenwich Meridian Thủ dòng . Vì vậy, bắt đầu truyền thống mỗi trạm dừng xe lửa hiển thị nổi bật một chiếc đồng hồ để cho thị trấn biết về thời gian tiêu chuẩn cho khu vực lớn hơn của họ thay vì giờ mặt trời cho thị trấn của họ. Nói chung, các thị trấn ở rìa phía tây của khu vực múi giờ đó sẽ thấy đồng hồ ga tàu của họ chỉ trước 12:00 một chútmặt trời ở trên cao. Đồng hồ ở các thị trấn ở rìa phía đông của khu vực chỉ điểm 12 giờ trưa sau khi mặt trời ló dạng.

Các chính trị gia trên khắp thế giới cho thấy xu hướng thay đổi (các) phần bù của quyền tài phán của họ. Các lý do khác nhau, chẳng hạn như ngoại giao, chiến tranh và chiếm đóng, và sự im lặng của Giờ tiết kiệm ánh sáng ban ngày (DST) . Các lý do khác nhau, nhưng những thay đổi của chúng đi kèm với tần suất đáng ngạc nhiên. Múi giờ là tên được đặt cho một khu vực để theo dõi lịch sử của những thay đổi đó. Vì vậy, một offset-from-UTC chỉ đơn thuần là một số giờ-phút-giây trước hoặc sau kinh tuyến gốc. Một múi giờ là nhiều hơn nữa: một lịch sử của quá khứ, hiện tại, và những thay đổi trong tương lai để offsets của một khu vực cụ thể. Mặc dù hai khu vực lân cận ngày nay có thể chia sẻ cùng một khoảng chênh lệch so với UTC, trong quá khứ hoặc tương lai chúng có thể khác nhau tùy thuộc vào ý tưởng bất chợt hoặc logic khác nhau của các chính trị gia của họ.

Điều này có nghĩa là việc theo dõi thời gian hiện đại do các chính trị gia xác định hầu như không liên quan đến địa lý. Ví dụ: đất nước Ấn Độ khổng lồ ngày nay có một múi giờ duy nhất (offset-from-UTC là +05: 30). Vì vậy, buổi trưa mặt trời (mặt trời chiếu thẳng qua đầu bạn) cách nhau hàng giờ ở nhiều nơi khác nhau trên khắp tiểu lục địa rộng lớn. Các chính trị gia của Ấn Độ quyết định điều này để giúp thống nhất nền dân chủ đa dạng của họ. Trong các ví dụ khác trên thế giới, chúng ta thấy các khu vực sử dụng múi giờ của họ làm biểu tượng cho quan hệ quốc tế, chẳng hạn như khác với quốc gia láng giềng đang xúc phạm hoặc chọn cùng múi giờ với nước láng giềng khi quan hệ tan băng như đã thấy gần đây ở Triều Tiên thay đổi để phù hợp Nam Triều Tiên. Vì vậy, ngày nay, thời gian mặt trời chỉ là một trong số những điều cần cân nhắc trong việc theo dõi thời gian.


Giới thiệu về java.time

Các java.time khung được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp ngày-giờ kế thừa cũ rắc rối như java.util.Date,Calendar , & SimpleDateFormat.

Để tìm hiểu thêm, hãy xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow để có nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của mình. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần dây, không cầnjava.sql.* lớp. Hibernate 5 & JPA 2.2 hỗ trợ java.time .

Lấy các lớp java.time ở đâu?

Bảng sử dụng thư viện java.time với phiên bản Java hoặc Android nào


ý bạn là giá trị bù đắp khác nhau tại các thời điểm khác nhau trong một vùng? cảm ơn nhiều!
FredSuvn

1
@FredSuvn Đó chính là định nghĩa của Giờ tiết kiệm ánh sáng ban ngày (DST), nửa năm bù trừ nửa năm. Và DST không phải là nguyên nhân duy nhất; các dị thường khác gây ra các thay đổi về độ lệch cho các múi giờ cụ thể. Ví dụ: vào mùa thu năm 2016, Thổ Nhĩ Kỳ đã quyết định điều chỉnh vĩnh viễn mức bù của họ thêm một giờ trước giờ UTC ( +03:00). Các chính trị gia thường xuyên thực hiện những thay đổi như vậy, thường ít được chú ý. Điều đó khiến mọi người tranh nhau cập nhật danh sách cơ sở dữ liệu 'tzdata' của máy tính của họ về các định nghĩa vùng.
Basil Bourque

1
Câu trả lời tốt nhất mà tôi đã nhìn thấy trên SO trong một thời gian khá 😀 @FredSuvn bạn nên chấp nhận câu trả lời bằng cách nhấn vào ✅
earcam

Đối với bất kỳ ai khác đang bối rối bởi phương trình Múi giờ = (Lịch sử của sự khác biệt + Quy tắc cho sự bất thường) . Điều này không có nghĩa là khi sử dụng zone.getRules().getOffset(instant), bạn cần thêm bất kỳ dị thường bổ sung nào vào phần bù thu được theo cách thủ công, chẳng hạn như DST. Bù đắp được trả về bởi getOffset(instant)đã là con số chính xác của giờ, phút và giây bù đắp từ giờ ở đó ngay lập tức trong thời gian. (Tôi luôn luôn nghĩ rằng bù đắp chỉ là địa lý bù đắp trong đó mô tả / sau mặt trời mọc như thế nào sớm hơn nhiều trong khu vực đó, nhưng nó thực sự xem xét tất cả các quy tắc.)
anddero

@anddero Nhận xét của bạn đã truyền cảm hứng cho tôi xóa phương trình đó và thêm một phần về thời gian mặt trời so với thời gian chính trị. Hy vọng rằng đọc rõ ràng hơn bây giờ.
Basil Bourque

0

Tùy thuộc vào mục tiêu của bạn, bạn có thể bỏ qua ZoneOffsethoàn toàn .

Giả sử bạn chỉ cần một ZoneOffsetví dụ LocalDateTime.ofEpochSecond(), bạn có thể thay thế

ZoneOffset offset = OffsetDateTime.now().getOffset();
LocalDateTime dt1 = LocalDateTime.ofEpochSecond(seconds, 0, offset);

với

LocalDateTime dt2 = LocalDateTime.ofInstant(
    Instant.ofEpochSecond(seconds), 
    ZoneId.systemDefault());

nơi dt1.equals(dt2)true.

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.