当前位置: 首页 > 知识库问答 >
问题:

如何在不转换的情况下将unix时间戳转换为LocalDate(Time)

屈升
2023-03-14

我在用org。乔达。时间LocalDate和LocalDateTime。我从外部源获得一个Unix时间戳,并希望从中生成一个LocalDate(时间)。关键是,在该外部系统的界面中定义,所有日期/时间都在UTC时区内。因此,我希望避免从该时间戳到本地系统的任何默认时区的任何隐式转换,这可能与UTC不同。有一个LocalDateTime的构造器用于这些事情,所以我尝试(作为一个例子):

System.out.println(new LocalDateTime(3600000L));
  --> 1970-01-01T02:00:00.000

System.out.println(new LocalDateTime(3600000L, DateTimeZone.UTC));
  --> 1970-01-01T01:00:00.000

结果让我有点吃惊。查看JavaDoc后,第一个构造函数“在默认区域使用ISO年表”计算时间戳根据定义,Unix时间戳是从01-JAN-1970T00:00:00UTC开始的秒数(这里是毫秒)!因此,如果值3600000(=正好2小时单位毫)被添加到该基数,它将达到01-JAN-1970T02:00:00UTC。我的本地系统设置为时区欧洲/柏林(CET),这是世界协调时1。准确地说,我们现在有夏令时,所以它甚至应该是UTC 2,但是让我们假装我们现在在UTC 1。因此,如果时间戳定义为UTC,那么我希望结果时间是01:00:00,如果它将时间戳的值解释为转换为UTC的CET,或者03:00:00,如果它正确地期望时间戳为具有转换为CET的UTC值。但它实际上显示了一个未转换的时间戳,正好离基地2小时。第二个构造函数应该“使用指定区域的国际标准化组织年表”计算时间戳(来自JavaDoc)所以如果我显式指定UTC时区,我不会期望任何转换,而是02:00:00的时间。基于UTC的时间戳,其结果本身被声明为UTC的时间应该完全是这样,但结果是01:00:00!为了再次检查,我明确地用CET调用它,得到了与我不提供任何时区相同的结果。

所以看起来,时间戳不是UTC,而是本地时区。创建LocalDateTime需要它,并将本地时区转换为目标时区(构造函数的第二个参数)。首先,我想知道这是否真的可以。其次,我必须保证我的代码中不会发生这种转换。所以我可以相信,保留第二个html" target="_blank">参数并使用默认时区可以做到这一点,但这能保证吗?或者,如果我们从夏时制改为夏时制,可能会发生一些奇怪的转换吗?即使更改本地时区也不能有任何后果,这就是为什么我们从外部系统获得的所有时间戳都已转换为UTC。

我观察到的一个坏情况是,时间戳应该只是一个日期(没有时间)。在这种情况下,时间戳将是时间设置为00:00:00的任何日期。当我使用LocalDate时,就像我在上面的例子中使用LocalDateTime一样,它会将时间戳转换为日期时间(当然),并简单地缩短时间。但是,如果日期是2014年7月15日00:00:00UTC,而我这边的结果与我的另一个例子中的结果相同,则会变为2014年7月14日23:00:00,并随之变为2014年7月14日!这实际上是一场灾难,绝不能发生!

你们有人知道为什么LocalDate(时间)会这样吗?或者我可能会误解的我背后的概念是什么。或者如何保证不发生转换?

共有3个答案

宣熙云
2023-03-14
匿名用户

new LocalDateTime(3600000L,DateTimeZone.UTC)没有真正意义:LocalDateTime根据定义是在您的时区中。因此,它的作用是:假设时间戳是使用本地时区获取的,并且您想知道UTC时区中的时间戳是什么。这正是你想要做的相反的转换。

试试新的日期时间(3600000L)。toLocalDateTime()将UTC时间戳转换为本地时间。

[编辑]你说得对,我上面的建议有误导性。文件说:

LocalDateTime是一个不可修改的datetime类,表示没有时区的datetime。

所以这件事是“当前时区”的局部现象——不管是什么。创建格式化程序时,它会隐式地获取时区(默认时区)。所以,当你格式化这样一个本地时间时,它会“移动”到你的时区,因为它本身没有时区。

您可以使用这种类型来表示“12:00”的概念,而不带时区。如果你加上与新加坡的日期,它将继承新加坡的时区。所以你可以用它来计算日期,比如“我想在世界上不同城市的“9:00”得到一个DateTime。”

另一方面,DateTime有一个固定的时区,它不会根据上下文而改变。如果不给它一个时区,JavaVM的当前时区将是默认的。

