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


85

我通过method1有一个纪元和一个zoneId。它可以使用系统默认的zoneId转换为LocalDateTime,但是我找不到通过method2将纪元转换为LocalDateTime的方法,因为没有ZoneOffset.systemDefault。我认为它是晦涩的。

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

您使用什么语言/方言来进行批量导入import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}?这是一个unexpected token我在Java中11
anddero

1
可以是Scala,但这在这里并不是很重要
donatas M

1
java.time在这里详细讨论了背后的理论:stackoverflow.com/a/56508200/145989
OndraŽižka,

Answers:


109

这里是你如何能得到ZoneOffset来自ZoneId

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

注意:ZoneId根据时间点和特定地点的历史记录,可以具有不同的偏移量。因此,选择不同的Instant会导致不同的偏移量。

NB2:ZoneId.of()可以返回ZoneOffset,而不是ZoneId如果UTC+3/ GMT+2,而不是像一个时间段传递的/ etc Africa/Cairo。因此,如果传递了UTC / GMT偏移量,Instant则不会考虑历史/地理/夏时制信息-您只需使用指定的偏移量即可。


如果当前时刻在DST中,则给出的值不正确,但在计算时没有DST
msangel

@msangel,您能仔细检查一下吗?也许您ZoneId.systemDefault()在代码中使用它,并且它在不同的计算机上返回了不同的时区?
Stanislav Bashkyrtsev

我检查了一下,它可以根据其他条件工作。更新了答案。
msangel

43

没有一对一的映射。ZoneId定义了随时间使用一组不同的ZoneOffset的地理范围。如果时区使用夏时制,则夏季和冬季之间的ZoneOffset将有所不同。

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

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

另请参阅https://en.wikipedia.org/wiki/Tz_database


10
我知道,但是如何完成?如果我知道LocaDate并具有ZoneId,该如何将其转换为ZoneOffset。我的用例是一个包含时间和区域的字符串。我想将字符串解析为OffsetTime,而不删除区域信息。
凯·莫里兹

33

tl; dr

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

…当前的默认时区…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

细节

由斯坦尼斯Bshkyrtsev回答正确,直接回答你的问题。

但是,正如乔恩·斯凯特(Jon Skeet)回答中所建议的那样,涉及的问题更大。

LocalDateTime

我找不到将纪元秒转换为LocalDateTime的方法

LocalDateTime故意没有时区或从UTC偏移的概念。不太可能是您想要的。该Local…机构的任何地方,不是任何一个特定地区。此类不代表时刻,而是代表大约26-27小时(全球时区范围)内的潜在时刻。

Instant

如果您要获取当前时间,则无需以纪元秒开始。获取当前Instant。该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的9个位数)。

Instant instant = Instant.now();

在里面Instant是从纪元开始的纳秒数。但是我们并不在乎。

ZonedDateTime

如果您想通过特定区域的挂钟时间的镜头来查看该时刻,请应用ZoneId来获取ZonedDateTime

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

作为快捷方式,您可以直接对进行操作ZonedDateTime

ZonedDateTime zdt = ZonedDateTime.now( z );  

A中ZonedDateTime有一个Instant。调用zdt.toInstant()以获得与UTC中的基本值相同的时间。相同数量的纳秒-因为历元任一方式,作为一个的ZonedDateTime或作为Instant

给定秒数

如果您给以秒为单位的秒计数,并且该时期是UTC1970-01-01T00:00:00Z)中的1970年的第一时刻,则将该数字输入Instant

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

Java中的日期时间类型表,包括现代的和传统的。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要类。java.sql.*

在哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容打下了基础。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多


10

文档所述,“这主要用于低级别转换,而不是一般的应用程序使用。”

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


9

我希望下面我的解决方案的前两行会有所帮助。我的问题是我有一个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)

1
我在此处发布此答案,因为这是我在寻找一种最终想出解决办法的页面。
gknauth

1

以下代码返回添加到UTC以获得该时区标准时间的时间(以毫秒为单位):

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

0

我有一个纪元和一个zoneId。在Java 8中有什么方法可以将ZoneId转换为ZoneOffset吗?

  1. ZonedDateTime从纪元秒和区域ID获取
  2. 获得ZoneOffsetZonedDateTime

演示:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.