6

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

示例:2008-10-1 2008-10-2 2008-10-4

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

最好的方法是什么?

4

6 回答 6

6
private Date getDateNearest(List<Date> dates, Date targetDate){
    return new TreeSet<Date>(dates).lower(targetDate);
}

不需要预先排序的列表,TreeSort 解决了这个问题。如果找不到,它将返回 null,因此如果出现问题,您将不得不对其进行修改。也不确定效率:P

于 2008-10-09T08:34:15.213 回答
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)文档)

从你的例子中,

目标日期 = 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

  • 于 2008-10-09T09:07:51.510 回答
    2

    我目前使用以下方法,但我不确定它是否是最有效的方法,因为这假设一个已经排序的列表,并且(可能)迭代列表中的每个日期。

    private Date getDateNearest(List<Date> dates, Date targetDate){
      for (Date date : dates) {
        if (date.compareTo(targetDate) <= 0) return date;
      }
    
      return targetDate;
    }
    
    于 2008-10-09T07:54:51.487 回答
    1

    尽管 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 );
      }
    
    }
    
    于 2008-10-09T09:08:05.770 回答
    1

    NavigableSet::lower

    基格的回答巧妙地简短。这个想法是利用接口中lower定义并在类中实现的方法。NavigableSetTreeSet

    但与其他答案一样,它使用与最早版本的 Java 捆绑在一起的旧的过时日期时间类。下面是使用java.time类的更新版本。

    旧的问题和答案使用的是java.util.DateUTC时间线上的时刻,表示日期时间,或者java.sql.Date笨拙地扩展 util.Date 而假装它没有时间。混乱的混乱。

    java.time

    那些麻烦的旧类已被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

    提示:用前导零填充这些月份和日期。这使它们符合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.
    
    于 2016-06-25T21:36:33.463 回答
    0

    你看过 JodaTime API 吗?我似乎记得有这样的功能可用。

    于 2008-10-10T03:32:17.787 回答