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