SimpleDateFormat 为红黑树将一个日期格式化为另一个日期?与if语句一起使用?

SimpleDateFormat to format one date into another for Red Black Tree? Used together with if statement?

我有一个充满数据的文本文件,我将其放入红黑树中,使用日期作为键,使用该行的其余数据作为值。问题是有些日期的格式是这样的:

"yyyy-MM-dd"

而其他一些日期采用这种格式:

"M/dd/yyyy"

我需要一种方法来比较这两个日期,因为我将它们用作我的红黑树中的键,所以我需要一种通用格式。我不确定比较哪个更容易,但我只知道它们需要采用相同的格式。我读过一些关于 SimpleDateFormat 的内容,但由于我正在考虑通读文件,使用某种 if 语句来确定日期格式是否错误,然后将其格式化为我想要的格式,我我只是不确定如何使用 SimpleDateFormat 来做到这一点,因为我以前从未使用过它。如有任何帮助,我们将不胜感激!

java.time

我建议您使用 java.time,现代 Java 日期和时间 API,作为您的约会工作。

如果您正在从文本文件中读取数据,请尽快将您的日期字符串解析为 LocalDate 对象并将它们存储在您的红黑树中。对于两种格式的字符串解析,如果你事先不知道你得到的是哪种格式,下面的方法可以简单地通过测试字符串是否包含斜杠来处理这两种格式。

private static final DateTimeFormatter DATE_FORMATTER
        = DateTimeFormatter.ofPattern("M/d/y", Locale.ROOT);
    
/** Parses yyyy-MM-dd or M/d/yyyy */
private static LocalDate parseDateString(String dateString) {
    if (dateString.contains("/")) {
        return LocalDate.parse(dateString, DATE_FORMATTER);
    } else {
        return LocalDate.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE);
    }
}

让我们试试看:

    System.out.println(parseDateString("2023-11-20"));
    System.out.println(parseDateString("9/18/2019"));

输出:

2023-11-20
2019-09-18

比较

LocalDate 实现了可比性,因此您可以使用 compareTo() 来比较它们。对于不涉及任何树的简单演示:

    LocalDate dateFromIso = parseDateString("2023-11-20");
    LocalDate dateFromSlashFormat = parseDateString("9/18/2019");
    LocalDate[] dates = { dateFromIso, dateFromSlashFormat };
    
    System.out.println("Before sort: " + Arrays.toString(dates));
    
    Arrays.sort(dates);
    
    System.out.println("After sort:  " + Arrays.toString(dates));
Before sort: [2023-11-20, 2019-09-18]
After sort:  [2019-09-18, 2023-11-20]

教程link

Oracle tutorial: Date Time 解释如何使用 java.time。

就个人而言,我讨厌处理基于 String(或数字)的 date/time 值。 Java(现在)有一个很好的 date/time API 我们不妨尽可能利用它(恕我直言)

因为你有两种相对容易区分的格式(它们使用 /-),解析它们将是一件简单的事情,例如...

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        DateTimeFormatter yearMonthDayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter monthDayYearFormatter = DateTimeFormatter.ofPattern("d/MM/yyyy");

        String yearMonthDayValue = "2020-10-10";
        String monthDayYearValue = "10/10/2020";

        List<String> values = new ArrayList<>();
        values.add("2020-10-10");
        values.add("10/10/2020");

        for (String value : values) {
            LocalDate dateValue = null;
            if (value.contains("-")) {
                dateValue = LocalDate.parse(value, yearMonthDayFormatter);
            } else if (value.contains("/")) {
                dateValue = LocalDate.parse(value, monthDayYearFormatter);
            } else {
                System.err.println("Bad format [" + value + "]");
            }

            if (dateValue != null) {
                // Deal with it
            }
        }
    }
}

我建议查看 Date/Time trail 了解更多详情

java.time

java.util 日期时间 API 及其格式 API、SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*.

解决方案使用 java.time,现代日期时间 API: 您可以在 DateTimeFormatter 中使用方括号指定多个可选模式.将日期字符串解析为 LocalDate 并使用 LocalDate#isBeforeLocalDate#isAfterLocalDate#isEqual 等进行比较

演示:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("[uuuu-MM-dd][M/dd/uuuu]", Locale.ENGLISH);

        // Test
        Stream.of(
                "2021-11-09",
                "11/09/2021",
                "5/09/2021"
        ).forEach(s -> System.out.println(LocalDate.parse(s, dtf)));
    }
}

输出:

2021-11-09
2021-11-09
2021-05-09

ONLINE DEMO

Trail: Date Time.

了解有关现代日期时间 API 的更多信息

* 如果您正在为 Android 项目工作,并且您的 Android API 水平仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time. Check this answer and this answer 学习如何使用 java.time API 和 JDBC。

补充 MadProgrammer 答案的另一种可能性是将日期格式之间的区别委托给具有异常处理的解析器本身。

比如定义一组可能的格式(在你的例子中现在只有两种):

private final DateTimeFormatter[] formats = {
        DateTimeFormatter.ofPattern("yyyy-MM-dd"),
        DateTimeFormatter.ofPattern("d/MM/yyyy")
};

并创建一种方法来规范化输入中读取的“原始”日期:

String normalize(String dateRaw) {
    if (dateRaw == null) {
        throw new IllegalArgumentException("Null date");
    }
    LocalDate standardized = null;
    for (DateTimeFormatter fmt : formats) {
        try {
            standardized = LocalDate.parse(dateRaw, fmt);
            break;
        } catch (final DateTimeParseException e) {
            // ignore or log if you need to
        }
    }
    if (standardized == null) {
        // do something about it, parse failed, invalid date
    }
    return standardized.toString();
}

编辑

如评论中所述,如果您的规范允许,比较 LocalDate 个对象会更容易:

LocalDate toLocalDate(String dateRaw) {
    if (dateRaw == null) {
        throw new IllegalArgumentException("Null date");
    }
    LocalDate localDate = null;
    for (DateTimeFormatter fmt : formats) {
        try {
            localDate = LocalDate.parse(dateRaw, fmt);
            break;
        } catch (final DateTimeParseException e) {
            // ignore or log if you need to
        }
    }
    if (localDate == null) {
        // do something about it, parse failed, invalid date
    }
    return localDate;
}

然后如果你需要一个字符串表示,你可以直接从LocalDate返回的

中得到它