简体   繁体   English

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

[英]There are two dates. How to create a list of the intervals of months between these dates?

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

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

  • java.util.Date end = 20.03.2018 00:00 java.util.Date结束= 20.03.2018 00:00

I want to create java.util.List<MonthInterval> list like: 我想创建java.util.List<MonthInterval> list例如:

  • 21.01.2018 00:00 — 01.02.2018 00:00 (or 31.01.2018 23:59:59) 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.02.2018 00:00 — 01.03.2018 00:00
  • 01.03.2018 00:00 — 20.03.2018 00:00 01.03.2018 00:00 — 20.03.2018 00:00

My Class: 我的课:

class MonthInterval {
    Date monthBegin, monthEnd;
}

I tried to do it myself. 我自己尝试过。 However, in the class java.util.Calendar I did not understand how to calculate the number of days in this or another month for this year. 但是,在类java.util.Calendar我不了解如何计算今年这个月或另一个月的天数。 But I think I went the wrong way. 但是我想我走错了路。 Any ideas? 有任何想法吗?

You should really use java.time API, there is some interesting stuff, using 您应该真正使用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);
    }
}

You can do different ways, like 您可以采取不同的方式,例如

  1. With do-while loop 使用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. With for-i loop 使用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; } 

To use as 用作

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

tl;dr 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.

Avoid legacy date-time classes 避免使用旧的日期时间类

Never use java.util.Date . 永远不要使用java.util.Date That awful class was supplanted years ago by the modern java.time classes. 可怕的类在几年前被现代的java.time类所取代。

ThreeTen-Extra 三人行

The other Answer by azro is headed in the right direction. Azro另一个答案朝着正确的方向前进。 But there is no need to invent your own interval class. 但是,您无需发明自己的间隔类。 Look to the existing tried-and-true classes found in the ThreeTen-Extra project. 查看在ThreeTen-Extra项目中找到的现有可靠的类。 That project is led by the same man, Stephen Colebourne, who led the JSR 310 java.time project and the Joda-Time project. 该项目由同一人Stephen Colebourne领导,后者负责JSR 310 java.time项目和Joda-Time项目。

In the ThreeTen-Extra library you will find two class to represent a span-of-time attached to the timeline. ThreeTen-Extra库中,您将找到两个类来表示附加到时间轴上的时间跨度。

  • Interval — A pair of moments in UTC, Instant objects. Interval — UTC中的一对瞬间, Instant对象。
  • LocalDateRange — A pair of date-only values, LocalDate objects. LocalDateRange —一对仅日期的值, LocalDate对象。

Moments 片刻

If you meant moments, parse your input strings at LocalDateTime objects. 如果您需要片刻,请在LocalDateTime对象处解析输入字符串。 This are not moments, only potential moments, as they lack a time zone or offset-from-UTC. 不是时刻, 而是潜在的时刻,因为它们缺少时区或UTC偏移。

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

Give those LocalDateTime real meaning by assigning a time zone to determine actual moment. 通过分配时区来确定实际时刻,使这些LocalDateTime真正具有含义。

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

Adjust into UTC by extracting Instant . 通过提取Instant适应UTC。 An Instant represents a moment always in UTC. Instant表示始终以UTC表示的时刻。

Instant instant = zdt.toInstant() ;

Pass a pair of such Instant objects to get an Interval . 传递一对这样的Instant对象以获取Interval

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

You can compare Interval objects with handy methods such as isBefore , isAfter , overlaps , contains , encloses , and so on. 你可以比较Interval与方便的方法,如对象isBeforeisAfteroverlapscontainsencloses ,等等。

Dates 日期

If you are focusing only on dates rather than moments, then use LocalDateRange . 如果您只关注日期而不是时间,请使用LocalDateRange We must still process your inputs as seen above, as the date varies around the globe for any given moment. 我们仍然必须如上所述处理您的输入,因为任何给定时刻的日期在全球范围内都不同。 For example, a few minutes after midnight in Paris France is “tomorrow” while still “yesterday” in Montréal Québec. 例如,法国巴黎午夜后的几分钟是“明天”,而在蒙特利尔魁北克仍然是“昨天”。

For the dates, take the ZonedDateTime objects seen above and extract a LocalDate . 对于日期,请使用ZonedDateTime看到的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).

Make a LocalDateRange with such dates 用这样的日期制作一个LocalDateRange

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

Like Interval , the LocalDateRange class offers handy comparison methods such as overlaps , contains , etc. Interval一样, LocalDateRange类提供了方便的比较方法,例如overlapscontains等。

Half-Open 半开

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

No, do not define a span-of-time by its last possible moment. 不可以,请不要在最后可能的时刻之前定义时间范围。 That is awkward and problematic. 那是尴尬和成问题的。 One problem is an infinitely divisible fractional second. 一个问题是无限可分的小数秒。

Instead, use Half-Open method: the beginning is inclusive , while the ending is exclusive . 相反,请使用Half-Open方法:开始是包含的 ,而结尾是排他的

Search Stack Overflow for much more info. 搜索堆栈溢出以获取更多信息。


About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. 现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参见Oracle教程 And search Stack Overflow for many examples and explanations. 并在Stack Overflow中搜索许多示例和说明。 Specification is JSR 310 . 规格为JSR 310

You may exchange java.time objects directly with your database. 您可以直接与数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later. 使用与JDBC 4.2或更高版本兼容的JDBC驱动程序 No need for strings, no need for java.sql.* classes. 不需要字符串,不需要java.sql.*类。

Where to obtain the java.time classes? 在哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目为将来可能在java.time中添加内容提供了一个试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM