Получение всех дат в указанном диапазоне после перехода на летнее время в Java - PullRequest
0 голосов
/ 23 октября 2019

У меня есть временной диапазон, для которого время начала и окончания указаны в UTC.

Местное время остается неизменным для всех дней в диапазоне дат. Вот почему, если дата окончания наступает после окончания перехода на летнее время, дата UTC изменяется на 1 час. то есть предположим, что начальная дата - 10/23, а конечная дата - 11/11 в 2 часа утра по тихоокеанскому времени. Таким образом, диапазон, который я имею в UTC, становится с 10/23 09:00 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

Но с 03 ноября я пытаюсь получить 12:30, поскольку время в местном часовом поясе остается неизменным. Я пытаюсь добиться того времени, чтобы время в местном часовом поясе было постоянным. т.е. до 02 ноября 11:30 UTC конвертируется в 4:30 PST. После завершения перехода на летнее время время в местном часовом поясе останется прежним. Поэтому в UTC я пытаюсь получить 12:30 после окончания летнего времени.

1 Ответ

0 голосов
/ 24 октября 2019

ZonedDateTime от java.time

Я думаю, что элегантное решение использует java.time, современный Java-интерфейс даты и времени. Вы можете думать об этом как о преемнике библиотеки Joda-Time, которую вы использовали. Нам нужен класс ZonedDateTime из java.time.

    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:30 до 12:30 с 3 ноября.

Если вы хотите, чтобы вывод был отформатирован, как в вашем вопросе:

    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 по двум причинам. Во-первых, проект Joda-Time находится в режиме обслуживания, и для нового кода вы должны предпочесть java.time. Во-вторых, я не очень разбираюсь в Joda-Time, поэтому моё решение может быть не самым элегантным из возможных. Я не нашел Joda-Time эквивалента ZonedDateTime, поэтому я использую его 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

При любых обстоятельствах избегайте плохо спроектированных и давно устаревших классов Date и SimpleDateFormat. Единственное исключение - если вам нужен устаревший объект Date для устаревшего API, который вы не можете позволить себе обновить прямо сейчас. В этом случае преобразуйте непосредственно перед вызовом в этот устаревший API.

Ссылка

...