Có cách nào để chuyển đổi ZoneId thành ZoneOffset trong java 8 không?


85

Tôi có một kỷ nguyên giây và một zoneId, theo method1, nó có thể được chuyển đổi thành LocalDateTime với zoneId mặc định của hệ thống, nhưng tôi không tìm thấy cách chuyển đổi kỷ nguyên thứ hai thành LocalDateTime bằng method2, vì không có. ZoneOffset.systemDefaultTôi nghĩ nó khó hiểu.

import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}

val epochSecond = System.currentTimeMillis() / 1000

LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())//method1
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)//method2

Bạn đang sử dụng ngôn ngữ / phương ngữ nào để nhập hàng loạt import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}hoạt động? Đó là unexpected tokenđối với tôi trong Java 11.
anddero

1
Có thể là Scala, nhưng điều đó không thực sự quan trọng ở đây
donatas M

1
Tôi đã thảo luận về lý thuyết đằng sau rất lâu java.timetại đây: stackoverflow.com/a/56508200/145989
Ondra Žižka

Câu trả lời:


109

Đây là cách bạn có thể nhận được ZoneOffsettừ ZoneId:

Instant instant = Instant.now(); //can be LocalDateTime
ZoneId systemZone = ZoneId.systemDefault(); // my timezone
ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);

NB: ZoneIdcó thể có mức bù khác nhau tùy thuộc vào thời điểm và lịch sử của địa điểm cụ thể. Vì vậy, việc chọn các Phiên bản khác nhau sẽ dẫn đến hiệu số khác nhau.

NB2: ZoneId.of()có thể trả về một ZoneOffsetthay vì ZoneIdnếu UTC+3/ GMT+2/ etc được chuyển qua trái ngược với múi giờ như Africa/Cairo. Vì vậy, nếu các hiệu số UTC / GMT được thông qua thì thông tin lịch sử / địa lý / tiết kiệm ánh sáng ban ngày của Instantchúng sẽ không được tính đến - bạn chỉ cần làm việc với độ lệch được chỉ định.


Điều này cung cấp giá trị không chính xác nếu thời điểm hiện tại là DST, nhưng tại thời điểm tính toán, nó không có DST
msangel

@msangel, bạn có thể kiểm tra lại được không? Có thể bạn đang sử dụng ZoneId.systemDefault()mã của mình và nó trả về các múi giờ khác nhau trên các máy khác nhau?
Stanislav Bashkyrtsev

Tôi đã kiểm tra điều đó và nó hoạt động tùy thuộc vào điều kiện khác. Cập nhật câu trả lời với điều đó.
msangel

43

Không có ánh xạ 1-1. ZoneId xác định một phạm vi địa lý trong đó một tập hợp các ZoneOffset khác nhau được sử dụng theo thời gian. Nếu múi giờ sử dụng thời gian tiết kiệm ánh sáng ban ngày, ZoneOffset của nó sẽ khác nhau giữa mùa hè và mùa đông.

Hơn nữa, các quy tắc về thời gian tiết kiệm ánh sáng ban ngày có thể đã thay đổi theo thời gian, vì vậy ZoneOffset có thể khác, ví dụ: 13/10/2015 so với 13/10/1980.

Vì vậy, bạn chỉ có thể tìm thấy ZoneOffset cho một ZoneId trên một Instant cụ thể.

Xem thêm https://en.wikipedia.org/wiki/Tz_database


10
Tôi biết điều đó, nhưng nó được thực hiện như thế nào? Nếu tôi biết LocaDate và có ZoneId, làm cách nào để chuyển đổi nó thành ZoneOffset. Ca sử dụng của tôi là một chuỗi chứa thời gian và múi giờ. Tôi muốn phân tích cú pháp chuỗi thành một OffsetTime mà không làm giảm thông tin vùng.
Kai Moritz

33

tl; dr

ZonedDateTime.now( 
    ZoneId.of( "America/Montreal" ) 
)

… Của múi giờ mặc định hiện tại…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Chi tiết

Câu trả lời của Stanislav Bshkyrtsev trả lời chính xác và trực tiếp Câu hỏi của bạn.

Tuy nhiên, có những vấn đề lớn hơn liên quan, như được đề xuất trong Câu trả lời của Jon Skeet .

LocalDateTime

Tôi không tìm thấy cách chuyển đổi epoch giây thành LocalDateTime

