【问题标题】:Is there any way to convert ZoneId to ZoneOffset in Java 8?有没有办法在 Java 8 中将 ZoneId 转换为 ZoneOffset?
【发布时间】:2015-12-14 02:39:06
【问题描述】:

我有一个纪元秒和一个 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

【问题讨论】:

  • 您使用什么语言/方言来进行批量导入import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset} 工作?在 Java 11 中对我来说是 unexpected token
  • 可以是 Scala,但这在这里并不重要
  • 我在这里详细讨论了java.time 背后的理论:stackoverflow.com/a/56508200/145989

标签: java java-8 java-time zoneddatetime java.time.instant


【解决方案1】:

您可以通过以下方式从ZoneId 获取ZoneOffset

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
  • 我检查了它,它取决于另一个条件。更新了答案。
【解决方案2】:

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

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

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

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

【讨论】:

  • 我知道,但它是如何完成的?如果我知道 LocaDate 并且有 ZoneId,我如何将其转换为 ZoneOffset。我的用例是一个包含时间和区域的字符串。我想将字符串解析为 OffsetTime,而不丢弃区域信息。
【解决方案3】:

tl;博士

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

…当前默认时区…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

详情

Answer by Stanislav Bshkyrtsev 正确直接地回答了您的问题。

但是,正如Answer by Jon Skeet 中所建议的那样,涉及更大的问题。

LocalDateTime

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

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

Instant

如果您想获取当前时间,则无需从纪元秒开始。获取当前的InstantInstant 类表示 UTC 时间线上的时刻,分辨率为 nanoseconds(最多九 (9) 位小数)。

Instant instant = Instant.now();

Instant 的内部是 nanoseconds-from-epoch 的计数。但我们并不在乎。

另请参阅,What's the difference between Instant and LocalDateTime?

ZonedDateTime

如果您想通过特定地区挂钟时间的镜头看到那一刻,请申请ZoneId 以获取ZonedDateTime

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

作为快捷方式,你可以直接到ZonedDateTime做。

ZonedDateTime zdt = ZonedDateTime.now( z );  

ZonedDateTime 中有一个 Instant。调用zdt.toInstant() 以获得与UTC 中的基本值相同的时刻。无论哪种方式,自纪元以来的纳秒数相同,如 ZonedDateTimeInstant

给定的秒数

如果给您一个自纪元以来的秒数,并且纪元是 1970 年的第一个时刻 UTC (1970-01-01T00:00:00Z),则将该数字提供给 Instant

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


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案4】:

    正如documentation 所说,“这主要用于低级转换,而不是一般的应用程序使用。”

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 我在这里发布了这个答案,因为这是我在寻找一种方法来做我最终想出的事情时出现的页面。
      【解决方案6】:

      以下返回以毫秒为单位的时间量,以添加到 UTC 以获得该时区的标准时间:

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

      【讨论】:

      • localZoneOffset = ZoneOffset.ofTotalSeconds(TimeZone.getTimeZone(localTimeZone).getRawOffset / 1000)
      【解决方案7】:

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

      1. 从纪元秒和区域 ID 获取 ZonedDateTime
      2. ZonedDateTime 获取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
      

      【讨论】:

        【解决方案8】:

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

        ZonedDateTime.now().getOffset()
        

        【讨论】:

          【解决方案9】:

          这样做无需创建 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 
                  )
              );
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-09-20
            • 1970-01-01
            • 2018-10-23
            • 2016-08-20
            • 1970-01-01
            • 1970-01-01
            • 2014-03-20
            相关资源
            最近更新 更多