Java Дата Время Начало и конец дня без какой-либо информации о часовом поясе - PullRequest
0 голосов
/ 28 июня 2019

У меня есть две строки, как startDate и endDate. Они имеют такие значения, как, например:

startDate="2019-09-29T06:00:00.000Z"
endDate="2019-10-06T05:59:59.999Z"

Теперь давайте скажем, что они указаны в Mountain Time как начало дня для startDate и Конец дня для endDate. Но так как это строки, как я могу заставить программу понять, что они могут быть преобразованы в местное время в горах, например:

startDate="2019-09-29T00:00:00.000Z"
endDate="2019-10-05T11:59:59.999Z"

И часовой пояс динамический. Я могу получить строку с меткой времени из восточного времени или любого другого часового пояса.
UPDATE
Я понял, что должен добавить больше информации.
Так что время Moutain, которое я положил, является примером. Это может быть из восточного времени или любого другого часового пояса. Единственный факт, который знает этот метод, состоит в том, что startDate - это начало дня в некотором часовом поясе, а endDate - конец дня в этом часовом поясе. Я понимаю, что «Z» - это время UTC, но выяснение того, какой часовой пояс сгенерировал это время UTC в начале дня (startDate) и в конце дня (endDate) и преобразование обратно в соответствующее местное время, является проблемой, которую я Я сталкиваюсь.

Ответы [ 2 ]

4 голосов
/ 28 июня 2019

Z в конце - это информация о часовом поясе, что означает смещение 00:00 от UTC , он же Ноль, он же Зулу, поэтому сначала вы разбираете строку в типкоторый хранит дату, время и часовой пояс Z.

С Java 8 Time API это будет Instant, OffsetDateTime или ZonedDateTime.
ЕслиВаши входы всегда заканчиваются Z, а не каким-либо другим смещением, используйте Instant.

Затем вы конвертируете в нужный часовой пояс, который для горного времени США называется America/Denver.

Примеры

String startDate = "2019-09-29T06:00:00.000Z";
String endDate = "2019-10-06T05:59:59.999Z";
ZoneId zone = ZoneId.of("America/Denver");

System.out.println(Instant.parse(startDate).atZone(zone));
System.out.println(OffsetDateTime.parse(startDate).atZoneSameInstant(zone));
System.out.println(ZonedDateTime.parse(startDate).withZoneSameInstant(zone));

System.out.println(Instant.parse(endDate).atZone(zone));
System.out.println(OffsetDateTime.parse(endDate).atZoneSameInstant(zone));
System.out.println(ZonedDateTime.parse(endDate).withZoneSameInstant(zone));

Выход

2019-09-29T00:00-06:00[America/Denver]
2019-09-29T00:00-06:00[America/Denver]
2019-09-29T00:00-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]

Если вы не хотите сохранять часовой пояс после преобразования, вы можетеудалите его, вызвав toLocalDateTime(), например,

System.out.println(Instant.parse(endDate).atZone(zone).toLocalDateTime());

Выход

2019-10-05T23:59:59.999

Обратите внимание, что у него нет Z в конце.

0 голосов
/ 01 июля 2019

