Спасибо за ответ; в ОП я думал об этой строке, но не правильно сказал:
log.info("The result should be 14:34 CEST: {}", result);
Я подумал, что это похоже на «Итак, я хочу, чтобы это был Мадрид, поэтому выходной результат - часовой пояс Мадрида», но наоборот:
Часовой пояс устройства форматирования будет входной датой / часовым поясом строки, а часовой пояс по умолчанию (если не изменен, то JVM, если изменено, значение Timezone.getDefault()
будет выходным результатом ( часовой пояс даты / строки). На основе этих двух форматер выполнит преобразование.
И Spring / Jackson внутренне использует SimpleDateFormat
для выполнения сериализации / десериализации JSON / Object, поэтому это будет правилом и для Spring
И, как я проверяю, spring.jackson.time-zone
и mapper.setTimezone()
будут переопределены JsonFormat(timezone = "xxx")
на полях. То есть spring.jackson.time-zone
является более общим и применяется ко всем полям Date, которым требуется часовой пояс "input", а JsonFormat(timezone = "xxx")
является более конкретным и переопределяет предыдущий. Я думаю, spring.jackson.dateformat
и @JsonFormat(pattern = "xx")
имеют такие же отношения, но я не проверял.
Графический:
Я пишу этот тест, чтобы продемонстрировать это:
/**
* Test the effect of setting timezone on a {@link SimpleDateFormat}. Apparently,
* <code>f.setTimezone()</code> sets the input timezone, and default timezone sets
* the output timezone.
*
*/
@Test
public void testTimezoneSettingOnSimpleDateFormat() throws ParseException {
/* *********** test parsing *********** */
log.info("********** test parsing **********");
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String d = "2018-08-08 12:34:56";
log.info("Trying to parse the date string: {}", d);
Date result = f.parse(d);
log.info("The result should be 12:34 UTC: {}", result);
f.setTimeZone(TimeZone.getTimeZone("UTC"));
result = f.parse(d);
log.info("The result should be 12:34 UTC: {}", result);
f.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
result = f.parse(d);
log.info("The result should be 10:34 UTC: {}", result);
/* ********** test formatting ********** */
log.info("********** test formatting **********");
// given
SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
// construct a date to represent this moment
OffsetDateTime now = OffsetDateTime.of(2018, 11, 16, 10, 22, 22, 0, ZoneOffset.of("+0100"));
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); // GMT+8, so Madrid+7
// when you construct a date without timezone, it will be the timezone of system/default!
Date nowDate = new Date(now.toEpochSecond() * 1000);
log.info("The constructed date is: {}", nowDate); // Fri Nov 16 17:22:22 CST 2018
// now formatter timezone is Madrid
f2.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
// now default timezone is Asia/Shanghai
// when
String result2 = f2.format(nowDate);
// then
log.info("The result should be 10:22: {}", result2); // 2018-11-16T10:22:22+01:00
log.info("Conclusion: the formatter's timezone sets the timezone of input; the application/default " +
"timezone sets the timezone of output. ");
}