【问题标题】:Is there a better way of comparing dates有没有更好的比较日期的方法
【发布时间】:2020-11-13 12:02:54
【问题描述】:

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

这是我的代码

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 个日期,因此它不会处理大量数据,只是我对编写更好的代码感兴趣

【问题讨论】:

  • 什么是“正确的输出”?
  • 不使用earliestDate 变量,您可以只使用return 来确定您想要返回的值。然后一些后续的 if 条件就变得不必要了。
  • 一些想法:您可以将除第一个 if 语句之外的所有语句更改为 else if,因为应该只输入其中一个语句。如果您这样做了,您可以将最后一个if (date2 != null && date1 != null) 更改为简单的else,因为您之前的所有案例都已经处理了null 的日期之一。您可以删除 String earliestDate 局部变量并直接返回(例如:return date1 而不是 easliestDate = date1
  • @sp00m 如果两个日期都为空,则正确的输出是最早的日期或“尚未见过”的日期。我已经相应地编辑了问题。

标签: java algorithm date-comparison


【解决方案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

【讨论】:

  • 谢谢超新星,我没想到这些字符串有可比性。这似乎是前进的方向。
【解决方案2】:

除了一堆看起来相似的 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。有人可能会发现使用流有点矫枉过正,这在某种程度上是正确的。

【讨论】:

    【解决方案3】:

    你可以像这样减少一个 if 条件:

    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;
    } 
    

    【讨论】:

      【解决方案4】:

      您可以使用自定义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;
      }
      

      【讨论】:

        【解决方案5】:

        下面的呢?

        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;
        }
        

        【讨论】:

        • 谢谢。这正是我一直在寻找的,但我无法决定所有 if 和 else 的去向。哪种方式在效率方面更好?
        • @3rdRockSoftware 在您的代码中,检查每个if 条件。
        • 我明白了。所以你的更好,因为要检查的 if 语句更少。再次感谢
        • @3rdRockSoftware 我建议您不要使用最有效的方法。您想要最易读和可维护的方式。
        【解决方案6】:

        日期作为字符串从数据库中导入……

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

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

            // 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

        链接:问题Insert & fetch java.time.LocalDate objects to/from an SQL database such as H2

        【讨论】:

          猜你喜欢
          • 2021-04-22
          • 1970-01-01
          • 1970-01-01
          • 2011-07-30
          • 2011-01-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多