Java SimpleDataFormat-如何防止时区被重新格式化
当我解析Java SimpleDataFormat-如何防止时区被重新格式化,java,datetime,simpledateformat,datetime-format,datetime-parsing,Java,Datetime,Simpledateformat,Datetime Format,Datetime Parsing,当我解析字符串并格式化生成的日期时,我在更改日期时间戳的外观方面遇到问题 下面的代码片段演示了这个问题。注意:我知道用相同的SimpleDateFormat解析并格式化相同的日期似乎是徒劳的,但这是一个人为的示例,只是为了演示以下原则: DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); String dateStringToConvert = "2016-03-
字符串
并格式化生成的日期
时,我在更改日期时间戳
的外观方面遇到问题
下面的代码片段演示了这个问题。注意:我知道用相同的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();
}
其结果如下:
通缉令:2016-03-12T22:00:00.000-00:00
实际日期:2016-03-12T22:00:00.000Z
由于此日期将用于自动测试以填写表单,因此重要的是,datetimestamp
的格式在被SimpleDateFormat
解析和格式化后保持完全相同,因此我不希望它删除-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));
试试这个:
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
(负零)的偏移量不等于零偏移量,因此像我这样将字符串解析为OffsetDateTime
是完全不正确的。在这种情况下,代码的正确版本将解析为LocalDateTime
,并使用相同的格式化程序将LocalDateTime
格式化回原处。从另一方面来说,它总的来说要长一点,您将不再需要parseDefaulting
调用
我正在使用并热情推荐
java.time
,这是一种现代的java日期和时间API。因为Date
,DateFormat
和SimpleDateFormat
早已过时,并且在不同程度上被证明是很麻烦的。现代的API好得多
链接:解释如何使用java.time
正如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
(负零)的偏移量不等于零偏移量,因此像我这样将字符串解析为OffsetDateTime
是完全不正确的。在这种情况下,代码的正确版本将解析为LocalDateTime
,并使用相同的格式化程序将LocalDateTime
格式化回原处。从另一方面来说,它总的来说要长一点,您将不再需要parseDefaulting
调用
我正在使用并热情推荐
java.time
,这是一种现代的java日期和时间API。因为Date
,DateFormat
和SimpleDateFormat
早已过时,并且在不同程度上被证明是很麻烦的。现代的API好得多
链接:解释如何使用
java.time
恐怕SimpleDateFormat
帮不了你。该类设计拙劣且非常有限,更不用说它存在的所有问题:
如果您有Java8,只需使用Java.time
API即可。不确定为什么要将字符串
转换为日期
,只是为了将其转换回另一个字符串
,但如果希望最终结果作为字符串
,并将-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
恐怕
SimpleDateFormat
帮不了你。该类设计拙劣且非常有限,更不用说它存在的所有问题:
如果您有Java8,只需使用Java.time
API即可。不确定为什么要将字符串
转换为日期
,只是为了将其转换回另一个字符串
,但如果希望最终结果作为字符串
,并将-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
无法保存文本是否表示为“+00:00”、“-00:00”或“Z”。这不是解析值的一部分。如果要保留相同的文本表示,只需保留字符串即可。同样值得注意的是,“-00:00”实际上与RFC 3339中的“+00:00”有着非常不同的含义。谢谢Jon的评论。我上面以字符串开头的示例可能会混淆我的问题。一种简单得多的表达问题的方法是:如何确保SimpleDateFormt.parse返回的字符串格式为2016-03-12T22:00:00.000-00:00,而不是2016-03-12T22:00:00.000Z?从你的评论来看,也许答案是你根本无法做到这一点?如果有任何格式(硬编码除外)返回-00:00,我会感到惊讶(也会感到担心),因为它具有奇怪的含义。+00:00(表示“本次与UTC之间无差异”)是可以接受的,还是您打算使用-00:00(“当地时间,我们不知道偏移量”)的意思?如果是这样的话,
Date
是不幸的,因为它代表了时间上的一个瞬间……SimpleDateFormat
早已过时,并且出了名的麻烦。它可能无法解决您的问题,但我建议您改为使用。答案非常清楚:您不能使用parse
方法来获取看起来像任何东西的String
,因为parse
方法返回的是Date
,而不是String
。无法保留文本是否表示为“+00:00”、“-00:00”或“Z”。这不是解析值的一部分。如果要保留相同的文本表示,只需保留字符串即可。还值得注意的是,-00:00”实际上与“+00:00”有非常不同的含义“在RFC 3339中。谢谢你的评论Jon。我上面以字符串开头的示例可能会混淆我的问题。一种简单得多的表达问题的方法是:如何确保SimpleDateFormt.parse返回