mysql数据库,datetime类型的数据,springboot项目,如何指定展示的时区(默认会转换成应用服务器的时区)?

感谢大家的回答,我最开始对datetime类型理解有偏差,现在理顺了,我重新编辑了一下

1.只有一套应用代码,部署在东八区
2.印度(东五区)、越南(东七区)的客户(浏览器)都要访问该应用,
3.每个国家的数据库是独立的,表结构一模一样,在应用中通过切换不同的数据源访问不同的数据库
4.比如,不同的国家在网站上进行操作,“操作时间”是后端new date()生成的(东八区),以datetime类型存到数据库
5.有一个公用接口查询操作时间,目前在该接口中可以通过session判断出不同的国家,@RestController返给前端的是一个实体类(返回的时候时间会被序列化成字符串)

需求
印度用户查询操作时间,接受到东五区的时间,越南用户查询接受到东七区时间


1.项目已经成型,多处用到该字段,数据库字段的datetime类型已经无法修改成时间戳,只能继续用datetime类型
2.也无法全局配置spring.jackson.time-zone,因为不同国家需要不同时区

我的想法是能不能从controller层想办法,因为在接口中是可以判断出不同国家的

阅读 3.1k
3 个回答

老哥看你问了不少问题,也邀请了我很多次,我很想帮助你,但是你提的“问题“的”问题“在于,你没有将问题解剖的足够细致,实际上你的问题打包了很多个问题、环境细节、需求状况等,这由于你没有抓住问题的关键点在哪里,从而让关键点隐藏在你海量的问题中,让解答者无所适从。

这就导致回答你的问题非常的吃力不讨好,抛开你提问的范围不谈,很多问题是需要提问者和解答者有相似的认知范围,这就像是一个会烧开水的师傅,和一个知道核电站发电本质上就是烧开水的核能领域教授一样,虽然看起来有相同的目的,但实际上完全不一样。

而到了你的问题中,大部分时间是需要先纠正你的认知的,然而大多数时候这是很困难的,因为认知到什么程度是你一个人的事情,解答者并不能帮你太多。


回到问题,其实你的问题很简单,跟 mysql、代码、数据库类型根本没关系,实际上你的问题完全能简化成一句话:

怎样让后台系统获取到不用地区客户端请求的时区

你自己说了服务器都部署在相同时区的服务器上,那么你存入数据库的时间根本就跟只有一个时区,你的存入时区和你服务器的时区必须相同,你真正要做的是:

让服务端确定客户端请求的时区,然后把数据库时间拿出来,根据然后客户端想要的时区做转换。

就是这么简单。

(根据@扬帆起航补充的,你更加需要理解什么是时间戳

接着往下来,你的问题实际上还能够拆分成下面的问题

javascript 怎么获取时区?

java 怎么做时区转换

javascript ajax 怎么增加自定义 header

这提问是不是更简单了?这时你提问的目标(javascript)和主题(获取时区)都很明确了。此时你把这些问题复制粘贴到最烂的百度,你都能很轻易在第一条获取到答案:
image.png


最后送你一句话:

你想要获得正确的答案,就必须学会提出正确的问题

更新

你这次的问题就比较清晰了。

下面是解决方案:

第一步:Jackson2ObjectMapperBuilder

实现 Jackson2ObjectMapperBuilderbean,其作用是改变 spring boot(默认你是 spring boot)序列化反序列化的行为:

@Bean
@Primary
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
    return new Jackson2ObjectMapperBuilder().serializerByType(Date.class, new DateSerializer());
}

第二步: StdSerializer

自定义自己序列化 Date 对象的行为,在重写的 serialize 方法中改变时区,如果你的 session 是存储在线程上下文中的,那么这个方法中也能够获取到,否则自己想办法把时区信息放进线程上下文

public class DateSerializer extends StdSerializer<Date> {
    protected DateSerializer() {
        super(Date.class);
    }

    @Override
    public void serialize(Date value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // 在这里处理你的时区
        gen.writeString(value.toString() + "这是一个测试");
    }
}

最后

这样就能够既方便又简单的解决这个问题了,我试验的环境是 spring boot 2.7,实测通过:
image.png

再次声明一遍,跟你数据库存什么没关系,你怎么样都是要到内存中处理的。

这个问题我的理解应该是这样的:

解决方法应该是连接的时候指定时区。比如这个程序部署在东八区,那么mysql连接的时候指定东八区。

  1. mysql datetime本身不带时区,时区是根据应用写入的时候确定的,可以类比字符串
  2. 同一套应用,不同的前端展示,这属于业务控制,需要在前端或者controller里面进行数据转换

所以基于以上两点,解决思路可以参考以下

  1. 后端写数据和数据库里存数据,统一使用固定时区,如utc,可以通过统一服务器的tz参数来实现
  2. 后端返回给前端,统一返回utc时区的时间值
  3. 前端根据用户浏览器的时区设置,转换utc时间
    大致整理一下,先定一个统一的时区,然后只在最贴近用户的地方,进行时区转换
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