英文:
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 小时。
所以,我的问题是:
- 我是否正确地按照描述的方式添加了客户应用的时区?
- 如何以更精确的方式应用时区,并将此日期格式化以查看应用的时区?
英文:
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:
- am I correct to adding timezone of client app in described way ?
- 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,那么atZone
的ZonedDateTime
输出也将表示指定时区的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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论