Я не мог держать пальцы подальше от этого, это весело.Насколько я понял, вы не знаете, из какого часового пояса идут начальная и конечная строки, это может быть любой часовой пояс.Что мы можем сделать, кроме как попробовать их все по очереди?

    String startDate = "2019-09-29T06:00:00.000Z";
    String endDate = "2019-10-06T05:59:59.999Z";

    LocalTime dayStart = LocalTime.MIN;
    LocalTime dayEndEarliset = LocalTime.of(23, 59, 59);

    Instant startInstant = Instant.parse(startDate);
    Instant endInstant = Instant.parse(endDate);
    // Just out of curiosity find candidate time zones
    Set<ZoneId> candidateZones = ZoneId.getAvailableZoneIds()
            .stream()
            .map(ZoneId::of)
            .filter(zid -> startInstant.atZone(zid).toLocalTime().equals(dayStart)
                    && ! endInstant.atZone(zid).toLocalTime().isBefore(dayEndEarliset))
            .collect(Collectors.toSet());
    System.out.println("Potential time zones: " + candidateZones);
    // Real work: find candidate date(s)
    Set<LocalDate> candidateDates = ZoneId.getAvailableZoneIds()
            .stream()
            .map(ZoneId::of)
            .filter(zid -> startInstant.atZone(zid).toLocalTime().equals(dayStart)
                    && ! endInstant.atZone(zid).toLocalTime().isBefore(dayEndEarliset))
            .map(zid -> startInstant.atZone(zid).toLocalDate())
            .collect(Collectors.toSet());
    if (candidateDates.isEmpty()) {
        System.out.println("Cannot identify a date from the instants");
    } else if (candidateDates.size() > 1) {
        System.out.println("Ambiguous date, candidates are " + candidateDates);
    } else {
        System.out.println("The date is " + candidateDates.iterator().next());
    }

Это печатает:

Potential time zones: [America/Inuvik, America/Yellowknife, America/Regina, America/Boise, SystemV/MST7MDT, America/El_Salvador, America/Costa_Rica, America/Shiprock, America/Guatemala, America/Denver, America/Belize, America/Swift_Current, America/Managua, Mexico/BajaSur, Canada/Mountain, America/Cambridge_Bay, Navajo, America/Chihuahua, America/Ojinaga, MST7MDT, Pacific/Galapagos, America/Mazatlan, US/Mountain, America/Edmonton, America/Tegucigalpa, Canada/Saskatchewan, Etc/GMT+6, SystemV/CST6]
The date is 2019-09-29

И да, Америка / Денвер входит в число возможных часовых поясов, как и ожидалось.Пока я нашел дату начала.Вы можете найти пару начальной и конечной даты аналогичным образом.Возможно, вы предпочтете старомодный цикл, а не потоковую операцию.

Однако дата не всегда будет однозначной.Давайте попробуем построить интервал в один день в часовом поясе Pacific / Pago_Pago.Это по смещению -11: 00.

    ZoneId zone = ZoneId.of("Pacific/Pago_Pago");
    LocalDate testDate = LocalDate.of(2019, Month.OCTOBER, 2);
    String startDate = testDate.atStartOfDay(zone).toInstant().toString();
    String endDate = testDate.atTime(LocalTime.of(23, 59, 59, 999_000_000))
            .atZone(zone)
            .toInstant()
            .toString();

Теперь вывод программы:

Potential time zones: [Antarctica/McMurdo, Pacific/Niue, Pacific/Samoa, Pacific/Tongatapu, Pacific/Enderbury, Etc/GMT+11, NZ, Antarctica/South_Pole, Etc/GMT-13, Pacific/Pago_Pago, Pacific/Midway, Pacific/Fakaofo, US/Samoa, Pacific/Auckland]
Ambiguous date, candidates are [2019-10-03, 2019-10-02]

Это потому, что существуют также часовые пояса со смещением +13: 00.Мы можем сказать, что смещение должно быть либо -11: 00, либо +13: 00, но мы не можем сказать, какое из двух.Таким образом, выходят две даты.

Используйте полуоткрытые интервалы для времени

Я не был уверен, будет ли конец всегда в 23: 59: 59,999 вчасовой пояс, о котором идет речь, а иногда возможно 23: 59: 59.999999 или что-то еще.Также независимо от того, сколько десятичных дробей мы добавим, теоретически будут существовать моменты, которые находятся после этого времени окончания, но все еще в пределах той же даты.В коде я консервативно принимаю что-нибудь с 23:59:59 и позже как время окончания.Точка, чтобы полностью избежать сомнения: Используйте полуоткрытый интервал .Представьте начало интервала как 00:00:00, как вы уже делаете, и конец как 00:00:00 в дате после последней даты.И считайте дату начала включительно, а конец - эксклюзив .

...