有了这些知识,new DateTime(3600000L,DateTimeZone.UTC)。toLocalDateTime()显然必须导致1970-01-01T01:00:00.000

首先,我们创建一个带有固定时区(UTC)的DateTime。单独格式化时,格式化程序会看到“哦,这有一个时区,所以我可以使用它。”现在,将其转换为本地时间,该时间会剥离时区信息,格式化程序将使用默认值。

要解决您的问题,请使用以下代码:

new DateTime(3600000L, DateTimeZone.UTC).withTimeZone(DateTimeZone.getDefault())

应与以下内容相同:

new DateTime(3600000L)

因为所有时间戳都是相对于1970-01-01T00:00:00ZZ==UTC时区)。

师博
2023-03-14

你为什么不:

timeStamp.toLocalDateTime().toLocalDate(); // JAVA 8
颛孙炜
2023-03-14

你的问题令人困惑,但你似乎声称数字3_600_000L代表自UTC 1970年第一个时刻(1970-01-01T00:00Z)的历元参考以来的毫秒计数。

所以解析为Instant

Instant                         // Represent a moment in UTC, an offset of zero hours-minutes-seconds.
.ofEpochMilli( 3_600_000L  )    // Parse a count of milliseconds since 1970-01-01T00:00Z. Returns a `Instant` object.
.toString()                     // Generate text representing this value, using standard ISO 8601 format.

结果是1970年第一天凌晨1点,如UTC所示。末尾的Z表示UTC。

1970-01-01T01:00:00Z

获取日期部分,如在UTC中看到的。

Instant                           // Represent a moment in UTC, an offset of zero hours-minutes-seconds.
.ofEpochMilli( 3_600_000L  )      // Parse a count of milliseconds since 1970-01-01T00:00Z.
.atOffset(                        // Convert from `Instant` (always in UTC, an offset of zero) to `OffsetDateTime` which can have any offset.
    ZoneOffset.UTC                // A constant representing an offset of zero hours-minutes-seconds, that is, UTC itself.
)                                 // Returns a `OffsetDateTime` object.
.toLocalDate()                    // Extract the date portion, without the time-of-day and without the offset-from-UTC.
.toString()                       // Generate text representing this value, using standard ISO 8601 format.

1970-01-01

将该时刻从UTC调整为欧洲/柏林时区。

Instant                           // Represent a moment in UTC, an offset of zero hours-minutes-seconds.
.ofEpochMilli( 3_600_000L  )      // Parse a count of milliseconds since 1970-01-01T00:00Z.
.atZone(                          // Convert from UTC to a particular time zone.
    ZoneId.of( "Europe/Berlin" )  // A time zone is a history of the past, present, and future changes to the offset-from-UTC used by the people of a particular region. 
)                                 // Returns a `ZonedDateTime` object.
.toString()                       // Generate text representing this value, using standard ISO 8601 format wisely extended to append the name of the time zone in square brackets.

1970-01-01T02:00 01:00[欧洲/柏林]

请注意,这个结果在一天中的不同时间,柏林地区是凌晨2点,而不是我们在UTC看到的凌晨1点。当时,欧洲/柏林的时区比UTC早一个小时运行,所以凌晨1点前一个小时就是凌晨2点——同一时刻,时间线上的同一点,不同的挂钟时间。

从那一刻获取日期部分,如欧洲/柏林所示。

Instant                           // Represent a moment in UTC, an offset of zero hours-minutes-seconds.
.ofEpochMilli( 3_600_000L  )      // Parse a count of milliseconds since 1970-01-01T00:00Z.
.atZone(                          // Convert from UTC to a particular time zone.
    ZoneId.of( "Europe/Berlin" )  // A time zone is a history of the past, present, and future changes to the offset-from-UTC used by the people of a particular region. 
)                                 // Returns a `ZonedDateTime ` object.
.toLocalDate()                    // Extract the date only, without the time-of-day and without the time zone. Returns a `LocalDate` object.
.toString()                       // Generate text representing this value, using standard ISO 8601.

1970-01-01

在本例中,柏林地区的日期与UTC相同。但在其他情况下,日期可能会有所不同。例如,UTC 1月23日晚上9点(21:00)同时是日本东京的“明天”24日。

显然,您使用术语“Unix时间戳”来表示自1970 UTC,1970-01-01T00:00Z的第一个时刻起的毫秒计数。

将该数字解析为一个Instant对象。类表示UTC时间线上的一个时刻,分辨率为纳秒(小数的九(9)位数)。

