这个问题根本上是前端时区和数据库时区不一致导致的,最简单的方式就是把db的链接手动设置时区,这样的话就可以解决时区问题,但是这样还有一个问题.如果用户不在你的时区登录你的系统的话,这样的解决方式就失效了,接下来我就会给出一个完美的答案,因为公司的db链接规定的是新加坡,而我在中国,测试必出现问题,所以想到了下面的解决方案.
Front-End
首先是前端的处理,我是用的是angular,使用的是TypeScript
private convert(holiday: Holiday): Holiday {
holiday.fromDate = new Date(holiday.fromDate.getTime() + Math.abs(new Date().getTimezoneOffset()) * 60 * 1000);
holiday.toDate = new Date(holiday.toDate.getTime() + Math.abs(new Date().getTimezoneOffset()) * 60 * 1000);
const copy: Holiday = Object.assign({}, holiday);
return copy;
}
这段代码是重要的转换代码,因为从前端取到的时间都是带有时区的,这时候我们手动把这个带有时区的时间转换成UTC,也就是国际标准时间,从而消除了时区的影响,这时候只需要在call back-end api 的时候call一下这个方法
create(holiday: Holiday): Observable<Holiday> {
const copy = this.convert(holiday);
return this.http.post(this.holidayAdminUrl, copy).pipe(
map((res: any) => {
const jsonResponse = res.body;
this.convertItemFromServer(jsonResponse);
return jsonResponse;
})
);
}
就可以了.
Back-End
其实后端的code都差不多,但是有一个问题必须要注意,使用的时间类型必须是包含时分秒的,不能是例如LocalDate这种类型,因为这种只包含日月年,这样就会导致我们前端对时区的处理完全失效了.我个人使用的是Timestamp,做逻辑处理的时候再转成Calendar来处理.
Enhance
使用 ZonedDateTime, 可以看我另外一篇blog.
前端传过来之后用 ZonedDateTime转成UTC进行存储.
Enhance2
或者后端使用Instant作为字段类型,前端传入用toJSON(),这样就不会有时区问题了
@Column(name = "start_dt")
private Instant startDt;
@Column(name = "end_dt")
private Instant endDt;
protected convertDateFromClient(record: IRecord): IRecord {
const copy: IRecord = Object.assign({}, record, {
startDt: record.startDt && record.startDt.isValid() ? record.startDt.toJSON() : undefined,
endDt: record.endDt && record.endDt.isValid() ? record.endDt.toJSON() : undefined,
});
return copy;
}
前端接收的时候用moment把Date String 转换成moment就可以了.
//"moment": "2.27.0",
import * as moment from 'moment';
query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IRecord[]>(this.resourceUrl, { params: options, observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}
protected convertDateArrayFromServer(res: EntityArrayResponseType): EntityArrayResponseType {
if (res.body) {
res.body.forEach((record: IRecord) => {
record.startDt = record.startDt ? moment(record.startDt) : undefined;
record.endDt = record.endDt ? moment(record.endDt) : undefined;
});
}
return res;
}