当前位置: 首页 > news >正文

记录一次问题排查,前台传的日期参数到后台取到的时候少了一天。

文章目录

  • 问题概述
  • 一、核心原因分析
  • 二、时区问题解决方案(分为改代码或者改服务器)
    • 第一类方案 代码调整
      • 方案 1:全局配置 Jackson 时区(推荐)
      • 方案 2:在实体类字段上指定时区(精准控制)
      • 方案 3:使用带时区的日期类型(避免歧义)
    • 第二类方案,服务器调整
      • 查看当前时区
        • 方法一:使用 `date +%Z` 命令
        • 方法二:使用 `timedatectl` 命令
      • 临时修改时区
        • 使用 `TZ` 环境变量
      • 永久修改时区
        • 方法一:使用 `timedatectl` 命令
        • 方法二:手动修改 `/etc/timezone` 和 `/etc/localtime` 文件
    • 时间问题解决方案
      • 出现时区错误时的修改办法
        • 日期时间设置错误
          • 使用 `date -s` 命令临时设置时间
          • 使用 `ntp` 同步时间
          • 直接设置系统时间(永久生效,写入硬件时钟)
        • 时区文件损坏

问题概述

我的问题是前台通过http请求,向后台发送请求,请求参数中有一个日期参数以json的形式传参给后台。

{
date:“2025-01-08”
}
我通过日志打印,可以看到后台将json转为对象的时候对象的date属性的值是2025-01-07。可以看到是少了一天的。即前台传过来的对象只进行了spring的类型转换就少了一天。

这里简单记录一下排查的思路:
首先将同样的代码和配置扔到其它测试环境的服务器上去部署,发现没有问题。这证明了代码和配置是没有问题的,问题就定位到了服务器相关的配置。问题大概率是由于服务器时区与前端时区不一致导致的日期转换偏差(例如前端发送的是本地时区日期,而服务器默认使用UTC时区处理,导致日期计算时减去时区差后跨天)

一、核心原因分析

  1. 时区差异
    前端发送的日期字符串(如 2025-01-08)默认是本地时区(如东八区 UTC+8)的日期,而 Spring 在反序列化 JSON 时,若未显式指定时区,会使用 服务器的默认时区(可能为 UTC) 进行转换。
    例如:前端时间 2025-01-08 00:00:00(UTC+8) 转换为 UTC 时间是 2025-01-07 16:00:00,若仅取日期部分(忽略时间),就会显示为 2025-01-07

二、时区问题解决方案(分为改代码或者改服务器)

第一类方案 代码调整

(如果是正式环境不建议调整代码,还是建议第二类方案,调整服务器时区。)

方案 1:全局配置 Jackson 时区(推荐)

在 Spring Boot 中配置 Jackson 的全局时区,确保 JSON 反序列化时使用与前端一致的时区(例如中国标准时间 UTC+8):

# application.properties 或 application.yml
spring:jackson:time-zone: GMT+8  # 或 UTC+8,与前端时区一致date-format: yyyy-MM-dd  # 显式指定日期格式(可选,默认已支持)

方案 2:在实体类字段上指定时区(精准控制)

若仅个别字段需要特殊处理,使用 @JsonFormat 注解指定时区和格式:

import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;public class YourEntity {@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")  // 与前端时区一致private Date date;// getters/setters
}

方案 3:使用带时区的日期类型(避免歧义)

建议前端发送 ISO 8601 格式的带时区日期字符串(如 2025-01-08T00:00:00+08:00),后端使用 OffsetDateTimeZonedDateTime 类型接收,再对时区进行相应的处理:

下面是前端示例:

// 假设 date 是前端获取的日期对象
const date = new Date('2025-01-08');
const utcDate = date.toISOString().split('T')[0];const data = {date: utcDate
};// 发送请求
fetch('/your-api-url', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));

下面是后端示例:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Map;@RestController
public class DateController {@PostMapping("/your-api-url")public String handleDate(@RequestBody Map<String, String> request) {String dateStr = request.get("date");LocalDate localDate = LocalDate.parse(dateStr);// 转换为 UTC 时间ZonedDateTime utcDateTime = localDate.atStartOfDay(ZoneId.of("UTC"));// 转换为服务器时区ZonedDateTime serverDateTime = utcDateTime.withZoneSameInstant(ZoneId.systemDefault());LocalDate serverDate = serverDateTime.toLocalDate();return "Received date: " + serverDate;}
}

第二类方案,服务器调整

下面是在 Linux 系统中调整时区的方法,以及出现时区调整之后服务器时间错误的修改办法,并给出了每个命令执行结果的大概的示例。由于linux服务器的区别比较大,考虑到在内网环境的同学可能有的命令没有办法获取到,所以每个功能都尽可能给出不止一种方法。

查看当前时区

方法一:使用 date +%Z 命令
  • 命令
date +%Z
  • 结果示例
UTC

这表明当前系统的时区为协调世界时(UTC)。

方法二:使用 timedatectl 命令
  • 命令
timedatectl
  • 结果示例
               Local time: Wed 2025-04-16 12:30:00 UTCUniversal time: Wed 2025-04-16 12:30:00 UTCRTC time: Wed 2025-04-16 12:30:00Time zone: UTC (UTC, +0000)
System clock synchronized: yesNTP service: activeRTC in local TZ: no

该输出显示了详细的时间信息和当前的时区设置。

临时修改时区

使用 TZ 环境变量
  • 命令
export TZ=Asia/Shanghai
date +%Z
  • 结果示例
CST

此时当前会话的时区已临时修改为中国标准时间(CST),但退出当前会话或重启系统后,时区设置会恢复原状。

永久修改时区

方法一:使用 timedatectl 命令
  • 命令
sudo timedatectl set-timezone Asia/Shanghai
  • 结果示例
               Local time: Wed 2025-04-16 20:30:00 CSTUniversal time: Wed 2025-04-16 12:30:00 UTCRTC time: Wed 2025-04-16 12:30:00Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yesNTP service: activeRTC in local TZ: no

可以看到时区已成功永久设置为 Asia/Shanghai

方法二:手动修改 /etc/timezone/etc/localtime 文件
  • 编辑 /etc/timezone 文件
sudo nano /etc/timezone

在编辑器中输入 Asia/Shanghai,然后保存并退出。

