将任何 ISO-8601 格式转换为 Android 中的可读格式

Convert any ISO-8601 format to a readable format in Android

所以,我知道这是一个讨论得很好的问题,有很多问题和答案(主要是关于 Joda),还有新的 class DateTimeFormatter 和所有支持 api 以上级别的问题26. 但我担心的是:

  1. 我的android应用支持21及以上
  2. 我从不同的 API 获得了 date/time ISO-8601 格式的多种变体: 例如:a) “2020-09-03T17:03:11.719566Z” b) “2021-03-05T18:30:00Z”

所以,我需要找到今天和那个日期之间的 #days。当我编写代码来解析其中一个时,另一个命中我的 catch 块,反之亦然,所以我编写了一个嵌套的 try/catch 块来处理这两种情况......像这样:

fun getFormattedDate(stringDate: String?): Long {
if (dueDateString.isNullOrEmpty())
    return 0
val today = Calendar.getInstance().time
try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
    val date = inputFormat.parse(dueDateString)
    return if (date != null) {
        val dueCalendar = Calendar.getInstance()
        dueCalendar.time = date
        getNoOfDays(today.time, dueCalendar.timeInMillis)
    } else
        0
} catch (ex: Exception) {
    ex.showLog()
    try {
val inputFormat1 = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH)
        val date = inputFormat1.parse(dueDateString)
        return if (date != null) {
            val dueCalendar = Calendar.getInstance()
            dueCalendar.time = date
            getNoOfDays(today.time, dueCalendar.timeInMillis)
        } else
            0
    } catch (exc: Exception) {
        exc.showLog()
        return 0
    }
}
}

我正在使用此函数查找两个日期之间的#days:

fun getDueDateAfterParsing(dueDateString: String?): Long {
val today = ZonedDateTime.ofInstant(now(), ZoneId.systemDefault())
val dueDate = ZonedDateTime.parse(
    dueDateString,
    DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault())
)
return ChronoUnit.DAYS.between(today, dueDate)
}

我很确定解决这个问题的方法不会这么复杂。 ISO-8601 的格式太多了,所以我不能编写适合所有情况的 try/catch 块,对吧?那么有人可以用最简单的方法帮助我解决这个问题吗?

我也考虑过正则表达式,他们中的大多数人最终会说我猜是 Joda,但至少我想确定什么是最佳方式或最佳方式。

在此先感谢您的帮助。

java.time 和脱糖或 ThreeTenABP

您可以使用 DateTimeFormatter 和来自 java.time 的另一个 类,现代 Java 日期和时间 API,在 Android API 21 级及以上有两种方式:

  1. 通过脱糖。
  2. 通过反向移植;甚至还有一个 Android 改编版本,ThreeTenABP,chrylis 已经提到过。它是 JSR-310 的 ThreeTen,其中 java.time 首次被描述,ABP 用于 Android backport。

对于这两种方式,请参阅底部的链接。

代码

您甚至不需要指定格式化程序。

    String stringWeGot = "2020-09-03T17:03:11.719566Z";
    Instant parsed = Instant.parse(stringWeGot);
    System.out.println(parsed);

输出:

2020-09-03T17:03:11.719566Z

或使用您的其他示例字符串:

    String stringWeGot = "2021-03-05T18:30:00Z";

2021-03-05T18:30:00Z

java.time 的 类 将最常见的 ISO 8601 变体解析为默认值,即没有显式格式化程序。秒上是否存在从 0 到 9 的小数位是内置的,甚至是秒本身的存在或不存在。 InstantOffsetDateTime 都可以按照代码所示的方式使用。

警告!如果您出于某种原因选择一个或多个格式化程序,永远不要将 Z 硬编码为格式中的文字模式字符串Z 是与 UTC 的偏移量(零),必须这样解析,否则在绝大多数 Android 设备上会得到不正确的结果。

此外,在计算天数方面,java.time 远优于旧的和设计不佳的 类,如 Calendar编辑:您计算设备时区到期日之前的整天数的方法是正确的。仅供参考,我的做法是:

    ZoneId zone = ZoneId.systemDefault();
    ZonedDateTime today = ZonedDateTime.now(zone);
    ZonedDateTime dueDate = parsed.atZone(zone);
    long daysUntilDue = ChronoUnit.DAYS.between(today, dueDate);
    System.out.println(daysUntilDue);

刚才使用 Europe/Copenhagen 时区的 2021-03-05T18:30:00Z 和 运行 的示例字符串,结果是:

181

链接