在日期列表中找到最接近目标的日期的最佳方法?

时间:2008-10-09 07:53:05

标签: java date

我有一个Date对象列表和一个目标Date。我想在列表中找到最接近目标日期的日期,但只查找目标日期之前的日期。

实施例: 2008-10-1 2008-10-2 2008-10-4

目标日期为2008-10-3,我想获得2008-10-2

最好的方法是什么?

6 个答案:

答案 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.time

    那些麻烦的旧类已经被Java 8及更高版本中内置的java.time类所取代。见Oracle Tutorial。许多功能已经被后端移植到Java 6&amp; ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。

    java.sql.Date

    LocalDate类表示没有时间且没有时区的仅限日期的值。虽然这些对象不存储时区,但请注意时区(ZoneId)对于确定当前日期至关重要。对于任何特定时刻,日期在全球范围内按时区变化。

    LocalDate

    ISO 8601

    提示:将那些月份和星期几的数字填入前导零。这使它们符合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吗?我似乎记得这样的功能可用。