Есть две даты. Как создать список интервалов месяцев между этими датами? - PullRequest
0 голосов
/ 17 января 2019

Пример (как «дд.мм.гггг ЧЧ: мм»).

  • java.util. Дата начала = 21.01.2018 00: 00

  • java.util. Дата окончания = 20.03.2018 00: 00

Я хочу создать java.util.List<MonthInterval> list как:

  • 21.01.2018 00:00 - 01.02.2018 00:00 (или 31.01.2018 23:59:59)
  • 01.02.2018 00:00 - 01.03.2018 00: 00
  • 01.03.2018 00:00 - 20.03.2018 00: 00

Мой класс:

class MonthInterval {
    Date monthBegin, monthEnd;
}

Я пытался сделать это сам. Однако в классе java.util.Calendar я не понимал, как рассчитать количество дней в этом или другом месяце для этого года. Но я думаю, что пошел не по тому пути. Есть идеи?

Ответы [ 2 ]

0 голосов
/ 17 января 2019

ТЛ; др

Interval.of(
    LocalDateTime.parse(                                    // Represent a date and a time-of-day but lacking a time zone or offset-from-UTC. So *not* a moment.
        "21.01.2018 00:00" ,
        DateTimeFormatter.ofPattern( "dd.MM.uuuu HH:mm" )   // Specify formatting pattern to match input strings.
    )                                                       // Returns a `LocalDateTime` object.
    .atZone(                                                // Apply a time zone to determine a moment.
        ZoneId.of( "Pacific/Auckland" )                     // Always use proper time zone in `Continent/Region` format, never 2-4 letter codes such as `IST` or `EST` or `PST`.
    )                                                       // Returns a `ZonedDateTime` object.
    .toInstant() ,                                          // Convert from a `ZonedDateTime` object to a `Instant` to adjust into UTC.
    …                                                       // Do the same as the above (the starting point) but for the stopping point.
)                                                           // Returns a `org.threeten.extra.Interval` object.
.toString()                                                 // Generate text representing both moments of this interval in standard ISO 8601 format, delimited by a `/` SOLIDUS character.

Избегайте устаревших классов даты и времени

Никогда не используйте java.util.Date. Этот ужасный класс был вытеснен несколько лет назад современными java.time классами.

ThreeTen-Extra

другой ответ от azro направлен в правильном направлении. Но нет необходимости изобретать свой собственный интервальный класс. Посмотрите на существующие испытанные классы, найденные в проекте ThreeTen-Extra . Этим проектом руководит тот же человек, Стивен Колебурн, который руководил проектом JSR 310 java.time и Joda-Time .

В библиотеке ThreeTen-Extra вы найдете два класса для представления промежутка времени, прикрепленного к временной шкале.

  • Interval - пара моментов в UTC, Instant объектов.
  • LocalDateRange - пара значений только для даты, LocalDate объектов.

Моменты

Если вы имели в виду моменты, проанализируйте свои входные строки в LocalDateTime объектах. Это не моментов, только потенциальные моменты, так как им не хватает часового пояса или смещения от UTC.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu HH:mm" ) ;
LocalDateTime ldt = LocalDateTime.parse( "21.01.2018 00:00" , f ) ;

Дайте этим LocalDateTime реальное значение, назначив часовой пояс для определения фактического момента.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

Настройте UTC, извлекая Instant. Instant представляет момент всегда в UTC.

Instant instant = zdt.toInstant() ;

Передайте пару таких Instant объектов, чтобы получить Interval.

org.threeten.extra.Interval interval = Interval.of( start , stop ) ;

Вы можете сравнивать Interval объекты с помощью таких удобных методов, как isBefore, isAfter, overlaps, contains, encloses и т. Д.

Дата

Если вы сосредотачиваетесь только на датах, а не на моментах, используйте LocalDateRange. Мы все еще должны обработать ваши входные данные, как показано выше, так как дата меняется по всему миру в любой данный момент. Например, через несколько минут после полуночи в Париже Франция - это «завтра», а еще «вчера» в Монреале-Квебеке.

Для дат возьмите ZonedDateTime объекты, показанные выше, и извлеките LocalDate.

LocalDate ld = zdt.toLocalDate() ;  // Extract the date as seen at that moment through the wall-clock time used by the people of that region (that time zone).

Сделать LocalDateRange с такими датами

org.threeten.extra.LocalDateRange ldr = LocalDateRange.of( start , stop ) ;

Как и Interval, класс LocalDateRange предлагает удобные методы сравнения, такие как overlaps, contains и т. Д.

Half-Open

21.01.2018 00:00 - 01.02.2018 00:00 (или 31.01.2018 23:59:59)

Нет, не определяйте промежуток времени по его последнему возможному моменту. Это неловко и проблематично. Одна проблема - это бесконечно делимая дробная секунда.

Вместо этого используйте метод Half-Open : начало включительно , а окончание exclusive .

Переполнение стека поиска для более подробной информации.


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 17 января 2019

Вы действительно должны использовать java.time API, есть некоторые интересные вещи, использующие

class MonthInterval {

    static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");

    LocalDateTime monthBegin, monthEnd;

    public MonthInterval(LocalDateTime monthBegin, LocalDateTime monthEnd) {
        this.monthBegin = monthBegin;
        this.monthEnd = monthEnd;
    }

    @Override
    public String toString() {
        return monthBegin.format(formatter) + " > " + monthEnd.format(formatter);
    }
}

Вы можете сделать по-разному, как

  1. С do-while loop

    static List<MonthInterval> list(LocalDateTime begin, LocalDateTime end) {
        List<MonthInterval> list = new ArrayList<>();
        LocalDateTime nextDayMonth;
        do {
            nextDayMonth = begin.plusMonths(1).withDayOfMonth(1);
            list.add(new MonthInterval(begin, nextDayMonth));
            begin = nextDayMonth;
        } while (nextDayMonth.getMonthValue() != end.getMonthValue());
        list.add(new MonthInterval(begin, end));
        return list;
    }
    
  2. С for-i петля

    static List<MonthInterval> list(LocalDateTime begin, LocalDateTime end) {
        List<MonthInterval> list = new ArrayList<>();
        LocalDateTime nextDayMonth;
        for (int i = 0; i < ChronoUnit.MONTHS.between(begin, end) + 1; i++) {
            nextDayMonth = begin.plusMonths(1).withDayOfMonth(1);
            list.add(new MonthInterval(begin, nextDayMonth));
            begin = nextDayMonth;
        }
        list.add(new MonthInterval(begin, end));
        return list;
    }
    

Использовать как

static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");

public static void main(String[] args) {
    LocalDateTime begin = LocalDateTime.parse("21.01.2018 00:00", formatter);
    LocalDateTime end = LocalDateTime.parse("20.03.2018 00:00", formatter);
    list(begin, end).forEach(System.out::println);
}

// And get
21.01.2018 00:00 > 01.02.2018 00:00
01.02.2018 00:00 > 01.03.2018 00:00
01.03.2018 00:00 > 20.03.2018 00:00
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...