如何正确将时间戳转换为带有 UTC 时区的即时?

问题描述 投票:0回答:1

当我从数据库获取数据时遇到问题 我得到这样的数据 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 time
1个回答
0
投票

您面临的问题是由于 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 代码中进行时区转换。

© www.soinside.com 2019 - 2024. All rights reserved.