开发者

Joda LocalDate - still an instant?

开发者 https://www.devze.com 2023-01-27 06:46 出处:网络
I\'m looking for a proper serializable date-only class. Got a server in Central time zone, I want users in the Eastern to enter date as 2010-11-23, and users in Pacific to see it as 2010-11-23 (and vi

I'm looking for a proper serializable date-only class. Got a server in Central time zone, I want users in the Eastern to enter date as 2010-11-23, and users in Pacific to see it as 2010-11-23 (and vice versa).

java.util.Date is a time-sensitive instant, so it doesn't work for me. Not wanting to reinvent the wheel, I decided to give Joda Time a try. According to overview, LocalDate is a "class representing a local date without a time (no time zone)" 开发者_StackOverflow社区- just what I need.

Unfortunately, it does not seem to be time zone independent. In database I have 2010-11-23. On server, I transform it to LocalDate with new LocalDate(java.sql.Date). date.toString() prints 2010-11-23.

After deserializing that on client, date.ToString() prints 2010-11-22 and date.getDayOfMonth() is 22. But date.toDateTimeAtStartOfDay() produces 2010-11-23T00:00:00.000-08:00.

Am I doing something wrong? Is there a proper date-only time zone insensitive class in Joda?

EDIT: In database I am using a timezone insensitive column (DATE in Postgres). Server is in the same time zone as the database, so it reads the date just fine. It is not an issue. I am looking for a Java type that once instantiated in one time zone, has the same civil (partial) date value in all time zones.

EDIT 2: On server everything is loaded properly and has UTC time zone. After investigation I think it is a bug in ISOChronology. On client it is unpacked as America/Los_Angeles. The reason is that serialization is done with:

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();
        }
    }
}

Good luck serializing with a transient field.


The trasient time zone in the stub class shown above is a bug. Amazing that it wasn't caught in tens of thousands of tests or 5 years of widespread usage. Bug report https://sourceforge.net/tracker/index.php?func=detail&aid=3117678&group_id=97367&atid=617889

The timezone should be UTC, as defined in the Javadoc - http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html . Deserializing to get any other time zone will break the internal state of the class.

JSR-310 uses a much better internal design which doesn't suffer from this kind of problem.


I suspect that using new LocalDate(java.sql.Date) constructor may be the culprit.

Instead, try using new LocalDate(int year, int month, int dayOfMonth).

See LocalDate JavaDoc and manual for more details.


You've got to check what is actually in your database. If it really is using absolute timestamps and they're all in one timezone, then you've got parse the values in that timezone and only then convert to a LocalDate. If you've got a string in your database, then parse that string and use the constructor for LocalDate that takes the information that you've really got. Whatever you do, don't get into mixing up between instants and dates; as you've found from your problems, they're not interchangeable.

0

精彩评论

暂无评论...
验证码 换一张
取 消