Android对Java的修改-SimpleDateFormat类

简介

Android会对部分OpenJDK中的代码进行一些修改,本篇记录一下因为这些修改而踩过的一些坑。

问题描述

一个在线上运行良好的Date工具类在写单元测试时一直报ParseException,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static String utc2Local(String utcTime) {
String utcTimePatten = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
String localTimePatten = "yyyy.MM.dd";
SimpleDateFormat utcFormater = new SimpleDateFormat(utcTimePatten);
utcFormater.setTimeZone(TimeZone.getTimeZone("UTC"));//时区定义并进行时间获取
Date gpsUTCDate = null;
try {
gpsUTCDate = utcFormater.parse(formatTimeStr(utcTime));
} catch (Exception e) {
e.printStackTrace();
return utcTime;
}
SimpleDateFormat localFormater = new SimpleDateFormat(localTimePatten);
localFormater.setTimeZone(TimeZone.getDefault());
String localTime = localFormater.format(gpsUTCDate.getTime());
return localTime;
}

这里传入的参数utcTime为”2020-01-01 08:00:00+08:00”

这段代码在Android环境下运行良好,但在单元测试下一直报错

原因

Android对OpenJDK中的SimpleDateFormat进行了修改,具体在subParseNumericZone方法中:

可以看到,OpenJDK原本是不支持带冒号的写法的,而在Android中修改了subParseNumericZone方法,使其可以解析带冒号的写法。

解决

解决方法也很简单,在测试时直接修改入参,去掉入参中的冒号就好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try (MockedStatic<DateUtils> mockedDateUtils = Mockito.mockStatic(DateUtils.class, new CallsRealMethods())) {
mockedDateUtils.when(() -> {
DateUtils.utc2Local(argThat((argument) -> {
int index = argument.length() - 3;
return argument.charAt(index) == ':';
));
}).then((invocation) -> {
String utcTime = invocation.getArgument(0, String.class);
String fixedDate = formatDate;
int index = formatDate.length() - 3;
if (formatDate.charAt(index) == ':') {
fixedDate = formatDate.substring(0, index) + formatDate.substring(index + 1);
}
return DateUtils.utc2Local(fixedDate);
});
}