java - 以任何符合 ISO-8601 的格式解析字符串的统一方法
问题描述
我需要一个统一的方法来解析任何符合 ISO-8601 的字符串。不幸的是,Joda 和 fastxml StdDateFormat 都没有资格这样做。
我想解释以下两个属性
- 字符串开始;
- 字符串时区;
start
是符合 ISO-8601 的字符串,可以是任何符合标准的格式,例如“2020-05-15T20:30:52+03:00”或 2020-05-15”。timezone
是IANA 时区,例如“Europe/Moscow”。
期望的逻辑是:
如果
timezone
未指定,则扩展start
到完全限定的 UTC,而不管它包含什么时区信息。例如,将“2020-05-15T20:30”扩展为“2020-05-15T20:30:00.000Z”。如果
timezone
指定,且时区信息与start
冲突timezone
,则报错。例如timezone
=“亚洲/上海”和start
=“2020-05-15T20:30:52+03:00”。如果
timezone
已指定,并且与 中的时区信息没有冲突start
,则扩展start
为完全限定的 ISO-8601 格式。例如timezone
= "Europe/Moscow",start
= "2020-05-15T20:30+03:00",然后扩展start
到 "2020-05-15T20:30:00.000+03:00"。如果
timezone
已指定且start
没有时区信息,则添加并将timezone
其start
扩展为完全限定的 ISO-8601 格式。例如timezone
= "Europe/Moscow" 和start
= "2020-05-15",然后扩展start
为 "2020-05-15T00:00:00.000+03:00"。
此代码片段侧重于解析符合 ISO-8601 的字符串。尚未涉及任何timezone
参数。它尝试使用Joda DateTime
and fasterxml StdDateFormat
。
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import com.fasterxml.jackson.databind.util.StdDateFormat;
public class ISOTest2 {
public void test() {
String [] inputs = new String [] {
"2019-06-16T09:30:20+06:00",
"2019-06-16T09:30Z",
"2019-06-16T09:30:20",
"2019-06-16T09:30",
"2019-06-16T",
"2019-06-16",
"20190616T09:30:20+06:00",
"20190618T110044Z"
};
StdDateFormat df = new StdDateFormat();
for (String input : inputs) {
System.out.println();
DateTime output = null;
boolean isStdDateFormatFail = false;
try {
Date date = df.parse(input);
output = new DateTime(date);
System.out.println("Valid for StdDateFormat:\t\t" + input);
print(input, output);
} catch (Exception e) {
isStdDateFormatFail = true;
System.out.println("=============");
System.out.println("Invalid for StdDateFormat:\t\t" + input);
}
if (isStdDateFormatFail) {
try {
output = DateTime.parse(input);
System.out.println("Valid for Joda:\t\t" + input);
print(input, output);
} catch (Exception e) {
System.out.println("=============");
System.out.println("Invalid for Joda:\t\t" + input);
}
}
}
}
private void print(String input, DateTime output) {
System.out.println("=============");
System.out.println("Input:\t\t" + input);
System.out.println("Output:\t\t" + output);
DateTimeZone zone = output.getZone();
System.out.println("Zone:\t\t" + zone);
}
public static void main(String[] args) {
ISOTest2 test = new ISOTest2();
test.test();
}
}
注意我的本地时区是“亚洲/上海”,即+08:00
预期结果
=============
Input: 2019-06-16T09:30:20+06:00
Output: 2019-06-16T09:30:20.000+06:00
Zone: +0600
=============
Input: 2019-06-16T09:30Z
Output: 2019-06-16T09:30:00.000Z
Zone: UTC
=============
Input: 2019-06-16T09:30:20
Output: 2019-06-16T09:30:20.000Z
Zone: UTC
=============
Input: 2019-06-16T09:30
Output: 2019-06-16T09:30:00.000Z
Zone: UTC
=============
Input: 2019-06-16T
Output: 2019-06-16T00:00:00.000Z
Zone: UTC
=============
Input: 2019-06-16
Output: 2019-06-16T00:00:00.000Z
Zone: UTC
=============
Input: 20190616T09:30:20+06:00
Output: 2019-06-16T09:30:20.000+06:00
Zone: +0600
=============
Input: 20190618T110044Z
Output: 2019-06-18T11:00:44.000Z
Zone: UTC
实际结果
Valid for StdDateFormat: 2019-06-16T09:30:20+06:00
=============
Input: 2019-06-16T09:30:20+06:00
Output: 2019-06-16T11:30:20.000+08:00
Zone: Asia/Shanghai
Valid for StdDateFormat: 2019-06-16T09:30Z
=============
Input: 2019-06-16T09:30Z
Output: 2019-06-16T17:30:00.000+08:00
Zone: Asia/Shanghai
Valid for StdDateFormat: 2019-06-16T09:30:20
=============
Input: 2019-06-16T09:30:20
Output: 2019-06-16T17:30:20.000+08:00
Zone: Asia/Shanghai
Valid for StdDateFormat: 2019-06-16T09:30
=============
Input: 2019-06-16T09:30
Output: 2019-06-16T17:30:00.000+08:00
Zone: Asia/Shanghai
=============
Invalid for StdDateFormat: 2019-06-16T
Valid for Joda: 2019-06-16T
=============
Input: 2019-06-16T
Output: 2019-06-16T00:00:00.000+08:00
Zone: Asia/Shanghai
Valid for StdDateFormat: 2019-06-16
=============
Input: 2019-06-16
Output: 2019-06-16T08:00:00.000+08:00
Zone: Asia/Shanghai
=============
Invalid for StdDateFormat: 20190616T09:30:20+06:00
Valid for Joda: 20190616T09:30:20+06:00
=============
Input: 20190616T09:30:20+06:00
Output: 20190616-01-01T09:30:20.000+06:00
Zone: +06:00
=============
Invalid for StdDateFormat: 20190618T110044Z
=============
Invalid for Joda: 20190618T110044Z
阻塞问题
存在三个阻塞问题。
fasterxml StdDateFormat
将更original timezone
改为local timezone
隐式。例如,输入字符串为“2019-06-16T09:30:20+06:00”,输出日期为“2019-06-16T11:30:20.000+08:00”。当 中不包含时区信息时
start
,两者都隐含Joda
地fasterxml
添加本地时区。例如,输入字符串为“2019-06-16T09:30”,输出日期为“2019-06-16T17:30:00.000+08:00”。(我当地的时区是“亚洲/上海”,例如 +08:00) 我期待的是一个添加timezone
它的机会。例如,另一个参数指定为“Asia/Shanghai”,start
=“2019-06-16T09:30”,所需的输出类似于:“2019-06-16T09:30”+“Asia/Shanghai”=“ 2019-06-16T09:30:00.000+08:00”。fasterxml
无法解析“20190616T09:30:20+06:00”。Joda 和 fastermxl 都无法解析“20190618T110044Z”。
解决方案
推荐阅读
- javascript - 使用 JavaScript 打开隐藏窗口并稍后显示
- javascript - 相对定位元素的原始位置上的单击事件
- go - Dredd 没有杀死 main.go 需要修复
- android-viewpager - 如何使用 ActionBar (Android) 均匀地布局选项卡标题
- jenkins - 使用 Jenkins 和 nvidia-docker 对多个 GPU 进行排队
- jquery - DNN 8.0.3.5 jQuery 1.9.1 安全问题
- reactjs - 使用带有 React 的 Material-UI 自定义开关
- polymer - Polymer 2.0 嵌套铁页
- javascript - 用于绑定回调序列的 Composer 函数
- java - 如何有效地只生成奇数(或偶数)随机数?