Algorithm to determine Daylight Saving Time of a d

2019-04-12 17:27发布

问题:

Originally I am looking for a solution in Actionscript. The point of this question is the algorithm, which detects the exact Minute, when a clock has to switch the Daylight Saving Time.

So for example between the 25th and the 31th of October we have to check, if the actual date is a sunday, it is before or after 2 o'clock...

回答1:

There is no real algorithm for dealing with Daylight Saving Time. Basically every country can decide for themselves when -and if- DST starts and ends. The only thing we can do as developers is using some sort of table to look it up. Most computer languages integrate such a table in the language.

In Java you could use the inDaylightTime method of the TimeZone class. If you want to know the exact date and time when DST starts or ends in a certain year, I would recommend to use Joda Time. I can't see a clean way of finding this out using just the standard libraries.

The following program is an example: (Note that it could give unexpected results if a certain time zone does not have DST for a certain year)

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

public class App {
    public static void main(String[] args) {
        DateTimeZone dtz = DateTimeZone.forID("Europe/Amsterdam");

        System.out.println(startDST(dtz, 2008));
        System.out.println(endDST(dtz, 2008));
    }

    public static DateTime startDST(DateTimeZone zone, int year) {
        return new DateTime(zone.nextTransition(new DateTime(year, 1, 1, 0, 0, 0, 0, zone).getMillis()));
    }

    public static DateTime endDST(DateTimeZone zone, int year) {
        return new DateTime(zone.previousTransition(new DateTime(year + 1, 1, 1, 0, 0, 0, 0, zone).getMillis()));
    }
}


回答2:

The Answer by Richters is correct and should be accepted.

As Richters noted, there is no logic to Daylight Saving Time (DST) or other anomalies. Politicians arbitrarily redefine the offset-from-UTC used in their time zones. They make these changes often with little forewarning, or even no warning at all as North Korea did a few weeks ago.

java.time

Here are some further thoughts, and example code using the modern java.time classes that succeeded the Joda-Time classes shown in his Answer.

These changes are tracked in a list maintained by ICANN, known as tzdata, formerly known as the Olson Database. Your Java implementation, host operating system, and database system likely all have their own copies of this data which must be replaced as needed when changes are mode to zones you care about. There is no logic to these changes, so there is no way to predict the changes programmatically. Your code must call upon a fresh copy of tzdata.

So for example between the 25th and the 31th of October we have to check, if the actual date is a sunday, it is before or after 2 o'clock...

Actually, you need not determine the point of the cut-over. A good date-time library handles that for you automatically.

Java has the best such library, the industry-leading java.time classes. When you ask for a time-of-day on a certain date in a certain region (time zone), if that time-of-day is no valid an adjustment is made automatically. Read the documentation for the ZonedDateTime to understand the algorithm used in that adjustment.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2018 , Month.MARCH , 11 );  // 2018-03-11.
LocalTime lt = LocalTime.of( 2 , 0 );  // 2 AM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );

Notice the result is 3 AM rather than the 2 AM requested. There was no 2 AM on that date in that zone. So java.time adjusted to 3 AM as the clock “Springs ahead” an hour.

zdt.toString(): 2018-03-11T03:00-04:00[America/Montreal]

If you feel the need to investigate the rules defined for a time zone, use the ZoneRules class.

Get the amount of DST shift used in the present moment.

Duration d = z.getRules().getDaylightSavings​( Instant.now() ) ;

Get the next planned change, represented as a ZoneOffsetTransition object.

ZoneId z = ZoneId.of( "America/Montreal" );
ZoneOffsetTransition t = z.getRules().nextTransition( Instant.now() );
String output = "For zone: " + z + ", on " + t.getDateTimeBefore() + " duration change: " + t.getDuration() + " to " + t.getDateTimeAfter();

For zone: America/Montreal, on 2018-11-04T02:00 duration change: PT-1H to 2018-11-04T01:00

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

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

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.