LocalDateTimecố tình không có khái niệm về múi giờ hoặc chênh lệch từ UTC. Không có khả năng những gì bạn muốn. Có Local…nghĩa là bất kỳ địa phương nào , không phải bất kỳ địa phương cụ thể nào. Lớp này không đại diện cho một khoảnh khắc, chỉ những khoảnh khắc tiềm năng trong khoảng 26-27 giờ (phạm vi của múi giờ trên toàn cầu).

Instant

Không cần bắt đầu bằng giây kỷ nguyên nếu bạn đang cố lấy thời gian hiện tại. Nhận hiện tại 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).

Instant instant = Instant.now();

Bên trong đó Instantlà số lượng nano giây -từ kỷ nguyên. Nhưng chúng tôi không thực sự quan tâm.

ZonedDateTime

Nếu bạn muốn xem khoảnh khắc đó qua lăng kính đồng hồ treo tường của một khu vực cụ thể, hãy áp dụng a ZoneIdđể lấy a ZonedDateTime.

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = instant.atZone( z );

Là một phím tắt, bạn có thể thực hiện trực tiếp với ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

A ZonedDateTimecó một Instantbên trong nó. Gọi zdt.toInstant()để nhận được đúng thời điểm giống như một giá trị cơ bản trong UTC . Cùng một số nano giây-kể từ kỷ nguyên theo cách nào đó, dưới dạng a ZonedDateTimehoặc a Instant.

Số giây kể từ kỷ nguyên đã cho

Nếu bạn được cung cấp số giây kể từ kỷ nguyên và kỷ nguyên là thời điểm đầu tiên của năm 1970 trong UTC ( 1970-01-01T00:00:00Z), thì hãy nạp số đó vào Instant.

long secondsSinceEpoch = 1_484_063_246L ;
Instant instant = Instant.ofEpochSecond( secondsSinceEpoch ) ;

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


Giới thiệu về java.time

Khung java.time được tích hợp sẵn trong Java 8 trở lên. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian 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 cho 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 chuỗi, không cần java.sql.*lớp.

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

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là cơ sở chứng minh cho những bổ sung có thể có trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval, YearWeek, YearQuarter, và nhiều hơn nữa .


10

Như tài liệu cho biết, "Điều này chủ yếu dành cho các chuyển đổi cấp thấp hơn là sử dụng ứng dụng chung".

Đi qua Instantcó ý nghĩa hoàn hảo đối với tôi - giây của bạn thực sự là một đại diện khác của một Instant, vì vậy hãy chuyển đổi thành một Instantvà sau đó chuyển đổi thành một múi giờ cụ thể.


9

Tôi hy vọng hai dòng đầu tiên của giải pháp của tôi dưới đây là hữu ích. Vấn đề của tôi là tôi có một LocalDateTimevà tên của một múi giờ, và tôi cần một múi giờ instantđể tôi có thể xây dựng một java.util.Date, bởi vì đó là những gì MongoDB muốn. Mã của tôi là Scala, nhưng nó rất gần với Java ở đây nên tôi nghĩ sẽ không có vấn đề gì khi hiểu nó:

val zid = ZoneId.of(tzName)                                // "America/Los_Angeles"
val zo: ZoneOffset = zid.getRules.getOffset(localDateTime) // ⇒ -07:00
                                         // 2017-03-16T18:03

val odt = OffsetDateTime.of(localDateTime, zo) // ⇒ 2017-03-16T18:03:00-07:00
val instant = odt.toInstant                    // ⇒ 2017-03-17T01:03:00Z
val issued = Date.from(instant)

1
Tôi đăng câu trả lời này ở đây vì đây là trang xuất hiện khi tôi đang tìm kiếm cách để thực hiện những gì cuối cùng tôi đã tìm ra.
gknauth

1

Phần sau trả về lượng thời gian tính bằng mili giây để thêm vào UTC để có được giờ chuẩn trong múi giờ này:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()

0

Tôi có một kỷ nguyên giây và một múi giờ. Có cách nào để chuyển đổi ZoneId thành ZoneOffset trong java 8 không?

  1. Nhận ZonedDateTimetừ kỷ nguyên giây và Id khu vực
  2. Nhận ZoneOffsettừZonedDateTime

Bản giới thiệu:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Get ZonedDateTime from epoch second and Zone Id
        ZonedDateTime zdt = Instant.ofEpochSecond(1597615462L).atZone(ZoneId.of("Europe/London"));

        // Get ZoneOffset from ZonedDateTime
        ZoneOffset offset = zdt.getOffset();

        System.out.println(offset);
    }
}

Đầu ra:

+01:00
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.