在 java 夏令时后获取给定范围内的所有日期

Getting all the dates in the given range after daylight time saving in java

我有一个时间范围,其开始时间和结束时间都是 UTC。

本地时间在日期范围内的所有日期都保持不变。这就是为什么如果结束日期在夏令时结束之后,UTC 日期将更改 1 小时。即假设开始日期是 10 月 23 日,结束日期是 11 月 11 日凌晨 2 点 US/pacific。所以我在 UTC 中的范围变成 10/23 09:00 AM UTC 到 11/11 10:00 AM UTC。

我想获取 UTC 时间范围内的所有日期。如果我继续从开始日期开始添加一天,在夏令时之后,UTC 时间将保持不变,这就是为什么当地时间将关闭 1 小时。即在上面的示例中,如果我在夏令时后继续从 10/23 09:00 添加一天,我将收到的日期是 (11/03 09:00 UTC),(11/04 09:00 UTC), (11/05 09 UTC) 等等。太平洋标准时间 01:00 上午。 java 中是否有任何方法可以在时间范围内获取日期时间,以便在 11/02 之前我将获得“11/02 09:00 UTC”,从 11/03 开始​​我将获得“11/ 03 10:00 UTC"?

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class MyClass {
    public static void main(String args[]) throws Exception{
      String date1 = "Wed Oct 23 11:30:00 GMT 2019";
      String date2 = "Mon Nov 04 12:30:00 GMT 2019";
      convert(date1, date2);
    }

    private static void convert(String date1, String date2) throws Exception{
        SimpleDateFormat localDateFormat = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy");

        DateTimeFormatter formatter = DateTimeFormat.forPattern("E MMM dd HH:mm:ss z yyyy");

        DateTime sDate = formatter.parseDateTime(date1);
        DateTime eDate = formatter.parseDateTime(date2);
        while(eDate.isAfter(sDate) || eDate.equals(sDate)) {
            Date finaldate = sDate.toDate();
            System.out.println(localDateFormat.format(finaldate));
            sDate = sDate.plusDays(1);
        }
    }
}

以下代码的输出是:

Thu Oct 24 11:30:00 GMT 2019
Fri Oct 25 11:30:00 GMT 2019
Sat Oct 26 11:30:00 GMT 2019
Sun Oct 27 11:30:00 GMT 2019
Mon Oct 28 11:30:00 GMT 2019
Tue Oct 29 11:30:00 GMT 2019
Wed Oct 30 11:30:00 GMT 2019
Thu Oct 31 11:30:00 GMT 2019
Fri Nov 01 11:30:00 GMT 2019
Sat Nov 02 11:30:00 GMT 2019
Sun Nov 03 11:30:00 GMT 2019
Mon Nov 04 11:30:00 GMT 2019

但是从 11 月 3 日开始,我试图获取 12:30,因为本地时区的时间保持不变。我试图实现的是时间,以便本地时区的时间保持不变。即到 11 月 2 日,11:30 UTC 转换为 4:30 PST。夏令时结束后,当地时区时间将保持不变。所以在 UTC 中,我试图在夏令时结束后获得 12:30。

ZonedDateTime 来自 java.time

我认为优雅的解决方案使用 java.time,现代 Java 日期和时间 API。您可能会认为它是您使用的 Joda-Time 库的继承者。我们需要的是 java.time.

中的 ZonedDateTime class
    ZoneId zone = ZoneId.of("America/Los_Angeles");
    DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);

    String date1 = "Wed Oct 23 11:30:00 GMT 2019";
    String date2 = "Mon Nov 04 12:30:00 GMT 2019";

    ZonedDateTime startDateTime = ZonedDateTime.parse(date1, formatter)
            .withZoneSameInstant(zone);
    ZonedDateTime endDateTime = ZonedDateTime.parse(date2, formatter)
            .withZoneSameInstant(zone);
    while (! startDateTime.isAfter(endDateTime)) {
        Instant gmt = startDateTime.toInstant();
        System.out.println(startDateTime + "  GMT: " + gmt);
        startDateTime = startDateTime.plusDays(1);
    }

此片段的输出是:

2019-10-23T04:30-07:00[America/Los_Angeles]  GMT: 2019-10-23T11:30:00Z
2019-10-24T04:30-07:00[America/Los_Angeles]  GMT: 2019-10-24T11:30:00Z
2019-10-25T04:30-07:00[America/Los_Angeles]  GMT: 2019-10-25T11:30:00Z
… (cut) …
2019-11-01T04:30-07:00[America/Los_Angeles]  GMT: 2019-11-01T11:30:00Z
2019-11-02T04:30-07:00[America/Los_Angeles]  GMT: 2019-11-02T11:30:00Z
2019-11-03T04:30-08:00[America/Los_Angeles]  GMT: 2019-11-03T12:30:00Z
2019-11-04T04:30-08:00[America/Los_Angeles]  GMT: 2019-11-04T12:30:00Z

您看到 GMT 时间从 11 月 3 日起从 11:30 变为 12:30。

如果您希望按照您的问题格式化输出:

    ZoneId gmtZone = ZoneId.of("Etc/GMT");
    while (! startDateTime.isAfter(endDateTime)) {
        ZonedDateTime gmtTime = startDateTime.withZoneSameInstant(gmtZone);
        System.out.println(gmtTime.format(formatter));
        startDateTime = startDateTime.plusDays(1);
    }
Wed Oct 23 11:30:00 GMT 2019
Thu Oct 24 11:30:00 GMT 2019
… (cut) …
Sun Nov 03 12:30:00 GMT 2019
Mon Nov 04 12:30:00 GMT 2019

乔达时间

出于两个原因,我对提出 Joda-Time 解决方案犹豫不决。第一,Joda-Time 项目处于维护模式,对于新代码,您应该更喜欢 java.time。第二,我不太精通 Joda-Time,所以我的解决方案可能不是最优雅的。我没有发现 ZonedDateTime 的 Joda-Time 等价物,所以我使用它的 LocalDateTime,这都需要更多的转换并且更脆弱,因为 datetime 对象不知道它自己的时区。

    DateTimeZone.setDefault(DateTimeZone.forID("Etc/GMT"));

    DateTimeZone zone = DateTimeZone.forID("America/Los_Angeles");
    DateTimeZone gmtZone = DateTimeZone.forID("Etc/GMT");
    DateTimeFormatter formatter
            = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss zzz yyyy")
                    .withLocale(Locale.ROOT);

    String date1 = "Wed Oct 23 11:30:00 GMT 2019";
    String date2 = "Mon Nov 04 12:30:00 GMT 2019";

    LocalDateTime sDate = formatter.parseDateTime(date1)
            .withZone(zone)
            .toLocalDateTime();
    LocalDateTime eDate = formatter.parseDateTime(date2)
            .withZone(zone)
            .toLocalDateTime();
    while(eDate.isAfter(sDate) || eDate.equals(sDate)) {
        DateTime finaldate = sDate.toDateTime(zone).withZone(gmtZone);
        System.out.println(finaldate.toString(formatter));
        sDate = sDate.plusDays(1);
    }
Wed Oct 23 11:30:00 GMT 2019
Thu Oct 24 11:30:00 GMT 2019
… (cut) …
Sat Nov 02 11:30:00 GMT 2019
Sun Nov 03 12:30:00 GMT 2019
Mon Nov 04 12:30:00 GMT 2019

在任何情况下都应避免使用设计不佳且早已过时的 DateSimpleDateFormat classes。唯一的例外是,如果您需要一个老式的 Date 对象用于遗留 API,而您现在无力升级。在这种情况下,就在调用旧版 API.

之前进行转换

Link