【问题标题】:How to change Java Date timezone from server local timezone to a different timezone for a spring boot native query?如何将 Java Date 时区从服务器本地时区更改为 Spring Boot 本机查询的不同时区?
【发布时间】:2021-12-04 04:34:11
【问题描述】:

我在数据库中有记录,其中列 created_date 保存为没有时区的时间戳。前端用户位于 +05.30 时区。后端托管在新加坡。因此 created_date 日期值比用户时间晚 5.30 小时。

如何正确选择在给定日期内创建的一组记录。

例如:如果用户在 2021 年 16 月 16 日请求数据,则服务器需要返回 created_date 在 2021-10-16 00:00:00 和 2021-10-16 23:59:59 之间的数据:他们当地时间是 999,即 +05.30

我为此编写了一个本机查询,如下所示,

select * from records rr where rr.created_date at time zone 'utc' at time zone 'Asia/Calcutta' between ?1 and ?2

我使用以下代码获得日期 1 和 2,仅在用户的时区 (+05.30) 上午 5.30 之后提供所需的数据集

Calendar startDate = (Calendar) Calendar.getInstance();
startDate.set(Calendar.HOUR_OF_DAY, 0);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
startDate.set(Calendar.MILLISECOND, 0);
                        
Calendar endDate = (Calendar) startDate.clone();
endDate.set(Calendar.HOUR_OF_DAY, 23);
endDate.set(Calendar.MINUTE, 59);
endDate.set(Calendar.SECOND, 59);
endDate.set(Calendar.MILLISECOND, 999);

Date fromDate = startDate.getTime();
Date toDate = endDate.getTime();

所以,假设我需要将 startDate 和 endDate 转换为用户的本地时区,然后作为查询的参数传递,我做了以下,

Calendar startDate = (Calendar) Calendar.getInstance();
startDate.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta")); // convert from server timezone to user's local timezone
startDate.set(Calendar.HOUR_OF_DAY, 0);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
startDate.set(Calendar.MILLISECOND, 0);   
                        
Calendar endDate = (Calendar) startDate.clone();
endDate.set(Calendar.HOUR_OF_DAY, 23);
endDate.set(Calendar.MINUTE, 59);
endDate.set(Calendar.SECOND, 59);
endDate.set(Calendar.MILLISECOND, 999);

Date fromDate = startDate.getTime();
Date toDate = endDate.getTime();

这仍然没有返回正确的数据集。如果我直接在 pgadmin 上运行以下查询,我可以获得结果

select * from records rr where rr.created_date at time zone 'utc' at time zone 'Asia/Calcutta' between '2021-10-16 00:00:00' and '2021-10-16 23:59:59' 

如何使用我的代码获得相同的数据集?任何帮助将非常感激。 TIA

【问题讨论】:

  • 您正在使用糟糕的日期时间类,这些类现在已经过时了。 Date 和 SimpleDateFormat 在几年前被 JSR 310 中定义的现代 java.time 类所取代。

标签: java spring postgresql spring-boot hibernate


【解决方案1】:

你说:

column created_date 保存为没有时区的时间戳

这是记录时刻的错误数据类型。时间线上的特定点必须写入TIMESTAMP WITH TIME ZONE 类型的列,而不是WITHOUT。

Postgres 使用与任何输入一起提供的与 UTC 的偏移量或时区信息来调整到 UTC。 Postgres 中 TIMESTAMP WITH TIME ZONE 列中的值始终采用 UTC 格式。

你说:

在 pgadmin 上运行以下查询

不幸的是,包括 pgAdmin 在内的许多工具都具有反功能,它们会应用一些默认时区来调整从数据库中检索到的值。这给人一种错误的错觉,即该值已存储在特定时区中。但正如我所说,Postgres 中TIMESTAMP WITH TIME ZONE 列中的值始终采用 UTC,始终如此。我建议始终将 pgAdmin 会话默认时区设置为 UTC。

切勿使用Calendar 或Date。仅在 JDBC 4.2 或更高版本中使用 java.time 类。

时区Asia/Calcutta 已重命名为Asia/Kolkata。

如果您想要现代印度的一天的开始和结束??:

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
LocalDate today = LocalDate.now( z ) ;
ZonedDateTime start = today.atStartOfDay( z ) ;
ZonedDateTime end = today.plusDays( 1 ).atStartOfDay( z ) ;

我们使用半开放方法来定义时间跨度,通常最适合日期时间工作。

在传递给PreparedStatement 之前转换为OffsetDateTime,以使用适合SQL 的数据类型。

OffsetDateTime startOdt = start.toOffsetDateTime() ;

你写道:

Calendar startDate = (Calendar) Calendar.getInstance();

这里不需要投射。该方法已经返回了一个Calendar 对象,所以强制转换是没有意义的。 (而且,永远不要使用Calendar。)

我在这里已经很简短了,因为这个话题已经在 Stack Overflow 上讨论过很多次了。搜索以了解更多信息。

【讨论】:

  • 正确。致 OP:您可以查看 this answer 和 this answer 以了解如何将 java.time API 与 JDBC 一起使用。
  • 感谢您的意见!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2015-04-23
  • 2019-09-30
  • 2011-06-09
  • 2013-04-26
相关资源
最近更新 更多