如何从今天的日期开始连续查看日期数组?

时间:2017-06-05 15:19:28

标签: java arrays date date-comparison

每次用户完成任务时,我都会有一系列唯一日期。我想检查数组中的日期是否是连续的,包括今天的日期。

如果数组包含日期:"2017/6/2, 2017/6/3, 2017/6/4, 2017/6/5",则根据今天的日期2017/6/5,该函数将返回4,因为今天有4个连续日期,包括今天。

如果数组包含日期"2017/6/2, 2017/6/3, 2017/6/4",那么它将返回0,因为数组不包含今天的日期。否则,计数将在非连续日期被破坏。

List<Date> dateList = new ArrayList<Date>();
int count = 0;
Date todayDate = new Date();

for (int i=0; i<dateList.size(); i++){
    // Check if dates within the array are consecutive from todayDate, if so then increment count by 1.
}

3 个答案:

答案 0 :(得分:2)

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。

虽然你也可以使用JodaTime,它已被停用并被新的API取代,我不建议用joda启动一个新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“即可。

由于您只想比较日期(日/月/年),而不是时间(小时/分钟/秒),最佳选择是使用LocalDate类。对于java 8,此类位于java.time包中,而在ThreeTen Backport中,包为org.threeten.bp。但类和方法名称是相同的。

代码如下:

public int count(List<LocalDate> dateList, LocalDate today) {
    if (!dateList.contains(today)) { // today is not in the list, return 0
        return 0;
    }

    int count = 0;
    LocalDate prev = dateList.get(0); // get first date from list
    for (int i = 1; i < dateList.size(); i++) {
        LocalDate next = dateList.get(i);
        if (prev.plusDays(1).equals(next)) {
            // difference between dates is one day
            count++;
        } else {
            // difference between dates is not 1
            // Do what? return 0? throw exception?
        }
        prev = next;
    }

    return count + 1; // didn't count the first element, adding 1
}

测试此方法:

List<LocalDate> dateList = new ArrayList<>();
dateList.add(LocalDate.of(2017, 6, 2));
dateList.add(LocalDate.of(2017, 6, 3));
dateList.add(LocalDate.of(2017, 6, 4));
dateList.add(LocalDate.of(2017, 6, 5));
LocalDate today = LocalDate.now();

System.out.println(count(dateList, today)); // 4

另一项测试(今天不在列表中)

List<LocalDate> dateList = new ArrayList<>();
dateList.add(LocalDate.of(2017, 6, 2));
dateList.add(LocalDate.of(2017, 6, 3));
dateList.add(LocalDate.of(2017, 6, 4));
LocalDate today = LocalDate.now();

System.out.println(count(dateList, today)); // 0

备注:

  • 由于没有指定日期不连续时要做什么(返回0或抛出异常),我留下了这部分评论。但是将它添加到代码
  • 应该是直截了当的
  • 如果您想将java.util.Date转换为LocalDate,您可以执行以下操作(使用代码of this answer,如果您有任何疑问,请在此链接中提供完整说明):

    public LocalDate convert(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }
    
    // if your Date has no toInstant method, try this:
    public LocalDate convert(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }
    
  • 我知道您要检查连续天(因此,日期之间的1天差异)。但是,如果您想检查上一个日期 之前的日期(无论多少天),您可以将if (prev.plusDays(1).equals(next))更改为if (prev.isBefore(next))

  • 我不确定是不是这样,但是如果你愿意,你也可以直接将String解析为LocalDate(所以你不需要创建很多使用Date

    DateTimeFormatter个对象)
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/M/d");
    LocalDate d = LocalDate.parse("2017/6/2", formatter); // 2017-06-02
    

答案 1 :(得分:1)

有很多方法可以更清楚地写出来:

  1. 使用新的Date API;
  2. 使用库;
  3. 但是,在这种情况下,使用旧的Date类,我会这样做:

    public static void main(String[] args) {
        long millisInDay = TimeUnit.DAYS.toMillis(1);
        List<Date> dates = Arrays.asList(new Date("2017/6/2"), new Date("2017/6/3"), new Date("2017/6/4"), new Date("2017/6/5"));
        System.out.println(getSequentialNumber(millisInDay, dates));
    }
    
    private static int getSequentialNumber(long millisInDay, List<Date> dates) {
        int count = 0;
        Date now = setMidnight(Calendar.getInstance().getTime());
        for (int i = dates.size() - 1; i >= 0; i--) {
            Date date = setMidnight(dates.get(i));
            if (date.getTime() == now.getTime()) {
                count++;
            }
            now.setTime(now.getTime() - millisInDay);
        }
        return count;
    }
    
    private static Date setMidnight(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        return calendar.getTime();
    }
    

答案 2 :(得分:1)

如果我正确理解了这个要求,你就会有一组Date个对象,按日期排序,并保证在同一天没有两个Date个对象,但可能在这些天之间有差距。您的目标是返回仅包含连续天数且包括当前日期的最大子数组的长度,或者如果没有此类子数组则返回0。当前日期可能落在该子阵列内的任何位置,不一定在开头或结尾。

目前尚不清楚你是否需要支持跨越年限,但我会这样认为。我还假设列表中的所有Date对象都用于同一时区,这也是您运行的设备的时区。如果情况并非如此,您应该参考this answer以获取有关测试两个Date对象是否在同一天引用的更多信息。

如果使用Calendar个对象而不是Date个对象,则执行此操作非常简单。您不需要任何第三方库,因为DateCalendar都是标准Android API的一部分。我建议分两个阶段进行:首先在数组中搜索当前日期,然后在两个方向上扫描日期中的间隙或数组边界。然后计算你可以向各个方向走多远。

public int getDateSpanCount(List<Date> dateList) {
    final int n = dateList.size();
    final Calendar today = Calendar.getInstance();
    final Calendar other = Calendar.getInstance();
    int count = 0;

    // First search for today in the date array
    int posToday = -1;
    for (int i=0; i<n; i++) {
        other.setTime(dateList.get(i));
        if (areSameDay(today, other)) {
            posToday = i;
            break;
        }
    }

    // If today is in the list, count the size of the sub-array containing today
    if (posToday >= 0) {
        count++; // count today, at least
        final Calendar probe = Calendar.getInstance();

        // scan backwards from position of today's date
        for (int prevPos = posToday - 1; prevPos >= 0; prevPos--) {
            final Date prev = dateList.get(prevPos);
            probe.setTime(prev);
            other.add(Calendar.DAY_OF_YEAR, -1);
            if (areSameDay(probe, other)) {
                count++;
                other.setTime(prev);
            } else {
                break;
            }
        }

        // reset the other time
        other.setTime(today.getTime());

        // scan forward from position of today's date
        for (int nextPos = posToday + 1; nextPos < n; nextPos++) {
            final Date next = dateList.get(nextPos);
            probe.setTime(next);
            other.add(Calendar.DAY_OF_YEAR, 1);
            if (areSameDay(probe, other)) {
                count++;
                other.setTime(next);
            } else {
                break;
            }
        }
    }
    return count;
}

/** Test whether two Calendar objects are set to the same day */
private static boolean areSameDay(Calendar c1, Calendar c2) {
    // see discussion above if dates may not all be for the local time zone
    return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) &&
           c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
}