java - 如何使用 ObjectOutputStream 和 ObjectInputStream 在 Java 中处理夏令时?
问题描述
我正在传递一个包含日期的哈希图
2019-03-08 00:00:00.0
到 servlet 并在 servlet 端读取 hashmap 时,我得到的日期为
2019-03-07 23:00:00.0
它仅在夏令时转换一小时。如何在 java 中处理这个?
java.util.Date d = new java.util.Date();
d.setDate(06);
d.setMonth(02);
d.setYear(2018);
d.setHours(23);
d.setMinutes(59);
d.setSeconds(00);
ObjectInputStream is = new ObjectInputStream(request.getInputStream());
java.util.Date obj=(java.util.Date)is.readObject();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(response.getOutputStream());
Vector vector = new Vector();
vector.add(d);
objectOutputStream.writeObject(vector);
objectOutputStream.flush();
objectOutputStream.close();
从 java 课上阅读它时,我少了一个小时。
解决方案
如果服务器时区设置未将夏令时 (DST) 考虑在内,可能会发生这种情况的一种解释。例如,我以美国/亚松森时区为例。亚松森是巴拉圭最大的城市和首都。巴拉圭在标准时间偏移-04:00,但在夏季偏移-03:00。夏季时间在 3 月 8 日仍然有效,并将持续到 3 月 24 日。
首先演示出了什么问题:
System.setProperty("user.timezone", ZoneId.ofOffset("GMT", ZoneOffset.ofHours(-4)).getId());
// Send a timestamp from America/Asuncion time zone
ZoneId zone = ZoneId.of("America/Asuncion");
// Create the timestamp as March 8 at 00:00:00
Instant testTime
= ZonedDateTime.of(2019, 3, 8, 0, 0, 0, 0, zone).toInstant();
Timestamp ts = Timestamp.from(testTime);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos)) {
objectOutputStream.writeObject(ts);
}
byte[] ba = baos.toByteArray();
try (ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(ba))) {
java.util.Date obj = (java.util.Date) is.readObject();
System.out.println(obj);
}
}
对于这个简单的演示,我们不需要单独的客户端和服务器代码。我在相关时区创建了一个Timestamp
具有已知日期和时间的对象,将其写入 an并使用相同的底层字节ObjectOutputStream
从 an 中读取。ObjectInputStream
我得到的是Timestamp
代表同一时间点的。为了演示接收器打印时会发生什么,我在顶部设置了默认时区。我使用一个恒定的偏移量-04:00
来演示当服务器时区不考虑夏令时时会发生什么。它打印:
2019-03-07 23:00:00.0
所以你得到了同样的结果。这是因为——令人困惑的是——Timestamp.toString
使用 JVM 的时区设置来生成字符串。
怎么修?
当我们知道Timestamp
是从美国/亚松森时区发送的时,我们可以在服务器上明确使用该时区:
java.util.Date obj = (java.util.Date) is.readObject();
ZonedDateTime timeAsSent = obj.toInstant().atZone(zone);
System.out.println(timeAsSent);
2019-03-08T00:00-03:00[美国/亚松森]
现在时间与最初写入对象输出流的内容一致。
更好的修复
如果有任何方法可以,请完全避免旧Date
课程Timestamp
。这些课程设计得很糟糕,并且对你玩这样的把戏。它们也早已过时。而是将 aZonedDateTime
或 an写入Instant
客户端的对象流,当然在服务器端读取相同的类型。那么就没有惊喜的余地了。
推荐阅读
- django - 如何创建带有接受字段的朋友模型?
- big-o - Ω(n) 中的 f 是否意味着 f 在 O(n^2) 中?
- r - 为什么我的因子水平在逻辑回归中会反转?(MNIST 数据)
- sql-server - 使用 VB.net 使用正则表达式计算文本摘要中的单词组合
- python - 当我期望一个数组时,函数返回类型 None
- java - 如何解决“org.junit.rules.Timeout”包中的 Timeout.seconds() 方法生成的“找不到符号”错误?
- macos - 如何检查 MacOS 终端中的互联网连接是否可用?
- java - Spring AWS SQS - MessageConversionException
- django - 如何在 Django 中使搜索更准确?
- wordpress - 在 woocommerce 中向客户发送/保存订单详细信息之前处理卡