有没有更好的比较日期的方法

Is there a better way of comparing dates

我正在尝试比较两个日期。 日期作为字符串从数据库导入,可能为空也可能不为空

这是我的代码

private String compareDates(String date1, String date2)
    {
        String earliestDate = null;
//        date2 is null and date1 is null
//            earliest = “not seen yet”
        if (date2 == null && date1 == null)
        {
            earliestDate = "not seen yet";
        }
//        date2 is null and date1 is not null
//            earliest = date1
        if (date2 == null && date1 != null)
        {
            earliestDate = date1;
        }
//        date2 is not null and date1 is null
//            earliest = date2
        if (date2 != null && date1 == null)
        {
            earliestDate = date2;
        }
//        date2 is not null and date1 is not null
//            compare dates
        if (date2 != null && date1 != null)
        {
            LocalDate LDdate1 = LocalDate.parse(date1);
            LocalDate LDdate2 = LocalDate.parse(date2);
            if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2))
            {
                earliestDate = LDdate1.toString();
            }
            else
            {
                earliestDate = LDdate2.toString();
            }
        }
        return earliestDate;
    }

这段代码给了我正确的输出,这是最早的日期,如果两个日期都为空,则为“尚未看到”,但我想知道是否有更好/更有效的做事方式。

我认为使用 switch 语句是一种选择,但如果换一种方式会更好吗?

数据库中的数据仅包含大约 200 个日期,因此它处理的数据不多,只是我有兴趣编写更好的代码

下面的怎么样?

private String compareDates(String date1, String date2) {
    String earliestDate;
    if (date1 == null) {
        if (date2 == null) {
            earliestDate = "not seen yet";
        }
        else {
            earliestDate = date2;
        }
    }
    else {
        if (date2 == null) {
            earliestDate = date1;
        }
        else {
            LocalDate LDdate1 = LocalDate.parse(date1);
            LocalDate LDdate2 = LocalDate.parse(date2);
            if (LDdate1.isAfter(LDdate2)) {
                earliestDate = date2;
            }
            else {
                earliestDate = date1;
            }
        }
    }
    return earliestDate;
}

如果条件如下,您可以减少一个:

private String compareDates(String date1, String date2) {
    String earliestDate = "not seen yet";
    if (!StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
        LocalDate LDdate1 = LocalDate.parse(date1);
        LocalDate LDdate2 = LocalDate.parse(date2);
        if (LDdate1.isBefore(LDdate2) || LDdate1.isEqual(LDdate2)) {
            earliestDate = LDdate1.toString();
        }
        else {
            earliestDate = LDdate2.toString();
        }
    } else if (!StringUtils.isEmpty(date2) && StringUtils.isEmpty(date1)) {
        earliestDate = LDdate2;
    } else if (StringUtils.isEmpty(date2) && !StringUtils.isEmpty(date1)) {
        earliestDate = LDdate1;
    }
    return earliestDate;
} 

您可以使用自定义 Comparator,它允许以 声明性 方式指定比较逻辑:

private String compareDates(String date1, String date2) {

    Comparator<String> c = Comparator.nullsLast(
                           Comparator.comparing(LocalDate::parse));

    int result = c.compare(date1, date2);

    return result == 0 && date1 == null ?
           "not seen yet"               :
           result <= 0                  ?
           date1                        :
           date2;
}

除了一堆看起来相似的 if 语句之外,还有一些其他选项。

  1. Comparator

    if (date1 == null && date2 == null) {
        return "not seen yet";
    }
    Comparator<String> c = Comparator.nullsLast((String a, String b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)));
    return c.compare(date1, date2) <= 0 ? date1 : date2;
    
  2. Stream::reduce 使用 Comparator

    return Stream.of(date1, date2)
        .filter(Objects::nonNull)
        .reduce((a, b) -> LocalDate.parse(a).compareTo(LocalDate.parse(b)) <= 0 ? a : b)
        .orElse("not seen yet");
    

对我来说,这两个选项都比您现在的可读性更好,但我会选择选项 1。人们可能会发现使用流有点矫枉过正,这在某种程度上是正确的。

如果日期采用标准本地格式并按 YYYY MM DD 排序,例如

"2018-01-24"

为什么要费心解析呢?只需进行字符串比较。大约快 100 倍,也更容易。

    public static String compareDatesStr(String date1, String date2) {
        if (date1 == null)
            if (date2 == null)
                return "not seen yet";
            else
                return date2;
        else if (date2 == null)
            return date1;
        else
            return date1.compareTo(date2) > 0 ? date2 : date1;
    }

一些非科学的性能比较:

    private static String compareDatesParse(String date1, String date2) {
        String earliestDate;
        if (date1 == null) {
            if (date2 == null) {
                earliestDate = "not seen yet";
            }
            else {
                earliestDate = date2;
            }
        }
        else {
            if (date2 == null) {
                earliestDate = date1;
            }
            else {
                LocalDate LDdate1 = LocalDate.parse(date1);
                LocalDate LDdate2 = LocalDate.parse(date2);
                if (LDdate1.isAfter(LDdate2)) {
                    earliestDate = date2;
                }
                else {
                    earliestDate = date1;
                }
            }
        }
        return earliestDate;
    }

    public static void testDateComp(){
        String[] dates = {"2020-10-30", "2020-10-29", "1990-10-30", "2021-06-01", null};
        String result = null;
        int loops = 400000;
        long start, end = 0;
        // System.out.println("Runs: " + (dates.length*dates.length*loops));


        start = System.currentTimeMillis();
        for (int i = 0; i < loops; i++) {
            for (String date1:dates) {
                for (String date2:dates) {
                    result = compareDatesStr(date1, date2);
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Runtime String: " + (end - start)+ "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < loops; i++) {
            for (String date1:dates) {
                for (String date2:dates) {
                    result = compareDatesParse(date1, date2);
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Runtime Parsing: " + (end - start) + "ms");
    }

10MM 方法执行次数:

Runtime String: 61ms
Runtime Parsing: 7361ms

The dates are imported from a database as strings …

第一点:不要那样做。从数据库中以 LocalDate 对象的形式获取日期,并在程序中这样处理它们。有关如何从 SQL 数据库中获取 LocalDate,请参阅底部的 link。

接下来,我将使用流管道来查找较早的管道:

    // Some example dates
    LocalDate date1 = null;
    LocalDate date2 = LocalDate.of(2020, Month.OCTOBER, 24);
    
    String earlierDate = Stream.of(date1, date2)
            .filter(Objects::nonNull)
            .min(LocalDate::compareTo)
            .map(LocalDate::toString)
            .orElse("Not seen yet");
    System.out.println(earlierDate);

输出:

2020-10-24

Link: 问题