java.time.format.DateTimeFormatter.ISO_INSTANT 的格式字符串?

Format string for java.time.format.DateTimeFormatter.ISO_INSTANT?

在Java8的java.time包中,有这个格式化程序

java.time.format.DateTimeFormatter.ISO_INSTANT (JavaDoc)

允许在解析和格式化中使用可选的小数秒

The ISO instant formatter that formats or parses an instant in UTC, such as '2011-12-03T10:15:30Z'.

This returns an immutable formatter capable of formatting and parsing the ISO-8601 instant format. When formatting, the second-of-minute is always output. The nano-of-second outputs zero, three, six or nine digits digits as necessary. When parsing, time to at least the seconds field is required. Fractional seconds from zero to nine are parsed. The localized decimal style is not used.

可用于创建此格式化程序的格式字符串是什么?我需要存储 String 而不是 DateTimeFormatter 因为后者不可序列化。

具体来说,我想知道如何表示小数秒(包括数字前面的.)。我知道 S 是分秒,X 是区域偏移,但我不知道如何将它们放在一起

S       fraction-of-second          fraction          978
X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;

我能找到的最接近的是 。但是,我不知道/找不到任何方法来获得 0/3/6/9 位小数点行为。

我建议您考虑一下您是否正在解决正确的问题,即:为什么您需要序列化格式化程序本身?格式化程序不是数据,而是逻辑。序列化您的数据,并在整个项目中使用一致的格式化方案 - 您甚至可以集中时间序列化/反序列化,这样 类 read/write 实际上根本不需要为格式化而烦恼。

另一种方法是找到一种方法来序列化格式化程序,并让每个 reader 和编写者承担记录和解释用于序列化时间的格式化程序的负担。您正在屈服于对所有相关 类 共享格式的严格依赖。

我找不到直接等效的格式模式字符串。正如@JB Nizet 所建议的那样,这甚至是不可能的。

但是,我发现我可以在 String 模式中使用可选的部分标记 [] 来获得近似的行为:

"yyyy-MM-dd'T'HH:mm:ss[.SSS]X"

这可以处理以下输入字符串:

"2019-09-02T12:38:16Z"
"2019-09-02T12:38:16.294Z"

这使得小数秒部分成为可选项。

但是,对我来说仍然存在限制 -- 小数秒虽然现在是可选的,但如果存在则必须正好是 3 位数。我不知道可以使 DateTimeFormatter 接受 0-9 小数秒数字的 String 模式是什么。

为了克服这个限制,现在我使用以下解决方案 -- 任何小数秒分量(如果存在)都首先 "canonicalized" 变成 3 位数字。这个 在将输入字符串传递到 DataTimeFormatter 进行解析之前,通过方法 optionalCanonicalizeFractionalSecond()(代码如下所示)完成。这个 到目前为止,方法对我有用。

所以给定 mm:ss[.SSS] 作为输入模式的一部分:

`12:30.123`       will be canon'ed as `12:30.123`
`12:30.12`        will be canon'ed as `12:30.120`
`12:30.1`         will be canon'ed as `12:30.100`
`12:30.123456789` will be canon'ed as `12:30.123`

示例代码

/*
 * Apparently java.time.format.DateTimeFormatter cannot handling
 * a string pattern with variable number of fractional-second
 * digitit.  This method "canonicalize"  any such component
 * to 3 digits
 */
private String optionalCanonicalizeFractionalSecond(String input) {
    if (!formatPattern.contains("mm:ss[.SSS]")) {
        // no fractional-second component in the pattern
        return input; // no need to make any changes
    }
    Pattern regexPattern = Pattern.compile("^(.*)(\d\d:\d\d)(\.\d+)(.*)$");
    Matcher matcher = regexPattern.matcher(input.trim());
    if (!matcher.matches()) {
        // no fractional-second componet in the input string
        return input;
    }
    String prefix = matcher.group(1);
    String minuteSecondString = matcher.group(2);
    String fractionalSecondString = matcher.group(3);
    String suffix = matcher.group(4);
    String canonFss;
    if (fractionalSecondString.length() == 2) {
        canonFss = fractionalSecondString + "00";           // padding with 00
    } else if (fractionalSecondString.length() == 3) {
        canonFss = fractionalSecondString + "0";            // padding with 0
    } else if (fractionalSecondString.length() == 4) {
        canonFss = fractionalSecondString;                  // as is
    } else if (fractionalSecondString.length() > 4
        && fractionalSecondString.length() <= 10) {
        canonFss = fractionalSecondString.substring(0,4);   // truncate to 3 digits
    } else {
        return input;
    }
    return prefix + minuteSecondString + canonFss + suffix;
}