【问题标题】:Sending Dates over RMI between machines in different regions在不同区域的机器之间通过 RMI 发送日期
【发布时间】:2023-10-20 16:33:01
【问题描述】:

我在通过 RMI 与不同时区的机器之间发送 java.util.Date 对象时遇到问题。

例如,德国的客户将日期对象发送到英国的服务器。

  1. 用户输入日期字符串,例如20090220。
  2. 德国的客户端应用程序使用 SimpleDateFormat("yyyyMMdd") 将其转换为日期:Fri Feb 20 00:00:00 CET 2009
  3. 英国服务器通过 RMI 接收日期为:Thu Feb 19 23:00:00 GMT 2009
  4. 服务器将日期存储到英国 Oracle 数据库的 DATE 列中

解决日期错误问题的最佳方法是什么? 我可以发送日期字符串并让服务器将其转换为日期,但我想减少服务器必须做的工作量。

这是一个显示日期序列化的独立测试程序:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class SerializationTest {

    public static void main(String[] args) throws Exception {

        final String yyyyMMdd = "20090220";
        final Date date = new SimpleDateFormat("yyyyMMdd").parse(yyyyMMdd);

        if (args.length != 1) {
            System.out.println("Usage SerializationTest S|D");
        }

        boolean serialise = false;
        if (args[0].equals("S")) {
            serialise = true;
        }
        else if (args[0].equals("D")) {
            serialise = false;
        }

        String filename = "date.ser";
        if (serialise) {
            // write the object to file
            FileOutputStream fos = new FileOutputStream(filename);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            ObjectOutputStream outputStream = new ObjectOutputStream(bos);
            outputStream.writeObject(date);
            outputStream.flush();
            outputStream.close();

            System.out.println("Serialised: " + date);
        }
        else {
            FileInputStream fis = new FileInputStream(filename);
            BufferedInputStream bis = new BufferedInputStream(fis);
            ObjectInputStream inputStream = new ObjectInputStream(bis);
            Date outDate = (Date) inputStream.readObject();
            inputStream.close();

            // print the object
            System.out.println(outDate);
        }
    }
}

【问题讨论】:

  • 2009 年 2 月 20 日星期五 00:00:00 CET 正好等于 2009 年 2 月 19 日星期四 23:00:00 GMT 2009。不存在日期差异。
  • 我知道日期是相等的。当我尝试将日期对象放入数据库的 DATE 列(不是 DATETIME)时,就会出现差异。它导致 19/2/2009 而不是 20/2/2009!

标签: java rmi


【解决方案1】:

我看不出你的问题是什么,这些日期对我来说看起来是正确的——它们只是被格式化为使用的语言环境。如果您希望用户输入的日期为 GMT 格式,请在 SimpleDateFormat 构造函数中指定区域设置

【讨论】:

  • 问题是我的服务器在我的数据库中存储了错误的日期。我得到的不是 20/02/2009,而是 19/02/2009。 (我的数据库列是 java.sql.Types.DATE)
  • 我所说的仍然有效。数据库中的日期应存储在单个时区(最好是 GMT)中 - 只需在存储日期之前将日期转换为该时区
【解决方案2】:

查看 getTime() 和 setTime()。他们应该做你正在寻找的东西。与其通过网络将其作为特定于位置的字符串发送,不如在客户端上使用 getTime() 将其作为纪元以来的毫秒数发送,然后在客户端上构建一个新的 Date 并使用 setTime() 和服务器。

【讨论】:

  • 我不是将它作为“特定于位置的字符串”发送,而是作为 java.util.Date 对象发送。我尝试发送毫秒数,但是当我在服务器上创建一个 Date 对象并调用 setTime 时,它​​仍然给我 2 月 19 日星期四,而不是 2 月 20 日星期五。
  • 将相同的长消息发送回客户端,在其语言环境中格式化时应显示 Fri Feb 20,尽管服务器值。如果您需要通过服务器端的管理 UI 对其进行修改,则必须使用时区数学,而且我已经多年没有编写 Java,所以我无法帮助您。
  • 您不必使用时区数学,只需设置正确的语言环境,它就会正确格式化
【解决方案3】:

看一下 java.util.Calendar 特别是 getTime() 方法。

这样您将以毫秒为单位发送时间,而不是可以以不同方式解释的字符串。

【讨论】: