java - 来自 Spring 的 Json 响应中的时区问题
问题描述
我在 JSON 输出中显示日期时遇到问题。在我使用的代码中java.util.Date
,它的值是2019-03-07
但在 JSON 中我得到了2019-03-06 23:00:00
. 我认为问题出在时区,但我不在数据库和代码中使用时区。
我试图用
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone="UTC")
和
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone="Europe/Warsaw")
第一个没有帮助,第二个有帮助,但我不接受这个解决方案。
我的控制器的一部分:
return new ThisDay(
sysoperMgr.getToday(),
new Date()
);
这是我返回的对象。
@Getter
@Setter
public class ThisDay {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
Date dataZamkniecia;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
Date dataSystemowa;
public BiezacaDoba(Date dataZamkniecia, Date dataSystemowa) {
this.dataZamkniecia = dataZamkniecia; // cdate = 2019-03-07T00:00:00.000+0100
this.dataSystemowa = dataSystemowa; // cdate = 2019-03-27T16:08:12.343+0100
}
}
此函数获取日期:
public Date getToday() {
Timestamp timestamp = sysoperDao.getDataOstatniejZamknietejDoby(); // cdate = 2019-03-06T00:00:00.000+0100
java.util.Date lastDay = new java.sql.Date(misc.roundTimestamp(timestamp).getTime()); // cdate = 2019-03-06T00:00:00.000+0100
java.util.Date thisDay = misc.incrementDate(ostatniaDoba, Increment.DAILY, 1); // cdate = 2019-03-07T00:00:00.000+0100
return thisDay;
}
json结果:
{
"dataZamkniecia":"2019-03-06 23:00:00",
"dataSystemowa": "2019-03-27 15:12:15"
}
如何让 JSON 始终在本地时区显示日期?
解决方案
Date
Java 8
是过时的类,自发布包以来不应使用,java.time
或者我们可以使用Joda-Time。您正在将日期从 转换Timestamp
为java.sql.Date
并稍后转换为java.util.Date
。这是非常不安全的,请参见下面的示例:
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// Java time precise dates
LocalDate localDateOpened = LocalDate.of(2019, 03, 07);
LocalDate localDateClosed = localDateOpened.plusDays(20);
ZoneId utc = ZoneId.of("UTC");
Date opened = Date.from(localDateOpened.atStartOfDay(utc).toInstant());
Date closed = Date.from(localDateClosed.atStartOfDay(utc).toInstant());
System.out.println("Dates generated from java.time.*");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
// Calculate dates with default timezone
Calendar calendar = Calendar.getInstance();
opened = calendar.getTime();
calendar.add(Calendar.DAY_OF_MONTH, 20);
closed = calendar.getTime();
System.out.println("Dates generated from Calendar");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
// Calculate dates with UTC timezone
calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone(utc));
calendar.set(Calendar.MILLISECOND, 0); // Recompute
opened = calendar.getTime();
calendar.add(Calendar.DAY_OF_MONTH, 20);
closed = calendar.getTime();
System.out.println("Dates generated from UTC Calendar");
System.out.println(mapper.writeValueAsString(new ThisDay(opened, closed)));
}
}
class ThisDay {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date opened;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date closed;
public ThisDay(Date opened, Date closed) {
this.opened = opened;
this.closed = closed;
}
public Date getOpened() {
return opened;
}
public void setOpened(Date opened) {
this.opened = opened;
}
public Date getClosed() {
return closed;
}
public void setClosed(Date closed) {
this.closed = closed;
}
}
上面的代码打印:
Dates generated from java.time.*
{
"opened" : "2019-03-07 00:00:00",
"closed" : "2019-03-27 00:00:00"
}
Dates generated from Calendar
{
"opened" : "2019-03-27 23:45:12",
"closed" : "2019-04-16 22:45:12"
}
Dates generated from UTC Calendar
{
"opened" : "2019-03-28 00:45:12",
"closed" : "2019-04-17 00:45:12"
}
请注意,第二个和第三个opened
日期相差一小时。我手动将日历时区设置为UTC
并强制重新计算将毫秒设置为的值0
:
calendar.setTimeZone(TimeZone.getTimeZone(utc));
calendar.set(Calendar.MILLISECOND, 0); // Recompute
这就是为什么Date
已经过时并且java.time
应该使用包的原因。如果您不想显示时间,只需将日期更改为@JsonFormat(pattern = "yyyy-MM-dd")
.
也可以看看:
推荐阅读
- css - 如何在悬停时填充带有背景的字体图标?
- google-cloud-platform - GCP - 无法将磁盘附加到现有实例
- excel - 带有 VBA 的 Excel 中的一次性时间戳
- c - 如何将字符串拆分为结构?
- linux - 在 Ubuntu 下使用 snap 时如何将 nvim 添加到 update-alternatives
- google-bigquery - Google BigQuery:为什么由不同表联合生成的表在预览模式下不显示任何值?只有在运行查询时才会这样做?
- c# - 如何从我的 VS 2019 解决方案资源管理器中删除波浪线
- java - 无法调用“java.sql.Connection.prepareStatement(String)”,因为“connection”为空
- excel - 如何正确计算 VBA Excel 中的可见行数?
- rxjs - EMPTY observable 的 RxJS 类型签名?