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
Java 8 LocalDate - How do I get all dates between two dates?
提问by Patrick
Is there a usablility to get all dates between two datesin the new java.time
API?
是否可以在新java.time
API 中获取两个日期之间的所有日期?
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 startDate
and endDate
.
现在我需要startDate
和之间的所有日期endDate
。
I was thinking to get the daysBetween
of 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 DateRange
class 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
回答by Flown
First you can use a TemporalAdjuster
to get the last day of the month. Next the Stream
API offers Stream::iterate
which is the right tool for your problem.
首先,您可以使用 aTemporalAdjuster
来获取该月的最后一天。接下来,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);
回答by Todd
You could create a stream
of LocalDate
objects. I had this problem too and I published my solution as java-timestream on github.
您可以创建一个stream
的LocalDate
对象。我也有这个问题,我在 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 LocalDate
class 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 datesUntil
in 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::datesUntil
stream
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 类?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 & 7 。
- 安卓
- java.time类的更高版本的 Android 捆绑实现。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
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 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by M. Justin
You could use the Rangefunctionality in Google's Guavalibrary. After defining the DiscreteDomainover LocalDate
instances you could get a ContiguousSetof all dates in the range.
您可以使用Google 的Guava库中的Range功能。在实例上定义DiscreteDomain 后,您可以获得该范围内所有日期的ContiguousSet。LocalDate
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);