【问题标题】:Convert any ISO-8601 format to a readable format in Android将任何 ISO-8601 格式转换为 Android 中的可读格式
【发布时间】:2020-09-03 17:53:57
【问题描述】:

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

  1. 我的android应用支持21及以上
  2. 我从不同的 API 获得了 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 backport。

标签: java android kotlin simpledateformat iso8601


【解决方案1】:

java.time 和脱糖或 ThreeTenABP

您可以在 Android API 级别 21 及更高级别上以两种方式使用 DateTimeFormatter 和 java.time(现代 Java 日期和时间 API)中的其他类:

  1. 通过脱糖。
  2. 通过后端端口; chrylis 已经提到了它甚至还有一个 Android 改编版 ThreeTenABP。 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);

使用您的示例字符串2021-03-05T18:30:00Z 并刚才在欧洲/哥本哈根时区运行,结果是:

181

链接

【讨论】:

  • 嗨,奥莱。感谢您解释清楚的回复。调查它,我在问题中附加了我的代码 sn-p。我用你提到的这个库来查找#days,但是我收到一个错误“2020-09-09T16:00:00Z”无法解析,在索引 10 找到未解析的文本。所以你能帮我解决这个问题吗
  • 可能使用 ZonedDateTime,因为 Z 是零区(偏移),区是 LocalDateTime 的补充。
  • 我编写的代码从这里和那里获得帮助。我已经更新了我的问题中的 sn-p。仍然对代码的验证/优化开放。
  • @OleV.V.如果您可以通过将其发布在您的答案中以更优化的方式展示您的方法,那将有很大的帮助。
猜你喜欢
  • 2018-05-26
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
相关资源
最近更新 更多