簡體   English   中英

Java 8 LocalDate - 如何獲取兩個日期之間的所有日期?

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

是否可以在新的java.time API中獲取兩個日期之間的所有日期

假設我有這部分代碼:

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

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

現在我需要startDateendDate之間的所有日期。

我想要獲取兩個日期之間的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...
}

有更好的方法來獲取日期嗎?

假設您主要想迭代日期范圍,那么創建一個可迭代的DateRange類是有意義的。 那會讓你寫:

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

就像是:

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;
  }
}

添加equals和hashcode方法,getters,可能有一個靜態工廠+私有構造函數來匹配Java時間API的編碼風格等是有意義的。

首先,您可以使用TemporalAdjuster來獲取該月的最后一天。 接下來, Stream API提供了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);

Java 9

在Java 9中, LocalDate類使用LocalDate.datesUntil(LocalDate endExclusive)方法進行了增強,該方法以Stream<LocalDate>形式返回日期范圍內的所有日期。

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

您可以使用.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);
}

產量

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

這里的例子

您可以創建LocalDate對象stream 我也有這個問題,我在github上將我的解決方案發布為java-timestream。

用你的例子......

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

它或多或少等同於此處提出的其他解決方案,但它會處理所有日期數學並知道何時停止。 您可以提供特定或相對結束日期,並告訴它跳過每次迭代的時間(上面的默認值是一天)。

ThreeTen-Extra庫有一個LocalDateRange類,可以完全按照您的要求執行:

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

在我的Time4J時間庫中,我編寫了一個優化的spliterator來構建具有良好並行化特征的日歷日期流。 適應您的用例:

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

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

如果您還對每個日歷日期的時鍾間隔(分區流)或其他間隔功能等相關功能感興趣並希望避免使用笨拙的手寫代碼,則此簡短方法可能是一個有趣的起點,另請參閱DateInterval的API。

TL;博士

擴展了Singh的優秀答案 ,使用來自Java 9及更高版本的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,20188 -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-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]

LocalDate::datesUntil

從Java 9開始,您可以要求提供日期流。 調用LocalDate::datesUntil

首先確定今天的日期。 這需要一個時區。 對於任何給定的時刻,日期在全球范圍內因地區而異。

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

確定結束日期。

LocalDate stop = today.plusMonths( 1 ) ;

詢問從開始到結束的日期流。

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

從該流中提取日期,將它們收集到List

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

打印我們的日期列表,生成標准ISO 8601格式的文本。

System.out.println( datesForMonthFromToday );

關於java.time

java.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊遺留日期時間類,如java.util.DateCalendarSimpleDateFormat

現在處於維護模式Joda-Time項目建議遷移到java.time類。

要了解更多信息,請參閱Oracle教程 並搜索Stack Overflow以獲取許多示例和解釋。 規范是JSR 310

您可以直接與數據庫交換java.time對象。 使用符合JDBC 4.2或更高版本的JDBC驅動程序 不需要字符串,不需要java.sql.*類。

從哪里獲取java.time類?

ThreeTen-Extra項目使用其他類擴展了java.time。 該項目是未來可能添加到java.time的試驗場。 您可以在這里找到一些有用的類,比如IntervalYearWeekYearQuarter ,和更多

您可以在Google的Guava庫中使用Range功能。 LocalDate實例上定義DiscreteDomain之后,您可以獲得范圍內所有日期的ContiguousSet

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM