Java API和客户端应用程序如何正确处理时区
我正在开发一个被安卓应用程序使用的JavaAPI。我已经到了需要正确处理日期和时间并考虑时区的地步
该应用程序的一个功能是预订某种指定日期和时间的服务。用户有可能取消预订,如果在预订开始前24小时取消预订,客户将获得所有退款
现在假设服务器位于伦敦(gmt 0),用户位于西班牙(gmt+1),预订时间为2015年2月25日16:00:00
当用户取消预订时,服务器需要在NOW()和预订开始日期之间进行区分。因此,如果用户(在西班牙)在2015年2月24日17:00:00(西班牙时间,预订前23小时)取消预订,则不会获得全额退款 当服务器检查差额时,因为现在(在英国是16:00:00),结果将是24小时,因此将错误地全额退款
我的问题在这里。如何根据用户时区正确获取正确的小时数? 我不太喜欢在取消请求中发送客户端时区,因为该值很容易被用户欺骗
在服务器端存储日期和时间时,什么是好的做法?我是否应该将它们存储在服务器时间中,并使用一个额外字段来了解客户端时区偏移量
# 1 楼答案
Basil Bourque,为了回答你最后的评论,我做了下面的测试。 如您所见,将时区设置为
LocalDateTime
很幸运。 你说得对,这不是正确的解决方案,如果我们没有其他解决方案,应该使用它以及输出:
注意,正如许多开发人员使用Hibernate一样,它提供了这个属性
hibernate.jdbc.time_zone
,这在处理日期时非常有帮助。将此属性设置为UTC
对LocalDateTime
和ZonedDateTime
有效# 2 楼答案
{a1}是正确的
在UTC工作
通常,所有业务逻辑、数据交换、数据存储和序列化都应该在UTC中完成。仅在需要/预期的情况下应用时区,例如向用户演示
爪哇。时间
一定要用java。Java 8及更高版本中内置的时间框架
默认情况下,java。时间类使用标准的ISO 8601格式来解析/生成日期时间值的文本表示。否则使用
DateTimeFormatter
对象Local…
类型是泛型的,不适用于任何地方,没有时区或offset-from-UTC。通常不在业务应用程序中使用,因为它们不是时间线上的实际时刻。此处用于分别解析日期字符串和时间字符串,组合,然后应用西班牙的已知时区。这样做会产生一个ZonedDateTime
,一个时间线上的实际时刻从中我们可以提取一个^{} ,UTC时间轴上的一个时刻
计算我们取消预订所需的24小时通知。请注意,24小时与“一天”不同,因为由于夏时制(DST)等异常情况,日的长度有所不同
获取正在取消的用户的当前时刻。这里我们使用问题中指定的日期时间进行模拟。对于较短的代码,我们调整了一小时,因为此解析方法仅处理UTC(
Z
)字符串。问题在西班牙时间17:00提出Europe/Madrid
比UTC早一个小时,所以16:00Z减去一个小时通过调用^{} 或^{} 方法来比较
Instant
对象A}方法使用{}的标准{a8},其中{}标记开始,{}将年-月-日部分与小时-分钟-秒部分分开,{}表示“小时”
Duration
表示总秒数加上几分之一秒(纳秒)的时间跨度。我们用这个来帮助数学,验证我们得到了23小时的预期结果。{转储到控制台
通过应用所需/预期时区向用户演示。指定一个
Instant
和一个ZoneId
来获取一个ZonedDateTime
让我们看看java。通过为人类语言指定一个短-中-长标志和一个
Locale
来实现时间本地化,其中(a)翻译日/月的名称,(b)使用文化规范对日期-时间部分进行排序,选择逗号与句点,等等忽略服务器时区
您的问题提到了服务器的时区。您永远不应该依赖服务器的时区,因为作为程序员,它超出了您的控制范围,而且系统管理员很容易不费吹灰之力就更改了它。此外,JVM的当前默认时区可能基于主机操作系统的时区。但不一定。JVM命令行启动上的标志可以设置JVM的默认时区。更危险的是:JVM中任何应用程序的任何线程上的任何代码都可以设置时区,并在运行时立即影响你的应用程序
如果不指定时区,则会隐式应用JVM的当前默认值。始终明确指定所需/预期的时区,如上面的代码所示
以上内容也适用于当前的默认值
Locale
。始终指定所需/预期的Locale
,而不是隐式地依赖于JVM的当前默认值# 3 楼答案
无论你身在何处,飞机都会准时起飞。这也称为时间戳。对于这种情况,存储时间戳将是一个合适的解决方案。在java中,当前时间戳可以通过
System.currentTimeMillis()
检索。此值不取决于服务器的时区,并且包含自1970年以来UTC的毫秒数当用户预订航班时,您需要将用户选择的时间+时区转换为时间戳。显示时,时间戳应转换为用户的时区
使用时间戳进行验证是一个简单的操作:
planeTakeOffTs - NOW > 24*60*60*1000
您可能还希望使用joda time(它已被包含在InspiredJava v8 Java.time中)这样的库来处理日期和时间