如何从输入中格式化日期字符串可以是多种字符串格式

问题描述 投票:0回答:1

具有输入日期字符串可能为

"2020-01-25T21:59:27Z"

"Sat Jan 25 20:06:07 +0000 2020"

Long

并且希望显示的像是

Jan 25, 2020

如何获取所需的格式化日期字符串?

android simpledateformat
1个回答
1
投票

java.time和ThreeTenABP

我的解决方案是为三种可能的输入格式构建三个格式化程序,然后针对每个输入依次尝试格式化程序。对于这个想法的简单演示:

    DateTimeFormatter[] inputFormatters = {
            DateTimeFormatter.ISO_INSTANT,
            DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss xx yyyy", Locale.ROOT),
            new DateTimeFormatterBuilder()
                    .appendValue(ChronoField.INSTANT_SECONDS)
                    .appendValue(ChronoField.MILLI_OF_SECOND, 3)
                    .toFormatter()
    };
    DateTimeFormatter displayFormatter
            = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
                    .withLocale(Locale.US);

    for (String inputString : new String[] {
            "2020-01-25T21:59:27Z",
            "Sat Jan 25 20:06:07 +0000 2020",
            "1566777888999"
    }) {
        // try the formatters in turn and see which one works
        for (DateTimeFormatter formatter : inputFormatters) {
            try {
                ZonedDateTime dateTime = formatter.parse(inputString, Instant.FROM)
                        .atZone(ZoneId.systemDefault());
                System.out.format("%-30s was parsed to %s%n",
                        inputString, dateTime.format(displayFormatter));
                break;
            } catch (DateTimeParseException ignore) {
                // Ignore, try next format
            }
        }
    }

在我的时区(欧洲/哥本哈根)中,此代码段的输出是:

2020-01-25T21:59:27Z           was parsed to Jan 25, 2020
Sat Jan 25 20:06:07 +0000 2020 was parsed to Jan 25, 2020
1566777888999                  was parsed to Aug 26, 2019

由于在所有时区都不是同一日期,所以输出将随时区而变化。

我建议使用java.time,现代的Java日期和时间API。我看到您标记了simpledateformat问题,但众所周知SimpleDateFormat类麻烦且久已过时,因此,建议不要使用它。而且我正在利用这样一个事实,您的第一种格式是标准ISO 8601,并且java.time具有内置的格式化程序DateTimeFormatter.ISO_INSTANT

我的第三个输入格式化程序,即long值输入格式器,将最后三个字符视为秒的毫秒数,并将其前的所有字符视为自纪元以来的秒数。最终结果是它解析了自该纪元以来的毫秒数。构建此格式化程序需要DateTimeFormatterBuilder

无lib解决方案

我承认我讨厌写这篇文章。我真的希望您能够避免臭名昭著的SimpleDateFormat类以及它像Date这样早已过时的亲信。由于我了解您的应用程序是无库的,因此Joda-Time和ThreeTenABP似乎都不是问题。抱歉。在这种情况下,由于SimpleDateFormat无法解析很长的时间,因此我的方法是尝试一下字符串以确定格式,然后基于该字符串选择我的解析方式。

    DateFormat inputIso = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
    // This format resembles the output from Date.toString
    DateFormat inputDatelike
            = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy", Locale.ROOT);
    DateFormat displayFormat
            = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US);
    displayFormat.setTimeZone(TimeZone.getDefault());

    for (String inputString : new String[] {
            "2020-01-25T21:59:27Z",
            "Sat Jan 25 20:06:07 +0000 2020",
            "1566777888999"
    }) {
        Date parsedDate;
        if (Character.isDigit(inputString.charAt(0))) {
            if (inputString.contains("-")) {
                parsedDate = inputIso.parse(inputString);
            } else {
                // long number of millis
                parsedDate = new Date(Long.parseLong(inputString));
            }
        } else {
            parsedDate = inputDatelike.parse(inputString);
        }
        System.out.format("%-30s was parsed to %s%n",
                inputString, displayFormat.format(parsedDate));
    }

输出与以前完全相同:

2020-01-25T21:59:27Z           was parsed to Jan 25, 2020
Sat Jan 25 20:06:07 +0000 2020 was parsed to Jan 25, 2020
1566777888999                  was parsed to Aug 26, 2019

[请注意,此处的无效输入可能会导致NumberFormatExceptionParseException,因此请同时捕获两者。如果无法避免,则只能诉诸此解决方案。

问题:java.time是否不需要Android API级别26?

java.time在较新和较旧的Android设备上均可正常运行。它只需要至少Java 6

  • 在Java 8和更高版本以及更新的Android设备(来自API级别26)中,内置了现代API。仅在这种情况下,使用方法参考Instant::from而不是常量Instant.FROM
  • 在非Android Java 6和7中,获得了ThreeTen Backport,这是现代类的backport(用于JSR 310的ThreeTen;请参见底部的链接。
  • 在(较旧的)Android上,使用ThreeTen Backport的Android版本。称为ThreeTenABP。并确保使用子包从org.threeten.bp导入日期和时间类。

链接

© www.soinside.com 2019 - 2024. All rights reserved.