java 在日期列表中找到最接近目标的日期的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/186311/
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
Best way to find date nearest to target in a list of dates?
提问by Sietse
I have a list of Date objects, and a target Date. I want to find the date in the list that's nearest to the target date, but only dates that are before the target date.
我有一个日期对象列表和一个目标日期。我想在列表中找到最接近目标日期的日期,但只能找到目标日期之前的日期。
Example: 2008-10-1 2008-10-2 2008-10-4
示例:2008-10-1 2008-10-2 2008-10-4
With a target date of 2008-10-3, I want to get 2008-10-2
目标日期为 2008-10-3,我想得到 2008-10-2
What is the best way to do it?
最好的方法是什么?
回答by Keeg
private Date getDateNearest(List<Date> dates, Date targetDate){
return new TreeSet<Date>(dates).lower(targetDate);
}
Doesn't require a pre-sorted list, TreeSort fixes that. It'll return null if it can't find one though, so you will have to modify it if that's a problem. Not sure of the efficency either :P
不需要预先排序的列表,TreeSort 修复了这个问题。如果找不到,它将返回 null,因此如果这是一个问题,您将不得不修改它。也不确定效率:P
回答by Jean
Sietse de Kaper solution assumes a reversesorted list, definitely not the most natural thing to have around
Sietse de Kaper 解决方案假设一个反向排序的列表,这绝对不是最自然的事情
The natural sort order in java is following the ascending natural ordering. (see Collection.sort http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#sort(java.util.List)documentation)
java中的自然排序顺序是按照升序自然排序。(参见 Collection.sort http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#sort(java.util.List)文档)
From your example,
从你的例子来看,
target date = 2008-10-03 list = 2008-10-01 2008-10-02 2008-10-04
If another developper uses your method with a naive approach he would get 2008-10-01 which is not what was expected
如果另一个开发人员以天真的方法使用您的方法,他将得到 2008-10-01 这不是预期的
private Date getDateNearest(List<Date> dates, Date targetDate){
Date returnDate = targetDate
for (Date date : dates) {
// if the current iteration'sdate is "before" the target date
if (date.compareTo(targetDate) <= 0) {
// if the current iteration's date is "after" the current return date
if (date.compareTo(returnDate) > 0){
returnDate=date;
}
}
}
return returnDate;
}
edit - I also like the Treeset answer but I think it might be slightly slower as it is equivalent to sorting the data then looking it up => nlog(n) for sorting and then the documentation implies it is log(n) for access so that would be nlog(n)+log(n) vs n
private Date getDateNearest(List<Date> dates, Date targetDate){
Date returnDate = targetDate
for (Date date : dates) {
// if the current iteration'sdate is "before" the target date
if (date.compareTo(targetDate) <= 0) {
// if the current iteration's date is "after" the current return date
if (date.compareTo(returnDate) > 0){
returnDate=date;
}
}
}
return returnDate;
}
编辑 - 我也喜欢 Treeset 的答案,但我认为它可能会稍微慢一些,因为它相当于对数据进行排序然后查找 => nlog(n) 进行排序,然后文档暗示它是 log(n) 进行访问,所以那将是 nlog(n)+log(n) vs n
回答by Sietse
I currently use the following method, but I'm not sure it's the most effective one, because this assumes an already sorted list, and (potentially) iterates over every single date in the list.
我目前使用以下方法,但我不确定它是最有效的方法,因为这假设一个已经排序的列表,并且(可能)迭代列表中的每个日期。
private Date getDateNearest(List<Date> dates, Date targetDate){
for (Date date : dates) {
if (date.compareTo(targetDate) <= 0) return date;
}
return targetDate;
}
回答by Basil Bourque
NavigableSet::lower
NavigableSet::lower
The Answer by Keegis cleverly brief. The idea there is to make use of the lowermethod defined in the NavigableSetinterface and implemented in the TreeSetclass.
Keeg的回答非常简洁。那里的想法是利用lower在NavigableSet接口中定义并在TreeSet类中实现的方法。
But like the other answers it uses the old outmoded date-time classes bundled with the earliest versions of Java. Below is an updated version using java.timeclasses.
但与其他答案一样,它使用与最早版本的 Java 捆绑在一起的旧的过时日期时间类。下面是使用java.time类的更新版本。
The old question and answers are using either java.util.Datewhich is a moment on the timeline in UTC representing both a date anda time-of-day, or the java.sql.Datewhich awkwardly extends util.Date while pretending it does not have a time-of-day. A confusing mess.
旧的问题和答案使用的是java.util.DateUTC 时间线上的一个时刻,代表日期和时间,或者java.sql.Dateutil.Date 笨拙地扩展 util.Date 同时假装它没有时间。一团乱麻。
java.time
时间
Those troublesome old classes have been supplanted by the java.timeclasses built into Java 8 and later. See Oracle Tutorial. Much of the functionality has been back-ported to Java 6 & 7 in ThreeTen-Backportand further adapted to Android in ThreeTenABP.
那些麻烦的旧类已被Java 8 及更高版本中内置的java.time类所取代。请参阅Oracle 教程。许多功能已被后移植到Java 6和7在ThreeTen-反向移植和在进一步适于到Android ThreeTenABP。
LocalDate
LocalDate
The LocalDateclass represents a date-only value without time-of-day and without time zone. While these objects store no time zone, note that time zone (ZoneId) is crucial in determining the current date. For any given moment the date varies around the globe by time zone.
该LocalDate级表示没有时间一天和不同时区的日期,唯一的价值。虽然这些对象不存储时区,但请注意时区 ( ZoneId) 对确定当前日期至关重要。对于任何给定时刻,日期在全球各地因时区而异。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId ); // 2016-06-25
ISO 8601
ISO 8601
Tip: Pad those month and day-of-month numbers with a leading zero. This makes them comply with the ISO 8601standard date-time formats. These formats are used by default in java.time when parsing/generating strings that represent date-time values.
提示:用前导零填充这些月份和月份的数字。这使它们符合ISO 8601标准日期时间格式。在解析/生成表示日期时间值的字符串时,默认情况下在 java.time 中使用这些格式。
So use 2008-10-01rather than 2008-10-1. If padding is not feasible, parse using DateTimeFormatter.
所以使用2008-10-01而不是2008-10-1. 如果填充不可行,请使用DateTimeFormatter.
NavigableSet dates = new TreeSet( 3 );
dates.add( LocalDate.parse( "2008-10-01" );
dates.add( LocalDate.parse( "2008-10-02" );
dates.add( LocalDate.parse( "2008-10-04" );
LocalDate target = LocalDate.parse( "2008-10-03" );
LocalDate hit = dates.lower( target );
// Reminder: test for `null == hit` to see if anything found.
回答by Daniel Hiller
Although the answer from Keeg is valid in 1.6 in 1.5 there is no method lower() (We're unfortunate to develop against 1.5 :-( )
尽管 Keeg 的答案在 1.5 中的 1.6 中有效,但没有方法 lower() (我们很遗憾针对 1.5 进行开发 :-( )
this one works in 1.5
这个适用于 1.5
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;
public class GetNearestDate {
public static void main( String[] args ) throws ParseException {
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat( "dd.MM.yyyy HH:mm:ss" );
List< Date > otherDates = Arrays.asList( new Date[]{
simpleDateFormat.parse( "01.01.2008 01:00:00" ) ,
simpleDateFormat.parse( "01.01.2008 01:00:02" ) } );
System.out.println( simpleDateFormat.parse( "01.01.2008 01:00:00" ).equals(
get( otherDates , simpleDateFormat.parse( "01.01.2008 01:00:01" ) ) ) );
System.out.println( simpleDateFormat.parse( "01.01.2008 01:00:02" ).equals(
get( otherDates , simpleDateFormat.parse( "01.01.2008 01:00:03" ) ) ) );
System.out.println( null == get( otherDates , simpleDateFormat.parse( "01.01.2008 01:00:00" ) ) );
}
public static Date get( List< Date > otherDates , Date dateToApproach ) {
final TreeSet< Date > set = new TreeSet< Date >( otherDates );
set.add( dateToApproach );
final ArrayList< Date > list = new ArrayList< Date >( set );
final int indexOf = list.indexOf( dateToApproach );
if ( indexOf == 0 )
return null;
return list.get( indexOf - 1 );
}
}
回答by Aidos
Have you looked at the JodaTime API? I seem to recall a feature like this being available.
你看过 JodaTime API 吗?我似乎记得有这样一个功能可用。

