当我从数据库获取数据时遇到问题 我得到这样的数据 TIMESTAMP TIME = 2024-05-15 15:12:44.0 - Timestamp SQL (package) type 转换为即时后,我偏移了 -3 小时 像这样即时 = 2024-05-15T12:12:44Z
这是我的代码示例
package ru.goldenage.map.repository.postgres.impl;
import ru.goldenage.map.entity.postgres.CalculatedCar;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
@Slf4j
@Repository
@AllArgsConstructor
public class CarDAOImpl {
private DataSource dataSource;
private JdbcTemplate postgresTemplate;
private EntityManager em;
public List<CalculatedCar> getCalculatedCarsBy(String minutes) throws SQLException {
String sql = "SELECT tmi.p_id AS id,"
+ "tmi.p_park_id AS parkId, "
+ "tmi.p_gosnumber AS gosnumber,"
+ "tmi.p_park_name AS parkName,"
+ "taotr.p_lon AS lon,"
+ "taotr.p_lat AS lat,"
+ "p_azimuth AS vector,"
+ "p_speed AS speed,"
+ "tmi.p_mark_name AS markName,"
+ "tmi.p_mark_id AS markId,"
+ "tmi.p_transport_type AS TT_Title,"
+ "mt.p_group_id AS groupTransportType,"
+ "mt.p_title AS titleTransportType,"
+ "org.p_title AS organization,"
+ "taotr.p_time AS time,"
+ "p_kilometers AS kilometers,"
+ "coalesce(substring(tum.p_name from 0 for position(' км' in tum.p_name)), '') AS road_name,"
+ "coalesce(tmi.p_navigator, '-') AS stationNum,"
+ "tmi.p_machine_type "
+ "FROM t_machine_info AS tmi "
+ "LEFT JOIN t_machine_type AS mt on tmi.p_machine_type = mt.p_id "
+ "LEFT JOIN t_organization AS org on tmi.p_organization = org.p_id, "
+ "(SELECT * FROM t_auto_on_the_roads "
+ "WHERE p_id in (SELECT max(p_id) FROM t_auto_on_the_roads "
+ "WHERE p_time >= (current_timestamp AT TIME ZONE 'UTC') - (?1 * CAST('1 minutes' AS interval)) "
+ "GROUP BY p_id_auto)) AS taotr "
+ "LEFT JOIN t_unit_members AS tum ON tum.p_id = taotr.p_name_road "
+ "WHERE taotr.p_id_auto = tmi.p_id;";
List<Object[]> resultList = em.createNativeQuery(sql)
.setParameter(1, Integer.parseInt(minutes))
.getResultList();
List<CalculatedCar> calculatedCars = new ArrayList<>(resultList.size());
resultList.forEach(result -> {
BigDecimal id = (BigDecimal)result[0];
Integer parkId = (Integer)result[1];
String gosNumber = (String) result[2];
String parkName = (String) result[3];
Double lon = (Double) result[4];
Double lat = (Double) result[5];
Integer vector = (Integer) result[6];
Integer speed = (Integer) result[7];
String markName = (String) result[8];
Integer markId = (Integer) result[9];
String title = (String) result[10];
BigDecimal groupTransportType = (BigDecimal) result[11];
String titleTransportType = (String) result[12];
String organization = (String) result[13];
Timestamp tmp = (Timestamp) result[14];
System.out.println("TIMESTAMP TIME = " + tmp);
Instant timeUTC = tmp.toInstant();
System.out.println("INSTANT TIME = " + timeUTC);
String kilometers = (String) result[15];
String roadName = (String) result[16];
String stationNum = (String) result[17];
BigDecimal machineType = (BigDecimal) result[18];
CalculatedCar car = CalculatedCar
.builder()
.id(id)
.parkId(parkId)
.gosnumber(gosNumber)
.parkName(parkName)
.lon(lon)
.lat(lat)
.vector(vector)
.speed(speed)
.markName(markName)
.markId(markId)
.TTTitle(title)
.groupTransportType(groupTransportType)
.titleTransportType(titleTransportType)
.organization(organization)
.timeUTC(timeUTC)
.kilometers(kilometers)
.roadName(roadName)
.stationNum(stationNum)
.machineType(machineType)
.build();
calculatedCars.add(car);
});
return calculatedCars;
}
}
转换发生在这部分代码中
Timestamp tmp = (Timestamp) result[14];
System.out.println("TIMESTAMP TIME = " + tmp);
Instant timeUTC = tmp.toInstant();
System.out.println("INSTANT TIME = " + timeUTC);
我期望 UTC 日期时间的时间没有变化 2024-05-15 15:12:44.0 因为在数据库中我已经写了一个 UTC 时间,但是在这个表中输入 DB Postgres 有一个没有时区的时间戳。
您面临的问题是由于 Java 和 PostgreSQL 处理时间戳的方式不同造成的。在Java中,Timestamp类表示带有时区偏移的时间点,而在PostgreSQL中,没有时区的TIMESTAMP数据类型存储为UTC时间。 当您从 PostgreSQL 检索 TIMESTAMP 值并将其转换为 Java 中的 java.sql.Timestamp 对象时,它假定该值位于 JVM 的默认时区中。由于 JVM 的默认时区似乎比 UTC 晚 3 小时,因此使用比实际 UTC 时间晚 3 小时的时间戳创建 Timestamp 对象。 要解决此问题,您需要使用正确的时区(在您的情况下为 UTC)创建 Timestamp 对象。您可以通过使用接受 java.time.Instant 对象和 UTC 时区 ID 的 Timestamp 构造函数来完成此操作:
javaCopy codeTimestamp tmp = (Timestamp) result[14];
System.out.println("TIMESTAMP TIME = " + tmp);
Instant instantUTC = tmp.toInstant();
System.out.println("INSTANT TIME = " + instantUTC);
Timestamp timestampUTC = Timestamp.from(instantUTC.atZone(ZoneId.of("UTC")).toInstant());
System.out.println("TIMESTAMP UTC = " + timestampUTC);
在此代码中:
tmp 是从数据库检索的时间戳对象。 instantUTC 是时间戳的即时表示,采用 UTC 格式。 timestampUTC 是一个新的 Timestamp 对象,它是从带有 UTC 时区的 Instant 创建的。
现在的输出应该是:
Copy codeTIMESTAMP TIME = 2024-05-15 15:12:44.0
INSTANT TIME = 2024-05-15T15:12:44Z
TIMESTAMP UTC = 2024-05-15 15:12:44.0
通过使用具有 UTC 时区的 Instant 创建 Timestamp 对象,可以确保时间戳值正确表示为 UTC 时间。 或者,您可以考虑使用 TIMESTAMP WITH TIME ZONE 数据类型将 TIMESTAMP 值与时区一起存储在 PostgreSQL 中。这样,时间戳值将使用正确的时区信息进行存储和检索,从而无需在 Java 代码中进行时区转换。