Instant instant = Instant.ofEpochMilli( 3_600_000L ) ;

instant.toString(): 1970-01-01T01:00:00Z

非常简单:一个Instant总是在UTC,总是一个时刻,时间线上的一个点。

时间戳应该只是一个日期(没有时间)。

为此,请使用LocalDate类。LocalDate类表示一个只包含日期的值,不包含一天中的时间和时区。

时区对确定日期至关重要。在任何一个特定的时刻,世界各地的日期因地区而异。例如,法国巴黎午夜过后几分钟是新的一天,而魁北克山仍然是“昨天”。

如果未指定时区,JVM将隐式应用其当前默认时区。默认值可能随时发生变化,因此结果可能会有所不同。最好将所需/预期时区明确指定为参数。

大陆/地区的格式指定适当的时区名称,例如美国/蒙特利尔非洲/卡萨布兰卡,或太平洋/奥克兰。切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不标准化,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

通过应用ZoneId生成ZoneDateTime,将UTC值(Instant)调整到另一个时区。

ZonedDateTime zdt = instant.atZone( z ) ;  

从那里,我们可以将仅日期部分提取为LocalDate对象。

LocalDate ld = zdt.toLocalDate() ;

如果您想在该日期当天的第一个时刻,您必须指定时区的上下文。对于任何给定的时刻,日期因时区而异。当新的一天在印度破晓时,在法国仍然是“昨天”。

总是让java。时间决定一天中的第一刻。不要假设00:00。在某些日期的某些区域,由于夏时制(DST)等异常情况,一天可能会在另一个时间开始,如01:00。

ZonedDateTime zdtStartOfDay = ld.atStartOfDay( z ) ;

如果您想看到与UTC相同的时刻,只需提取一个Instant

Instant instant = zdtStartOfDay.toInstant() ;

java.time类也有一个LocalDateTime类。要明白,这个类LocalDateTime不代表一个时刻!它不代表时间线上的一个点。它没有真正的意义,除非你把它放在一个时区的上下文中。这个类只用于两种含义:

  • 区域/偏移量未知(情况很糟糕)

希望您能看到,一旦理解了核心概念并使用了优秀的精心设计的java,这项工作就不会那么令人困惑了。时间课。

爪哇。时间框架内置于Java8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,比如java。util。日期日历

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

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR 310。

你可以交换java。时间对象直接与数据库连接。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java。sql* 类。

在哪里获得java.time类?

  • JavaSE8、JavaSE9及更高版本
    • 内置的
    • 标准Java API的一部分,带有捆绑实现
    • Java9增加了一些小功能和修复
    • java的大部分内容。时间功能被重新移植到Java 6
    • 更高版本的Android捆绑包实现了java。时间课

    额外的Three Ten项目扩展了java。有额外课程的时间。这个项目是java未来可能增加的一个试验场。时间你可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,等等。

 类似资料:
  • 问题内容: 我正在寻找将UTC时间字符串转换为Unix时间戳的选项。 我拥有的字符串变量是,需要将其转换为unix时间戳,例如 任何想法如何做到这一点? 问题答案: 首先,unix时间戳没有时间,但以UTC为单位。 在包有功能解析与预计解析时的布局。布局是从参考时间开始构造的。因此,在您的情况下,布局应为。使用Parse之后,您将获得一个可以调用Unix来接收Unix时间戳的结构。

  • 如果本地时间位于UTC时区,那么如何将转换为Unix时间戳? >。

  • 问题内容: 我将时间作为Unix时间戳存储在MySQL数据库中,并将其发送到一些JavaScript代码。我怎么会得到时间呢? 例如,以HH / MM / SS格式。 问题答案: let unix_timestamp = 1549312452 有关Date对象的更多信息,请参考MDN或ECMAScript5规范。

  • 问题内容: 关于“ UNIX timestamp to MySQL time”,有很多问题要问。我需要相反的方式,是的…知道吗? 问题答案: 用途: 还要检查一下(以MySQL方式完成)。 http://dev.mysql.com/doc/refman/5.5/en/date-and-time- functions.html#function_unix- timestamp

  • 问题内容: 如何在Java中将分钟从Unix时间戳转换为日期和时间。例如,时间戳1372339860对应于。 我想转换成。 编辑:其实我希望它是根据美国时间GMT-4,所以它将是。 问题答案: 你可以使用SimlpeDateFormat来格式化日期,如下所示: 如果使用的模式SimpleDateFormat非常灵活,则可以根据给定的特定模式,在javadocs中检入可用于产生不同格式的所有变体Da