在Java/Kotlin中处理时区的逻辑是什么?

huangapple go评论61阅读模式
英文:

What is logic of manipulation with timezones in Java/Kotlin?

问题

假设我在数据库中保存了客户的时间为 2020-09-22T10:50:37.276240900

根据客户的时区,在客户应用的网络服务中呈现这个日期,例如,如果客户位于 UTC+2 时区,我需要在保存的日期上添加 2 小时。

那么我在做什么呢?

从实体中获取日期,并将时区添加到从数据库获取的时间 (startDate: LocalDateTime)。

entity.startDate.atZone(ZoneId.of("Europe/Vienna"))

这将给我一个值为 ZonedDateTime 的结果 2020-09-22T10:50:37.276240900+02:00[Europe/Vienna],这正是我预期的结果,基本上是 "初始时间加上 2 小时"。

之后,我想要将这个时间格式化,以便输出中包含添加了这 2 小时的时间,类似于这样:

12:50 22.09.2020

但是,当我使用以下格式化方式时:

entity.startDate
    .atZone(ZoneId.of("Europe/Vienna"))
    .format(DateTimeFormatter.ofPattern(NotificationListener.EUROPEAN_DATE_FORMAT, Locale.ENGLISH))

其中 const val EUROPEAN_DATE_FORMAT = "HH:mm dd.MM.yyyy"

我得到的输出是 10:50 22.09.2020 ,看起来我的格式没有正确应用,因此我看不到添加的 2 小时。

所以,我的问题是:

  1. 我是否正确地按照描述的方式添加了客户应用的时区?
  2. 如何以更精确的方式应用时区,并将此日期格式化以查看应用的时区?
英文:

Let's assume that I have client's time saved in my database as 2020-09-22T10:50:37.276240900

I need to present this date in web-service for client app depending on client timezone, for example I need to add 2 hours to saved date if client lives in UTC+2 timezone.

So what am I doing for ?

Getting date from entity and adding timezone to time taken from database (startDate: LocalDateTime)

entity.startDate.atZone(ZoneId.of("Europe/Vienna"))

what gives me the value of ZonedDateTime 2020-09-22T10:50:37.276240900+02:00[Europe/Vienna]

This value is what I'm expecting for, basically "initial time plus 2 hours". After that I would to format this time to have output with this 2 hours of being added, some kind of this

12:50 22.09.2020

but when I do format like this

entity.startDate
 .atZone(ZoneId.of("Europe/Vienna"))
 .format(DateTimeFormatter.ofPattern(NotificationListener.EUROPEAN_DATE_FORMAT, Locale.ENGLISH))

where const val EUROPEAN_DATE_FORMAT = "HH:mm dd.MM.yyyy"

I get this output 10:50 22.09.2020 which looks like my format is not applied properly, so I cannot see my 2 hours.

So my questions are:

  1. am I correct to adding timezone of client app in described way ?
  2. how to apply timezone in more precise way and format this date to see timezone zone applied ?

答案1

得分: 2

LocalDateTime.atZone 不会“移动”时间点。实际上,它试图呈现一个时间点,其中给定时区的本地时间恰好是LocalDateTime显示的时间。

换句话说:如果你的LocalDateTime表示某个日期的10:00,那么atZoneZonedDateTime输出也将表示指定时区的10:00 本地时间(在本地时间由于夏令时变化而不存在的情况下除外)。

因此,如果你存储的时间实际上是在UTC时间,你需要再添加一步:

ZonedDateTime utcTime = entity.startDate.atZone(ZoneOffset.UTC);
ZonedDateTime localTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Vienna"));

或者,你可以避免每次计算localTime,而是配置DateTimeFormatter以使用给定的时区(这意味着它将在内部执行必要的计算)使用DateTimeFormatter.withZone。如果你这样做,你可以直接将utcTime传递给它。

英文:

LocalDateTime.atZone does not "move" the point in time. In fact it tries to present the point in time where the local time in the given timezone is exactly what the LocalDateTime shows.

In other words: if your LocalDateTime represented 10:00 at some date, then the ZonedDateTime output of atZone will also represent 10:00 local time at the specified time zone (except in cases where that local time doesn't exist due to DST changes).

So if your stored time is actually in UTC, you need to add one more step:

ZonedDateTime utcTime = entity.startDate.atZone(ZoneOffset.UTC);
ZonedDateTime localTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Vienna"));

Alternatively you can avoid calculating the localTime each time and instead configure the DateTimeFormatter to use a given time zone (which means it'll do the necessary calculations internally) using DateTimeFormatter.withZone. If you do this then you can pass the utcTime to it directly.

huangapple
  • 本文由 发表于 2020年9月22日 19:06:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/64008412.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定