首页 / 知识

关于java:确定日期的夏令时的算法?

2023-04-15 20:24:00

关于java:确定日期的夏令时的算法?

Algorithm to determine Daylight Saving Time of a date?

最初,我在Actionscript中寻找解决方案。 这个问题的关键是算法,当时钟必须切换夏令时时,它会检测确切的分钟。

因此,例如在10月25日至10月31日之间,我们必须检查一下,如果实际日期是星期天,则是在2点之前或之后...


没有真正的算法来处理夏时制。 基本上,每个国家/地区都可以自行决定DST的开始时间和结束时间。 作为开发人员,我们唯一能做的就是使用某种表进行查找。 大多数计算机语言都在语言中集成了这样的表格。

在Java中,可以使用TimeZone类的inDaylightTime方法。 如果您想知道DST在特定年份开始或结束的确切日期和时间,我建议使用Joda Time。 我看不出仅使用标准库就能找到答案的干净方法。

下面的程序是一个示例:(请注意,如果某个时区在某年没有DST,它可能会产生意外结果)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()));
    }
}

Richters的答案是正确的,应该接受。

正如Richters所指出的,夏令时(DST)或其他异常情况没有逻辑。政治家任意重新定义其时区中使用的UTC偏移量。他们做出这些改变的时候常常没有什么预警,甚至完全没有警告,就像朝鲜几周前所做的那样。

java.time

这里有一些进一步的想法,以及使用现代java.time类的示例代码,该类继他的Answer中显示的Joda-Time类之后。

ICANN维护的列表tzdata(以前称为Olson数据库)中跟踪了这些更改。您的Java实现,主机操作系统和数据库系统都可能拥有该数据的自己的副本,当更改为您关心的区域的模式时,必须根据需要替换这些副本。这些更改没有逻辑,因此无法以编程方式预测这些更改。您的代码必须调用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...

实际上,您无需确定转换点。一个好的日期时间库会自动为您处理。

Java具有最好的此类库,即业界领先的java.time类。当您要求某个地区(时区)中某个日期的日期时,如果该日期时间无效,则会自动进行调整。阅读ZonedDateTime的文档以了解该调整中使用的算法。

1
2
3
4
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 );

请注意,结果是3 AM,而不是请求的2 AM。该日期当天该区域没有凌晨2点。因此,java.time调整为凌晨3点,因为时钟"提前"了一个小时。

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

如果您需要研究为时区定义的规则,请使用ZoneRules类。

获取当前时刻使用的DST偏移量。

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

获取下一个计划的更改,以ZoneOffsetTransition对象表示。

1
2
3
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

continent/region格式指定正确的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

  • Java SE 8,Java SE 9,Java SE 10和更高版本

    • 内置的
    • 标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
  • Java SE 6和Java SE 7

    • java.time的许多功能在ThreeTen-Backport中都被反向移植到Java 6和7。
  • 安卓系统

    • 更高版本的Android捆绑了java.time类的实现。
    • 对于早期的Android(<26),ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP…。

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter等。


算法日期解决方案时钟

最新内容

相关内容

猜你喜欢