如何使用ObjectOutputStream和ObjectInputStream处理Java中的夏令时?

问题描述 投票:0回答:1

我正在传递一个包含日期的hashmap

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类中读取它时,Iam减少了一个小时。

java serialization dst objectinputstream
1个回答
0
投票

如果服务器时区设置不考虑夏令时(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对象,该对象在所讨论的时区中具有已知的日期和时间,将其写入ObjectOutputStream并使用相同的底层字节从ObjectInputStream读回来。我得到的是代表同一时间点的Timestamp。为了演示接收器打印时会发生什么,我将默认时区设置在顶部。我正在使用-04:00的常量偏移来演示当服务器时区不考虑夏令时时会发生什么。它打印:

2019-03-07 23:00:00.0

所以你得到的结果相同。这是因为 - 令人困惑的是 - Timestamp.toString使用JVM的时区设置来生成字符串。

怎么修?

当我们知道Timestamp是从America / Asuncion时区发送的时候,我们可以在服务器上明确使用该时区:

            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 [美国/亚松森]

现在,时间与首先写入对象输出流的内容一致。

更好的解决方案

如果你有任何办法,可以完全避免旧班级DateTimestamp。这些课程的设计很差,并且会对你起作用。它们也很久了。而是将ZonedDateTimeInstant写入客户端的对象流,当然在服务器端读取相同的类型。然后就没有惊喜的余地了。

© www.soinside.com 2019 - 2024. All rights reserved.