2010-11-24 74 views
5

我正在寻找一个正确的可串行化日期类。在中央时区有一台服务器,我希望东部的用户输入日期为2010-11-23,太平洋的用户将其视为2010-11-23(反之亦然)。乔达LocalDate - 仍然是一个瞬间?

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

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

在客户端上反序列化之后,2010-11-22和date.getDayOfMonth()打印出来的是date.ToString(),但是产生了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(); 
     } 
    } 
} 

祝您好运序列化与瞬态字段。

+1

如果你想忽略时区,你可以在所有地方使用UTC/GMT吗? – 2010-11-24 15:33:19

+0

你正在使用哪个Joda版本,以及如何序列化对象?对于标准的Java序列化,Stub类具有适当的writeObject/readObject方法来处理iZone字段的“手动”处理,但这当然可能会失败,其他序列化实现(如IIOP,SOAP或其他任何尝试自动从对象实例中提取字段值。 – jarnbjo 2010-11-24 16:17:51

+0

@jarnbjo 1.6.2。串行器是好的,像我上面指出的问题是`Stub.iZone`是暂时的。 – 2010-11-24 16:25:04

回答

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

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

有关更多详细信息,请参见LocalDateJavaDocmanual

1

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