2

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

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

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

以 UTC 格式格式化或解析瞬间的 ISO 瞬间格式化程序,例如“2011-12-03T10:15:30Z”。

这将返回一个能够格式化和解析 ISO-8601 即时格式的不可变格式化程序。格式化时,总是输出秒数。纳秒根据需要输出零、三、六或九位数字。解析时,至少需要秒字段的时间。解析从零到九的小数秒。不使用本地化的十进制样式。

可用于创建此格式化程序的格式字符串是什么?我需要存储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;
4

2 回答 2

4

我能找到的最接近的是这个答案。但是,我不知道/找不到任何方法来获得 0/3/6/9 位十进制行为。

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

另一种方法是找到一种方法来序列化格式化程序,并让每个读者和作者承担记录和解释用于序列化时间的格式化程序的负担。您将自己置于对所有涉及的类之间共享的格式的硬依赖中。

于 2019-08-30T17:41:49.497 回答
0

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

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

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

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

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

这使得小数秒部分是可选的。

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

为了克服这个限制,现在我使用以下解决方案——任何小数秒分量(如果存在)首先被“规范化”为 3 位数字。这是在将输入字符串传递给解析之前通过一种方法optionalCanonicalizeFractionalSecond()(代码如下所示)完成的。DataTimeFormatter到目前为止,这种方法对我有效。

所以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;
}
于 2019-08-30T18:35:17.803 回答