Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SimpleDataFormat-如何防止时区被重新格式化_Java_Datetime_Simpledateformat_Datetime Format_Datetime Parsing - Fatal编程技术网

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返回