Joda LocalDate - 还在片刻吗?

时间:2010-11-24 15:28:41

标签: java jodatime

我正在寻找一个适当的可序列化日期类。在中部时区有一台服务器,我希望东部的用户输入日期为2010-11-23,而太平洋的用户将其视为2010-11-23(反之亦然)。

java.util.Date是一个对时间敏感的瞬间,所以它对我不起作用。我不想重新发明轮子,我决定试试Joda Time。根据概述,LocalDate是“代表没有时间的本地日期(没有时区)的类” - 正是我需要的。

不幸的是,它似乎与时区无关。在数据库中我有2010-11-23。在服务器上,我使用LocalDate将其转换为new LocalDate(java.sql.Date)date.toString()打印2010-11-23。

在客户端反序列化后,date.ToString()打印2010-11-22,date.getDayOfMonth()为22.但date.toDateTimeAtStartOfDay()生成2010-11-23T00:00:00.000-08:00。

我做错了吗?在Joda中是否有适当的仅限日期的时区敏感类?

编辑:在数据库中,我使用的是时区不敏感列(Postgres中为DATE)。服务器与数据库位于同一时区,因此它可以很好地读取日期。这不是问题。 我正在寻找曾在一个时区实例化的Java类型,在所有时区都具有相同的民用(部分)日期值。

编辑2 :在服务器上,所有内容都已正确加载并具有UTC时区。经过调查,我认为这是ISOChronology中的一个错误。在客户端,它被解压缩为America / Los_Angeles。原因是序列化完成了:

class ISOChronology {
// ...
    private Object writeReplace() {
        return new Stub(getZone());
    }

    private static final class Stub implements Serializable {
        private static final long serialVersionUID = -6212696554273812441L;

        private transient DateTimeZone iZone;

        Stub(DateTimeZone zone) {
            iZone = zone;
        }

        private Object readResolve() {
            return ISOChronology.getInstance(iZone);
        }

        private void writeObject(ObjectOutputStream out) throws IOException {
            out.writeObject(iZone);
        }

        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            iZone = (DateTimeZone)in.readObject();
        }
    }
}

祝你好运用瞬态字段序列化。

3 个答案:

答案 0 :(得分:3)

上面显示的存根类中的trasient时区是一个错误。令人惊讶的是,它没有被成千上万的测试或5年的广泛使用所吸引。错误报告https://sourceforge.net/tracker/index.php?func=detail&aid=3117678&group_id=97367&atid=617889

时区应为UTC,如Javadoc中定义的那样 - http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html。反序列化以获取任何其他时区将破坏类的内部状态。

JSR-310采用了更好的内部设计,不会遇到这类问题。

答案 1 :(得分:1)

我怀疑使用new LocalDate(java.sql.Date)构造函数可能是罪魁祸首。

相反,请尝试使用new LocalDate(int year, int month, int dayOfMonth)

有关详细信息,请参阅LocalDate JavaDocmanual

答案 2 :(得分:1)

您必须检查数据库中实际的内容。如果它确实使用了绝对时间戳并且它们都在一个时区中,那么您已经解析了 时区中的值,然后才转换为LocalDate。如果你的数据库中有一个字符串,那么解析该字符串并使用LocalDate的构造函数来获取你真正获得的信息。无论你做什么,都不要在时间和日期之间混淆;正如你从问题中发现的那样,它们是不可互换的。