Java 8 LocalDate - 如何获取两个日期之间的所有日期?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38220543/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:06:24  来源:igfitidea点击:

Java 8 LocalDate - How do I get all dates between two dates?

javadatejava-8java-time

提问by Patrick

Is there a usablility to get all dates between two datesin the new java.timeAPI?

是否可以在新java.timeAPI 中获取两个日期之间的所有日期

Let's say I have this part of code:

假设我有这部分代码:

@Test
public void testGenerateChartCalendarData() {
    LocalDate startDate = LocalDate.now();

    LocalDate endDate = startDate.plusMonths(1);
    endDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
}

Now I need all dates between startDateand endDate.

现在我需要startDate和之间的所有日期endDate

I was thinking to get the daysBetweenof the two dates and iterate over:

我正在考虑获取daysBetween两个日期中的一个并迭代:

long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);

for(int i = 0; i <= daysBetween; i++){
    startDate.plusDays(i); //...do the stuff with the new date...
}

Is there a better way to get the dates?

有没有更好的方法来获取日期?

采纳答案by assylias

Assuming you mainly want to iterate over the date range, it would make sense to create a DateRangeclass that is iterable. That would allow you to write:

假设您主要想迭代日期范围,创建一个DateRange可迭代的类是有意义的。这将允许你写:

for (LocalDate d : DateRange.between(startDate, endDate)) ...

Something like:

就像是:

public class DateRange implements Iterable<LocalDate> {

  private final LocalDate startDate;
  private final LocalDate endDate;

  public DateRange(LocalDate startDate, LocalDate endDate) {
    //check that range is valid (null, start < end)
    this.startDate = startDate;
    this.endDate = endDate;
  }

  @Override
  public Iterator<LocalDate> iterator() {
    return stream().iterator();
  }

  public Stream<LocalDate> stream() {
    return Stream.iterate(startDate, d -> d.plusDays(1))
                 .limit(ChronoUnit.DAYS.between(startDate, endDate) + 1);
  }

  public List<LocalDate> toList() { //could also be built from the stream() method
    List<LocalDate> dates = new ArrayList<> ();
    for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) {
      dates.add(d);
    }
    return dates;
  }
}

It would make sense to add equals & hashcode methods, getters, maybe have a static factory + private constructor to match the coding style of the Java time API etc.

添加 equals 和 hashcode 方法、getter、可能有一个静态工厂 + 私有构造函数来匹配 Java 时间 API 等的编码风格是有意义的。

回答by N.J.Dawson

You can use the .isAfter and .plusDays to do this over a loop. I would not say betteras I haven't done a huge amount of research into the topic but I can confidently say it uses the Java 8 API and is a slightalternative.

您可以使用 .isAfter 和 .plusDays 在循环中执行此操作。我不会说更好,因为我没有对该主题进行大量研究,但我可以自信地说它使用 Java 8 API 并且是一个轻微的替代方案。

LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
while (!startDate.isAfter(endDate)) {
 System.out.println(startDate);
 startDate = startDate.plusDays(1);
}

Output

输出

2016-07-05
2016-07-06
...
2016-08-04
2016-08-05

Example Here

示例在这里

回答by Flown

First you can use a TemporalAdjusterto get the last day of the month. Next the StreamAPI offers Stream::iteratewhich is the right tool for your problem.

首先,您可以使用 aTemporalAdjuster来获取该月的最后一天。接下来,StreamAPI 提供Stream::iterate了适合您问题的工具。

LocalDate start = LocalDate.now();
LocalDate end = LocalDate.now().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
List<LocalDate> dates = Stream.iterate(start, date -> date.plusDays(1))
    .limit(ChronoUnit.DAYS.between(start, end))
    .collect(Collectors.toList());
System.out.println(dates.size());
System.out.println(dates);

回答by Todd

You could create a streamof LocalDateobjects. I had this problem too and I published my solution as java-timestream on github.

您可以创建一个streamLocalDate对象。我也有这个问题,我在 github 上java-timestream 的形式发布了我的解决方案

Using your example...

用你的例子...

LocalDateStream
    .from(LocalDate.now())
    .to(1, ChronoUnit.MONTHS)
    .stream()
    .collect(Collectors.toList());

It's more or less equivalent to other solutions proposed here, but it takes care of all of the date math and knowing when to stop. You can provide specific or relative end dates, and tell it how much time to skip each iteration (the default above is one day).

它或多或少等同于此处提出的其他解决方案,但它会处理所有日期数学并知道何时停止。您可以提供特定的或相对的结束日期,并告诉它跳过每次迭代的时间(上面的默认值是一天)。

回答by Meno Hochschild

In my time library Time4J, I have written an optimized spliterator to construct a stream of calendar dates with good parallelization characteristics. Adapted to your use-case:

在我的时间库Time4J 中,我编写了一个优化的拆分器来构造具有良好并行化特性的日历日期流。适应您的用例:

LocalDate start = ...;
LocalDate end = ...;

Stream<LocalDate> stream = 
  DateInterval.between(start, end) // closed interval, else use .withOpenEnd()
    .streamDaily()
    .map(PlainDate::toTemporalAccessor);

