我有一个Date对象列表和一个目标Date。我想在列表中找到最接近目标日期的日期,但只查找目标日期之前的日期。
实施例: 2008-10-1 2008-10-2 2008-10-4
目标日期为2008-10-3,我想获得2008-10-2
最好的方法是什么?
答案 0 :(得分:6)
Sietse de Kaper解决方案假定反向排序列表,绝对不是最自然的东西
java中的自然排序顺序遵循升序自然排序。 (参见Collection.sort http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#sort(java.util.List)文档)
从您的示例中
target date = 2008-10-03 list = 2008-10-01 2008-10-02 2008-10-04
如果另一个开发者使用你的方法采用天真的方法,他会得到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;
}
编辑 - 我也喜欢Treeset的答案,但我认为它可能稍慢,因为它等同于排序数据然后查找它=&gt; nlog(n)用于排序,然后文档暗示它是log(n)用于访问,因此它将是nlog(n)+ log(n)vs n
答案 1 :(得分:5)
private Date getDateNearest(List<Date> dates, Date targetDate){
return new TreeSet<Date>(dates).lower(targetDate);
}
不需要预先排序的列表,TreeSort修复了这个问题。如果它找不到它,它将返回null,因此如果这是一个问题,你将不得不修改它。不确定效率:P
答案 2 :(得分:2)
我目前使用以下方法,但我不确定它是最有效的方法,因为这假定已经排序的列表,并且(可能)迭代列表中的每个日期。
private Date getDateNearest(List<Date> dates, Date targetDate){
for (Date date : dates) {
if (date.compareTo(targetDate) <= 0) return date;
}
return targetDate;
}
答案 3 :(得分:1)
虽然Keeg的答案在1.6中的1.6中有效但没有方法更低()(我们很遗憾对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 );
}
}
答案 4 :(得分:1)
NavigableSet::lower
Answer by Keeg非常简短。我们的想法是使用lower
界面中定义的NavigableSet
方法,并在TreeSet
类中实现。
但与其他答案一样,它使用与最早版本的Java捆绑在一起的旧的过时日期时间类。以下是使用java.time类的更新版本。
旧的问题和答案使用的是java.util.Date
,它是UTC时间轴上的一个时刻,代表日期和一个时间,或{{1}在假装它没有时间的情况下,它笨拙地扩展了util.Date。令人困惑的混乱。
那些麻烦的旧类已经被Java 8及更高版本中内置的java.time类所取代。见Oracle Tutorial。许多功能已经被后端移植到Java 6&amp; ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。
java.sql.Date
LocalDate
类表示没有时间且没有时区的仅限日期的值。虽然这些对象不存储时区,但请注意时区(ZoneId
)对于确定当前日期至关重要。对于任何特定时刻,日期在全球范围内按时区变化。
LocalDate
提示:将那些月份和星期几的数字填入前导零。这使它们符合ISO 8601标准日期时间格式。在解析/生成表示日期时间值的字符串时,默认情况下在java.time中使用这些格式。
因此请使用ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId ); // 2016-06-25
而不是2008-10-01
。如果填充不可行,请使用DateTimeFormatter
进行解析。
2008-10-1
答案 5 :(得分:0)
你看过JodaTime API吗?我似乎记得这样的功能可用。