SimpleDateFormat - 如何防止重新格式化时区
SimpleDateFormat - how to prevent timezone being reformatted
当我解析 String
然后格式化生成的 Date
.
时,我遇到 SimpleDateFormat
更改 datetimestamp
外观的问题
下面的代码片段演示了这个问题。注意:我知道用相同的 SimpleDateFormat
解析然后格式化相同的日期似乎是徒劳的,但这是一个人为的例子,只是为了说明原理:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
try {
Date date = dateFormat.parse(dateStringToConvert);
String convertedDateString = dateFormat.format(date);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
} catch (ParseException e) {
e.printStackTrace();
}
输出结果如下:
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000Z
由于此日期将用于自动测试以填写表格,因此 datetimestamp
的格式在被 [=11= 解析和格式化后保持完全相同很重要], 所以我不希望它删除 -00:00
并添加 Z
.
这似乎是一个非常简单的问题,但我找不到任何明显的答案。
试试这个:
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat df = new SimpleDateFormat(pattern) {
public StringBuffer format(Date date, StringBuffer prefix, FieldPosition fieldPosition) {
StringBuffer finalStr = super.format(date, prefix, fieldPosition);
finalStr = finalStr.insert(finalStr.length()-2, ':');
finalStr = finalStr.deleteCharAt(finalStr.length() - 6);
finalStr = finalStr.insert(finalStr.length() - 5, '-');
return finalStr;
};
};
System.out.println(df.format(yourDate));
正如 Jon Skeet 在 中所说,没有办法绕过硬编码这一特殊要求。
DateTimeFormatter formatter;
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
if (dateStringToConvert.endsWith("-00:00")) {
formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm:ss.SSS'-00:00'")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
} else {
formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
}
OffsetDateTime dateTime = OffsetDateTime.parse(dateStringToConvert, formatter);
String convertedDateString = dateTime.format(formatter);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
这会打印
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000-00:00
正如已经说过的,-00:00
的偏移量(负零)不等同于零偏移量,因此将字符串解析为 [=13 确实是不正确的=] 和我一样。在这种情况下,代码的正确版本将解析为 LocalDateTime
并使用相同的格式化程序格式化 LocalDateTime
。它总体上会更长一些,另一方面,您将不再需要 parseDefaulting
调用。
我正在使用并热烈推荐 java.time
,现代 Java 日期和时间 API。因为 Date
、DateFormat
和 SimpleDateFormat
早已过时,并且已被证明在不同程度上使用起来很麻烦。现代的 API 好多了。
Link: Oracle tutorial: Date Time 解释如何使用 java.time
恐怕SimpleDateFormat
帮不了你。这个class设计的很差,而且非常有限,更不用说它存在的所有问题了:https://eyalsch.wordpress.com/2009/05/29/sdf/
如果你有Java8,就用java.time
API。不确定为什么要将 String
转换为 Date
只是为了将其转换回另一个 String
,但是如果您希望最终结果为 String
和 -00:00
作为偏移量,那么你可以这样做:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
// offset, use "-00:00" when it's zero
.appendOffset("+HH:MM", "-00:00")
// create formatter, always work in UTC
.toFormatter().withZone(ZoneOffset.UTC);
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
Instant instant = fmt.parse(dateStringToConvert, Instant::from);
String result = fmt.format(instant);
System.out.println(result);
这将打印:
2016-03-12T22:00:00.000-00:00
当我解析 String
然后格式化生成的 Date
.
SimpleDateFormat
更改 datetimestamp
外观的问题
下面的代码片段演示了这个问题。注意:我知道用相同的 SimpleDateFormat
解析然后格式化相同的日期似乎是徒劳的,但这是一个人为的例子,只是为了说明原理:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
try {
Date date = dateFormat.parse(dateStringToConvert);
String convertedDateString = dateFormat.format(date);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
} catch (ParseException e) {
e.printStackTrace();
}
输出结果如下:
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000Z
由于此日期将用于自动测试以填写表格,因此 datetimestamp
的格式在被 [=11= 解析和格式化后保持完全相同很重要], 所以我不希望它删除 -00:00
并添加 Z
.
这似乎是一个非常简单的问题,但我找不到任何明显的答案。
试试这个:
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat df = new SimpleDateFormat(pattern) {
public StringBuffer format(Date date, StringBuffer prefix, FieldPosition fieldPosition) {
StringBuffer finalStr = super.format(date, prefix, fieldPosition);
finalStr = finalStr.insert(finalStr.length()-2, ':');
finalStr = finalStr.deleteCharAt(finalStr.length() - 6);
finalStr = finalStr.insert(finalStr.length() - 5, '-');
return finalStr;
};
};
System.out.println(df.format(yourDate));
正如 Jon Skeet 在
DateTimeFormatter formatter;
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
if (dateStringToConvert.endsWith("-00:00")) {
formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm:ss.SSS'-00:00'")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
} else {
formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
}
OffsetDateTime dateTime = OffsetDateTime.parse(dateStringToConvert, formatter);
String convertedDateString = dateTime.format(formatter);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
这会打印
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000-00:00
正如已经说过的,-00:00
的偏移量(负零)不等同于零偏移量,因此将字符串解析为 [=13 确实是不正确的=] 和我一样。在这种情况下,代码的正确版本将解析为 LocalDateTime
并使用相同的格式化程序格式化 LocalDateTime
。它总体上会更长一些,另一方面,您将不再需要 parseDefaulting
调用。
我正在使用并热烈推荐 java.time
,现代 Java 日期和时间 API。因为 Date
、DateFormat
和 SimpleDateFormat
早已过时,并且已被证明在不同程度上使用起来很麻烦。现代的 API 好多了。
Link: Oracle tutorial: Date Time 解释如何使用 java.time
恐怕SimpleDateFormat
帮不了你。这个class设计的很差,而且非常有限,更不用说它存在的所有问题了:https://eyalsch.wordpress.com/2009/05/29/sdf/
如果你有Java8,就用java.time
API。不确定为什么要将 String
转换为 Date
只是为了将其转换回另一个 String
,但是如果您希望最终结果为 String
和 -00:00
作为偏移量,那么你可以这样做:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
// offset, use "-00:00" when it's zero
.appendOffset("+HH:MM", "-00:00")
// create formatter, always work in UTC
.toFormatter().withZone(ZoneOffset.UTC);
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
Instant instant = fmt.parse(dateStringToConvert, Instant::from);
String result = fmt.format(instant);
System.out.println(result);
这将打印:
2016-03-12T22:00:00.000-00:00