This short approach can be an interesting start point if you are also interested in related features like clock intervals per calendar date (partitioned streams) or other interval features and want to avoid awkward hand-written code, see also the API of DateInterval.

如果您还对每个日历日期的时钟间隔(分区流)或其他间隔功能等相关功能感兴趣,并希望避免笨拙的手写代码,则这种简短的方法可能是一个有趣的起点,另请参阅DateInterval的 API 。

回答by Durgpal Singh

Java 9

爪哇 9

In Java 9, the LocalDateclass was enhanced with the LocalDate.datesUntil(LocalDate endExclusive)method, which returns all dates within a range of dates as a Stream<LocalDate>.

在 Java 9 中,LocalDate该类使用LocalDate.datesUntil(LocalDate endExclusive)方法进行了增强,该方法将日期范围内的所有日期作为Stream<LocalDate>.

List<LocalDate> dates = startDate.datesUntil(endDate).collect(Collectors.toList());

回答by M. Justin

The ThreeTen-Extralibrary has a LocalDateRangeclass that can do exactly what you're requesting:

ThreeTen-EXTRA库有LocalDateRange类,它可以做的正是你的要求是什么:

LocalDateRange.ofClosed(startDate, endDate).stream()
        .forEach(/* ...do the stuff with the new date... */);

回答by Basil Bourque

tl;dr

tl;博士

Expanding on the good Answer by Singh, using a stream from datesUntilin Java 9 and later.

使用Java 9 及更高版本中的流扩展Singh的好答案datesUntil

today                                 // Determine your beginning `LocalDate` object.
.datesUntil(                          // Generate stream of `LocalDate` objects.
    today.plusMonths( 1 )             // Calculate your ending date, and ask for a stream of dates till then.
)                                     // Returns the stream.
.collect( Collectors.toList() )       // Collect your resulting dates in a `List`. 
.toString()                           // Generate text representing your found dates.

[2018-09-20, 2018-09-21, 2018-09-22, 2018-09-23, 2018-09-24, 2018-09-25, 2018-09-26, 2018-09-27, 2018-09-28, 2018-09-29, 2018-09-30, 2018-10-01, 2018-10-02, 2018-10-03, 2018-10-04, 2018-10-05, 2018-10-06, 2018-10-07, 2018-10-08, 2018-10-09, 2018-10-10, 2018-10-11, 2018-10-12, 2018-10-13, 2018-10-14, 2018-10-15, 2018-10-16, 2018-10-17, 2018-10-18, 2018-10-19]

[2018-09-20, 2018-09-21, 2018-09-22, 2018-09-23, 2018-09-24, 2018-09-25, 2018-09-26, 2018-09-28, 2018-09-27, -09-28、2018-09-29、2018-09-30、2018-10-01、2018-10-02、2018-10-03、2018-10-04、2018-10-05、2018-01 -06, 2018-10-07, 2018-10-08, 2018-10-09, 2018-10-10, 2018-10-11, 2018-10-12, 2018-10-13, 2018-10-10-10 , 2018-10-15, 2018-10-16, 2018-10-17, 2018-10-18, 2018-10-19]

LocalDate::datesUntilstream

LocalDate::datesUntil溪流

As of Java 9, you can ask for a stream of dates. Call LocalDate::datesUntil.

从 Java 9 开始,您可以请求日期流。打电话LocalDate::datesUntil

Start by determining today's date. That requires a time zone. For any given moment, the date varies around the globe by zone.

首先确定今天的日期。这需要一个时区。对于任何给定时刻,日期因地区而异。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate today = LocalDate.now( z ) ;

Determine your ending date.

确定您的结束日期。

LocalDate stop = today.plusMonths( 1 ) ;

Ask for stream of dates from beginning to ending.

要求从开始到结束的日期流。

Stream< LocalDate > stream = today.datesUntil( today.plusMonths( 1 ) );

Pull the dates from that stream, collecting them into a List.

从该流中提取日期,将它们收集到List.

List< LocalDate > datesForMonthFromToday = stream.collect( Collectors.toList() );

Print our list of dates, generating text in standard ISO 8601format.

打印我们的日期列表,以标准ISO 8601格式生成文本。

System.out.println( datesForMonthFromToday );


About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

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

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by M. Justin

You could use the Rangefunctionality in Google's Guavalibrary. After defining the DiscreteDomainover LocalDateinstances you could get a ContiguousSetof all dates in the range.

您可以使用Google 的Guava库中的Range功能。在实例上定义DiscreteDomain 后,您可以获得该范围内所有日期的ContiguousSetLocalDate

LocalDate d1 = LocalDate.parse("2017-12-25");
LocalDate d2 = LocalDate.parse("2018-01-05");

DiscreteDomain<LocalDate> localDateDomain = new DiscreteDomain<LocalDate>() {
    public LocalDate next(LocalDate value) { return value.plusDays(1); }
    public LocalDate previous(LocalDate value) { return value.minusDays(1); }
    public long distance(LocalDate start, LocalDate end) { return start.until(end, ChronoUnit.DAYS); }
    public LocalDate minValue() { return LocalDate.MIN; }
    public LocalDate maxValue() { return LocalDate.MAX; }
};

Set<LocalDate> datesInRange = ContiguousSet.create(Range.closed(d1, d2), localDateDomain);