有两个日期。如何创建这些日期之间每月间隔的列表?

时间:2019-01-16 22:02:08

标签: java list date collections calendar

示例(如“ dd.MM.yyyy HH:mm”)。

  • java.util.Date开始= 21.01.2018 00:00

  • java.util.Date结束= 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 :(得分:1)

您应该真正使用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

答案 1 :(得分:1)

tl; dr

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

other Answer by azro朝着正确的方向前进。但是,您无需发明自己的间隔类。查看在ThreeTen-Extra项目中找到的现有的经过验证的类。该项目由同一人Stephen Colebourne领导,他领导了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 ) ;

通过提取Instant调整为UTC。 Instant代表时刻始终是UTC。

Instant instant = zdt.toInstant() ;

传递一对这样的Instant对象以获得Interval

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

您可以将Interval对象与方便的方法进行比较,例如isBeforeisAfteroverlapscontainsencloses

日期

如果您只关注日期而不是时间,请使用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 ) ;

类似于IntervalLocalDateRange类提供了方便的比较方法,例如overlapscontains等。

半开放

  

21.01.2018 00:00-01.02.2018 00:00(或31.01.2018 23:59:59)

否,请不要在最后可能的时刻之前定义时间范围。那是尴尬和成问题的。一个问题是无限可分的小数秒。

相反,请使用 Half-Open 方法:开头是 inclusive ,而结尾是 exclusive

Search Stack Overflow了解更多信息。


关于 java.time

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

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

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

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

在哪里获取java.time类?

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