Converting from java.util.TimeZone to org.joda.Dat

2019-06-24 02:18发布

问题:

How is it possible in Java to convert an instance of java.util.TimeZone to org.joda.DateTimeZone and keeping the daylight saving time?

回答1:

Joda-Time in maintenance-mode

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

java.time.ZoneId

The modern replacement for java.util.TimeZone is java.time.ZoneId & java.time.ZoneOffset.

You should avoid the old legacy date-time classes. But if necessary, you can convert to/from the java.time types. Look to new methods added to the old classes. You can move between TimeZone and ZoneId.

java.util.TimeZone tz = java.util.TimeZone.getTimeZone( myZoneId );

…and…

java.time.ZoneId z = myLegacyTimeZone.toZoneId();

If you are looking for the offset-from-UTC or Daylight Saving Time (DST) info for the zone, look at the ZoneRules class. Search Stack Overflow for more discussion and examples on that, or edit your Question to describe more about your goal.



回答2:

When you call DateTimeZone.forTimeZone, it uses the timezone ID and Joda creates the equivalent object using its own DST rules - it doesn't import the rules from the TimeZone object.

Another detail is that you're using "GMT", which is a zone without DST rules (just check the value for DateTimeZone.forID("GMT").isFixed() - it returns true meaning that the zone is fixed, AKA it doesn't have offset changes, AKA it has no DST).

It seems that you want a zone with London DST rules (based on the dates you've chosen to DST start and end). If that's the case, you can just create a zone using DateTimeZone.forID("Europe/London").


But if you want to create a custom zone with specific DST rules, you have to do it manually by extending DateTimeZone class. One example of a zone with DST starting at 27/Mar/2013 and ending at 31/Oct/2013, both at midnight (you can change the values according to your needs though).

public class CustomTimeZone extends DateTimeZone {

    private DateTime dstStart;

    private DateTime dstEnd;

    protected CustomTimeZone(String id) {
        super(id);
        // DST starts at 27/Mar/2013 and ends at 31/Oct/2013
        this.dstStart = new DateTime(2013, 3, 27, 0, 0, 0, 0, DateTimeZone.UTC);
        this.dstEnd = new DateTime(2013, 10, 30, 23, 0, 0, 0, DateTimeZone.UTC);
    }

    @Override
    public String getNameKey(long instant) {
        return this.getID();
    }

    @Override
    public int getOffset(long instant) {
        // check if it's in DST
        if (dstStart.getMillis() <= instant && instant < dstEnd.getMillis()) {
            // DST, offset is 1 hour ahead of UTC - value must be in milliseconds
            return 3600000;
        }
        return 0;
    }

    @Override
    public int getStandardOffset(long instant) {
        // assuming stardard offset is zero (same as UTC)
        return 0;
    }

    @Override
    public boolean isFixed() {
        return false;
    }

    @Override
    public long nextTransition(long instant) {
        if (instant < dstStart.getMillis()) {
            return dstStart.getMillis();
        }
        if (instant < dstEnd.getMillis()) {
            return dstEnd.getMillis();
        }
        return instant;
    }

    @Override
    public long previousTransition(long instant) {
        if (instant > dstEnd.getMillis()) {
            return dstEnd.getMillis();
        }
        if (instant > dstStart.getMillis()) {
            return dstStart.getMillis();
        }
        return instant;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof CustomTimeZone) {
            return getID().equals(((CustomTimeZone) obj).getID());
        }
        return false;
    }
}

Testing this zone:

CustomTimeZone customZone = new CustomTimeZone("Custom");
// date in DST (between March and October)
DateTime d = new DateTime(2013, 4, 20, 0, 0, 0, 0, customZone);
System.out.println(d); // 2013-04-20T00:00:00.000+01:00

// one minute before DST starts - offset is zero ("Z")
d = new DateTime(2013, 3, 26, 23, 59, 0, 0, customZone);
System.out.println(d); // 2013-03-26T23:59:00.000Z
// add 1 minute - DST starts and offset changes to +01:00 (clock moves 1 hour forward to 1 AM)
System.out.println(d.plusMinutes(1)); // 2013-03-27T01:00:00.000+01:00

// one minute before DST ends - offset is +01:00
d = new DateTime(1383173940000L, customZone);
System.out.println(d); // 2013-10-30T23:59:00.000+01:00
// add 1 minute - DST starts and offset changes to zero ("Z") (clock moves 1 hour back to 23 PM)
System.out.println(d.plusMinutes(1)); // 2013-10-30T23:00:00.000Z

I've created just a simple case with just one DST transition, but you can make the class as complex as you want, storing all the DST changes you need and adjusting the start and end dates (and the offsets as well) accordingly.