根据自定义TimeZone不会显示日期。始终选择默认时区

时间:2017-09-29 11:40:56

标签: java datetime jackson datetime-parsing

尝试了所有可能的组合,创建了自定义JsonDeserializer类,并根据需要修改了DateFormat。但仍然没有多少成果。

但结果总是在“EST'”中显示日期。 1月1日星期六14:08:56 EST 2000。 我希望我的日期以UTC显示,或者根据客户需要更加可配置。

public class CustomJsonDeserializerWithDateFormat extends JsonDeserializer<Date>{

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); 
        TimeZone TZ = TimeZone.getTimeZone("US/Central");
        dateFormat.setTimeZone(TZ); 
        dateFormat.getCalendar().setTimeZone(TZ);
        Calendar newCalendar = new GregorianCalendar();
        newCalendar.setTimeZone(TZ);
        dateFormat.setCalendar(newCalendar);
        //ZonedDateTime 
        System.out.println("Time Zone : "+dateFormat.getTimeZone());
        JsonToken t = p.getCurrentToken();

        if (t == JsonToken.VALUE_STRING) {
            String value = p.getText().trim();
            try {
                Date formattedDate = dateFormat.parse(value);
                DateFormat formatter = new SimpleDateFormat
                        ("EEE MMM dd HH:mm:ss zzz yyyy");
                TimeZone central = TimeZone.getTimeZone("America/Chicago");
                formatter.setTimeZone(central);
                Date fromDate = (Date)formatter.parse(formattedDate.toString());

                System.out.println(fromDate);

                DateTimeFormatter f = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu" , Locale.ENGLISH );
                ZonedDateTime zdt = ZonedDateTime.parse ( formattedDate.toString() , f );
                System.out.println(zdt.toString());
                ZoneId z = ZoneId.of( "America/Chicago" );
                ZonedDateTime zdtChicago = zdt.withZoneSameInstant( z );
                System.out.println(zdtChicago.toString());
                return fromDate;
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }   
}

1 个答案:

答案 0 :(得分:0)

如果您有新的java.time课程,则无需将其与旧SimpleDateFormat混合使用。要解析输入2000-01-01T12:08:56.235-0700,只需使用java.time.format.DateTimeFormatter并将其解析为java.time.OffsetDateTime - 这种情况的最佳选择,因为它代表日期和时间(2000-01-01T12: 08:56.235)特定偏移量(-0700)。

然后使用java.util.Date方法将其转换为from。你的解串器就像这样简单:

public class CustomJsonDeserializerWithDateFormat extends JsonDeserializer<Date> {

    // will deserialize inputs in the format "2000-01-01T12:08:56.235-0700"
    private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXX");

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        // parse input
        OffsetDateTime odt = OffsetDateTime.parse(p.getText(), fmt);
        // convert to java.util.Date
        return Date.from(odt.toInstant());
    }
}

我还重新创建了您的课程,并使用一些示例数据进行了测试:

public class RuntimePropertyData {

    @JsonProperty("begin-date")
    @JsonDeserialize(using = CustomJsonDeserializerWithDateFormat.class)
    private Date beginDate;

    // getter and setter
}

ObjectMapper om = new ObjectMapper();
Map<String, String> map = new HashMap<>();
map.put("begin-date", "2000-01-01T12:08:56.235-0700");
RuntimePropertyData data = om.convertValue(map, RuntimePropertyData.class);
System.out.println(data.getBeginDate());

现在这是棘手的部分。一个java.util.Date doesn't have any timezone information。此类只有一个值:自UTC时间(1970-01-01T00:00Z&#34; 1月1日 st 1970年午夜UTC&#34; )。它只是代表一个瞬间,一个特定的时间点。

当我System.out.println一个Date时(或者当我记录它,或者在调试器中检查它的值时),它隐含地调用toString() method,并将日期转换为JVM默认时区。因此,当您看到Sat Jan 01 14:08:56 EST 2000时,这是Date&#39; toString()的结果。

如果您想在序列化日期时更改格式,可以使用@JsonFormat为字段添加注释,并设置所需的时区:

@JsonProperty("begin-date")
@JsonDeserialize(using = CustomJsonDeserializerWithDateFormat.class)
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX", timezone = "UTC")
private Date beginDate;

然后,如果我序列化它:

// data is the same RuntimePropertyData I've got from the code above
System.out.println(om.writeValueAsString(data));

这将产生以下JSON(日期为UTC):

  

{&#34;开始最新&#34;:&#34; 2000-01-01T19:08:56.235Z&#34;}

要更改时区,您还可以在ObjectMapper中进行设置。在这种情况下,我必须从注释中删除它:

@JsonProperty("begin-date")
@JsonDeserialize(using = CustomJsonDeserializerWithDateFormat.class)
// just the format, without timezone
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
private Date beginDate;

然后我在映射器中设置时区:

om.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
System.out.println(om.writeValueAsString(data));

现在输出是:

  

{&#34;开始最新&#34;:&#34; 2000-01-01T13:08:56.235-0600&#34;}

不幸的是,如果我再次设置时区,它就不会再改变输出了(我使用Jackson 2.8.8)。显然,保留了第一个序列化中使用的时区,并且进一步修改没有任何效果 - 因此,如果您需要高度自定义的输出(时区总是可以更改),解决方案是始终创建新的ObjectMapper