  • 更新 /etc/localtime 文件
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
date +%Z
  • 结果示例
CST

这表明时区已永久修改为 Asia/Shanghai

时间问题解决方案

对于我的问题而言到这里并没有结束,因为我的服务器时区的时间是错的,真的裂开。下面是修改时区的时间的方法。但是请注意建议先修改时区再修改时间。

出现时区错误时的修改办法

日期时间设置错误
使用 date -s 命令临时设置时间
  • 命令
sudo date -s "2025-04-18 14:30:00"
date
  • 结果示例
Fri Apr 18 14:30:00 CST 2025

特别需要注意的是,使用 date -s 命令手动设置时间只是临时的,系统重启后时间可能会恢复之前的设置

使用 ntp 同步时间
  • 安装 ntp 服务(以 Debian/Ubuntu 为例)
sudo apt-get update
sudo apt-get install ntp
  • 启动 ntp 服务并设置开机自启
sudo systemctl start ntp
sudo systemctl enable ntp
  • 验证时间同步
ntpq -p
  • 结果示例
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntp1.example.com  192.168.1.1    2 u   23   64    37    0.234    0.123   0.012

此输出表明系统正在从 ntp1.example.com 服务器同步时间。

直接设置系统时间(永久生效,写入硬件时钟)

使用 timedatectl 修改系统时间

  1. 查看当前时间状态
timedatectl

输出示例(未同步 NTP 且时间可能错误):

               Local time: Fri 2025-04-18 11:30:00 UTC       # 本地时间(错误时区)Universal time: Fri 2025-04-18 11:30:00 UTC       # UTC 时间RTC time: Fri 2025-04-18 11:30:00           # 硬件时钟(RTC)时间Time zone: UTC (UTC, +0000)                  # 当前时区(错误,应为 CST)
System clock synchronized: no                                 # NTP 未同步NTP service: inactive                            # NTP 服务未运行RTC in local TZ: no
  1. 直接设置系统时间(永久生效,写入硬件时钟)
sudo timedatectl set-time "2025-04-18 14:30:00"  # 格式:YYYY-MM-DD HH:MM:SS

执行后验证

timedatectl

输出示例(时间已修正):

               Local time: Fri 2025-04-18 14:30:00 UTC       # 时间已更新,但时区仍错误Universal time: Fri 2025-04-18 14:30:00 UTCRTC time: Fri 2025-04-18 14:30:00Time zone: UTC (UTC, +0000)                  # 时区需额外修改!
System clock synchronized: noNTP service: inactiveRTC in local TZ: no
时区文件损坏
  • 删除损坏的 /etc/localtime 文件并重新创建
sudo rm /etc/localtime
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
date +%Z
  • 结果示例
CST

这表明 /etc/localtime 文件已修复,时区设置恢复正常。

相关文章:

  • 考研系列-计算机网络-第二章、物理层
  • IntelliJ IDEA clean git password
  • 广搜bfs-P1443 马的遍历
  • 8.Rust+Axum 数据库集成实战:从 ORM 选型到用户管理系统开发
  • Python爬虫实战: 有道翻译
  • Qt 创建QWidget的界面库(DLL)
  • Jenkins 多分支管道
  • 主动防御VS自动化筛查:渗透测试与漏洞扫描的深度攻防指南
  • #systemverilog# 进程控制问题#(八)关于#0 问题的使用(三)
  • shell脚本
  • 基于Ubuntu22.04和OpenCV4.5.4的物联网人脸识别考勤机
  • SpringBoot私人西服系统开发与设计
  • FreeRTOS任务通知
  • linux如何手动设置域名与 IP 地址的映射关系
  • iOS 冷启动时间监控:启动起点有哪些选择?
  • 从零构建 Vue3 登录页:结合 Vant 组件与 Axios 实现完整登录功能
  • 【Datawhale Al春训营】气象预测(AI+航空安全)竞赛笔记
  • ProjectChrono安装
  • Oracle 19c部署之手工建库(四)
  • Axios的使用
  • 又一名90后干部被查,已有多人倒在乡镇领导岗位上
  • 人民日报任仲平:为什么中国意味着确定性、未来性、机遇性
  • 万能险新规落地:保险期限不得低于五年,明确万能险销售“负面清单”
  • 交警不在就闯红灯?上海公安用科技手段查处非机动车违法
  • 苏炳添任暨南大学体育学院院长
  • 合同约定拿850万保底利润?重庆市一中院:约定无效,发回重审