在Java 8 中有什么方法可以将ZoneId 转换为ZoneOffset 吗?

Is there any way to convert ZoneId to ZoneOffset in Java 8?

我有一个纪元秒和一个 zoneId(请参阅下面的 method1)。

可以用系统默认的zoneId转成LocalDateTime,但是我没有找到把纪元秒转成LocalDateTime的方法(见下文method2),因为有是没有ZoneOffset.systemDefault。我觉得很晦涩。

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

val epochSecond = System.currentTimeMillis() / 1000

// method1
LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())

// method2
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)

注意

上面显示的源代码是Scala

正如documentation所说,"This is primarily intended for low-level conversions rather than general application usage."

通过 Instant 对我来说非常有意义 - 你的纪元秒实际上是 Instant 的不同表示,因此转换为 Instant,然后将其转换为特定的时区。

没有一对一的映射。 ZoneId 定义一个地理范围,其中随时间使用一组不同的 ZoneOffsets。如果时区使用夏令时,它的ZoneOffset在夏季和冬季会有所不同。

此外,夏令时规则可能会随着时间发生变化,因此 ZoneOffset 可能会有所不同,例如13/10/2015 与 13/10/1980 相比。

因此您只能在特定 Instant 上找到 ZoneId 的 ZoneOffset。

另见 https://en.wikipedia.org/wiki/Tz_database

这是从 ZoneId 获取 ZoneOffset 的方法:

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

注意:ZoneId 可以有不同的偏移量,具体取决于时间点和特定地点的历史。所以选择不同的 Instants 会导致不同的偏移量。

NB2: ZoneId.of() 可以 return 一个 ZoneOffset 而不是 ZoneId 如果 UTC+3/GMT+2/etc 被传递而不是像 Africa/Cairo 这样的时区。因此,如果传递 UTC/GMT 偏移量,则不会考虑 Instant 的 historical/geographical/daylight-saving 信息 - 您只需使用指定的偏移量即可。

tl;博士

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

…当前默认时区…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

详情

正确而直接地回答了您的问题。

但是,如 .

中所建议的,还涉及更大的问题

LocalDateTime

I don't find the way to convert epoch second to LocalDateTime

LocalDateTime 故意没有时区概念或 offset-from-UTC。不太可能是你想要的。 Local… 表示 任何 地点,而不是任何一个特定地点。这个 class 代表一个时刻,仅 可能 个大约 26-27 小时范围内的时刻(时区范围全球)。

Instant

如果您要获取当前时间,则无需以纪元秒开始。获取当前 InstantInstant class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。

Instant instant = Instant.now();

Instant 里面是 nanoseconds-from-epoch 的计数。但是我们真的不在乎。

另见,

ZonedDateTime

如果您想通过特定地区 wall-clock 时间的镜头看到那一刻,请应用 ZoneId 以获得 ZonedDateTime

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

作为快捷方式,可以直接做ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

一个ZonedDateTime里面有一个Instant。调用 zdt.toInstant() 以获取与 UTC 中的基本值相同的时刻。相同数量的 nanoseconds-since-epoch 作为 ZonedDateTimeInstant.

Seconds-since-epoch给定

如果给你一个计数seconds-since-epoch,并且纪元是UTC1970-01-01T00:00:00Z)中的1970年的第一个时刻,那么将该数字输入Instant.

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


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

在哪里获取 java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

我希望下面我的解决方案的前两行对您有所帮助。我的问题是我有一个 LocalDateTime 和时区名称,我需要一个 instant 以便我可以构建一个 java.util.Date,因为那是 MongoDB 想要的。我的代码是Scala,不过这里和Java很接近我觉得理解起来应该没有问题:

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)

以下 returns 添加到 UTC 以获取此时区标准时间的时间量(以毫秒为单位):

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

I have an epoch second and a zoneId. Is there any way to convert ZoneId to ZoneOffset in java 8?

  1. 从纪元秒和 Zone Id
  2. 获取 ZonedDateTime
  3. ZonedDateTime
  4. 得到ZoneOffset

演示:

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);
    }
}

输出:

+01:00

因为您正在寻找默认区域偏移

ZonedDateTime.now().getOffset()

无需创建 Instant 或此类对象即可将其拉出。

public static ZoneOffset offset() {
    return offset(ZoneId.systemDefault());                 // Default system zone id
}
public static ZoneOffset offset(ZoneId id) {
    return ZoneOffset.ofTotalSeconds((int) 
        TimeUnit.MILLISECONDS.toSeconds(
            TimeZone.getTimeZone(id).getRawOffset()        // Returns offset in milliseconds 
        )
    );
}