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

Pat*_*ick 52 java date java-8 java-time

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

假设我有这部分代码:

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

    LocalDate endDate = startDate.plusMonths(1);
    endDate = endDate.withDayOfMonth(endDate.lengthOfMonth());
}
Run Code Online (Sandbox Code Playgroud)

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

我想要得到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...
}
Run Code Online (Sandbox Code Playgroud)

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

ass*_*ias 66

假设您主要想迭代日期范围,那么创建一个DateRange可迭代的类是有意义的.那会让你写:

for (LocalDate d : DateRange.between(startDate, endDate)) ...
Run Code Online (Sandbox Code Playgroud)

就像是:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 它是一种在自己的类中拥有逻辑的干净方法.谢谢你指点我这个方向! (2认同)
  • `LongStream.rangeClosed(0, ChronoUnit.DAYS.between(startDate, endDate)) .mapToObj(startDate::plusDays)`... (2认同)

Flo*_*own 65

首先,您可以使用a TemporalAdjuster来获取该月的最后一天.接下来,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);
Run Code Online (Sandbox Code Playgroud)

  • @Patrick你没有说明结果应该是什么样子,这只是一个假设.您也不必存储结果,而是可以使用[`Stream :: forEach`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream. html#forEach-java.util.function.Consumer-)来处理结果. (2认同)
  • 它应该是`.limit(ChronoUnit.DAYS.between(start,end)+ 1)`以包含每个月的最后一天. (2认同)

Dur*_*ngh 28

Java 9

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

List<LocalDate> dates = startDate.datesUntil(endDate).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 需要注意的是,`datesUntil` 是独占的。 (3认同)

N.J*_*son 9

您可以使用.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);
}
Run Code Online (Sandbox Code Playgroud)

产量

2016-07-05
2016-07-06
...
2016-08-04
2016-08-05
Run Code Online (Sandbox Code Playgroud)

这里的例子

  • 如上所述,`for`循环是此用例的预期语法结构.具有良好定义的初始值,条件和增量模式使代码清晰.无论循环体的大小如何,这三个相关的东西也总是在一起.在`while`循环中,没有办法区分循环增量操作,通常是在结尾处的某个地方,以及循环体内的实际操作,此外,循环变量必须在循环外声明,产生于范围大于预期. (4认同)
  • 好吧,注释中没有格式化会使每个重要的代码片段难以阅读. (2认同)

Bas*_*que 7

tl;博士

使用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.
Run Code Online (Sandbox Code Playgroud)

[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::datesUntil 溪流

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

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

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate today = LocalDate.now( z ) ;
Run Code Online (Sandbox Code Playgroud)

确定您的结束日期。

LocalDate stop = today.plusMonths( 1 ) ;
Run Code Online (Sandbox Code Playgroud)

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

Stream< LocalDate > stream = today.datesUntil( today.plusMonths( 1 ) );
Run Code Online (Sandbox Code Playgroud)

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

List< LocalDate > datesForMonthFromToday = stream.collect( Collectors.toList() );
Run Code Online (Sandbox Code Playgroud)

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

System.out.println( datesForMonthFromToday );
Run Code Online (Sandbox Code Playgroud)

关于java.time

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

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

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

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

从哪里获得 java.time 类?

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


Tod*_*odd 6

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

用你的例子......

LocalDateStream
    .from(LocalDate.now())
    .to(1, ChronoUnit.MONTHS)
    .stream()
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

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