java系统时间转Timestamp类型

本文介绍了一种从前端接收到字符串格式的时间,并将其转换为Java中Timestamp类型的方法。具体步骤包括:将字符串转换为Long类型并乘以1000以调整时间单位,最后创建Timestamp对象。

从前端获取到了一个String类型的时间,因为前端传过来的和java的单位不一样,所以乘以1000,然后转换。

String time = jo.getString("time");
Long timeLong = (Long.valueOf(time)*1000);
Timestamp d = new Timestamp(timeLong); 

 

<think> 我们正在讨论如何在Java中更改`java.sql.Timestamp`对象的时间类型(特别是时区换)。 根据引用[1],用户的问题是如何将一个原本时区为CST的`java.sql.Timestamp`对象换为GMT时区。 注意:`java.sql.Timestamp`对象本身并不存储时区信息,它实际上是从1970-01-01 00:00:00 GMT以来的毫秒数(加上纳秒调整)表示的绝对时间点。 因此,更改时区实际上意味着:将这个绝对时间点用另一个时区来表示,即重新格式化为目标时区的日期时间字符串,或者换为另一个表示带时区的对象(如`ZonedDateTime`)。 然而,引用[3]指出,`java.sql.Timestamp`继承自`java.util.Date`,它表示的是UTC时间(即从1970-01-01 00:00:00 UTC开始的毫秒数),所以它本身没有时区概念。 我们通常说的时区问题,是在将这个时间戳换为字符串(或从字符串解析)时,使用了特定的时区。 因此,更改`java.sql.Timestamp`的时区,实际上有两种理解: 1. 将这个时间戳对象所代表的时间点,按照另一个时区来显示(即格式化为字符串时使用目标时区)。 2. 将一个原本被解释为某个时区的时间字符串,换为另一个时区对应的时间点(即重新解析)。 根据引用[2],我们知道Java 8引入了新的日期时间API(`java.time`包),其中`ZonedDateTime`可以明确地处理时区。 所以,解决方案如下: 方案一:使用`java.time` API进行换(推荐) 步骤: 1. 将`java.sql.Timestamp`换为`Instant`(因为`Timestamp`可以换为`Instant`)。 2. 将`Instant`与原始时区(CST)结合,得到`ZonedDateTime`(这样我们就知道这个时间最初是在CST时区表示的)。 3. 然后,将时区更改为目标时区(GMT),并调整时间。 4. 如果需要,可以再换回`Timestamp`(注意:换后的`Timestamp`表示的是同一时间点,只是时区表示不同)。 但是注意:`java.sql.Timestamp`存储的是UTC时间,所以如果我们有一个时间字符串是"CST时间",然后我们将其解析为`Timestamp`,那么实际上我们在解析时已经做了时区换(通常换成了UTC存储)。所以这一步需要小心。 假设我们有一个`java.sql.Timestamp`对象,它代表的时间点是从数据库中获取的(数据库通常存储UTC时间)。但是,这个时间点最初是从CST时区的时间换而来的,现在我们想把它换回GMT时区的时间字符串?或者我们想调整这个时间点使得它在GMT时区显示原来的本地时间? 实际上,用户可能有两种需求: 需求A:将时间点用GMT时区来表示(即显示为GMT时区的本地时间)。 需求B:将CST时区的本地时间换为GMT时区的本地时间(即同一本地时间在不同时区的时间点不同)。 由于问题描述不够详细,这里我们假设用户的需求是需求A:将时间戳用GMT时区来显示。 方法如下: ```java Timestamp timestamp = ...; // 从数据库获取的时间戳(存储在UTC时间) // 换为Instant(同一时刻) Instant instant = timestamp.toInstant(); // 设置为GMT时区(GMT时区的本地时间) ZonedDateTime gmtTime = instant.atZone(ZoneId.of("GMT")); // 或者使用UTC(与GMT相同) // ZonedDateTime utcTime = instant.atZone(ZoneId.of("UTC")); // 现在,我们可以格式化输出 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String formattedGMT = formatter.format(gmtTime); ``` 如果用户的需求是需求B:比如有一个时间字符串表示的是CST时区的时间,我们将其解析为时间戳(存储为UTC时间),然后我们希望得到这个时间在GMT时区的本地时间? 注意:同一个时间点在不同时区的本地时间表示是不同的。例如,CST(中央标准时间,UTC-6)时间比GMT(UTC+0)晚了6小时。所以: CST时间 2023-01-01 12:00:00 相当于 GMT时间 2023-01-01 18:00:00。 因此,如果我们有一个时间字符串表示CST时间,我们解析成时间戳(即UTC时间)后,再用GMT时区显示,就会显示为GMT的本地时间(即加上6小时)。 但是,如果用户想要的是:将CST时间字符串直接当成GMT时间来解析(即不调整时间点,只改变时区解释),那么相当于时间点变了(提前了6小时)。这实际上是改变了时间点。 所以,我们需要明确用户的需求: 情况1:已经有一个`Timestamp`对象(它代表一个绝对时间点),我们希望用GMT时区来显示它的本地时间。上面的代码即可。 情况2:我们有一个字符串,它表示的是CST时区的本地时间,我们想把它当作GMT时区的本地时间(即同一个本地时间字符串,但解释为不同时区),那么就需要重新解析,并且时间点会改变。 根据引用[1]中的问题,用户说“which was initially, instantiated to CST”,意思是最初这个Timestamp是用CST设置的。那么,可能指的是这个时间戳在创建时,是使用CST时区解析的,现在想把它当作GMT时区来用(即同一个时间点,用GMT时区显示)。 所以,我们按照情况1处理即可。 但是,如果我们创建`Timestamp`对象时,错误地使用了CST时区来解析,而实际上我们应该用GMT来解析,那么我们就需要调整这个时间点(即情况2)。这种情况,我们需要用新的时区重新解析原始字符串。 由于问题中没有给出具体的创建过程,我们分别给出两种情况的代码: 情况1:仅改变显示时区(不改变时间点) ```java // 假设我们有一个从数据库获取的Timestamp对象(代表UTC时间Timestamp timestamp = ...; // 换为GMT时区显示 Instant instant = timestamp.toInstant(); ZonedDateTime gmtZdt = instant.atZone(ZoneId.of("GMT")); // 然后使用gmtZdt进行格式化输出 ``` 情况2:重新解析(改变时间点)—— 如果我们最初有一个CST时间字符串,但我们错误地将其解析为Timestamp(使用CST时区换成了UTC时间),现在想要用GMT时区来解释这个字符串(即同一个本地时间字符串,但时区是GMT),那么我们需要重新解析字符串,并调整时间点。 例如: ```java // 原始字符串(CST时区的时间) String cstTimeStr = "2023-01-01 12:00:00"; // 错误做法:如果我们用SimpleDateFormat解析,但没有设置时区,它会使用系统默认时区 // 假设我们需要按CST时区解析,然后存储为Timestamp(UTC时间) SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("CST")); // 设置为CST时区 Date date = sdf.parse(cstTimeStr); // 解析为Date(即UTC时间Timestamp timestampCST = new Timestamp(date.getTime()); // 这个timestampCST代表的是UTC时间,但对应CST时区的时间字符串 // 现在,我们想把同样的时间字符串当作GMT时区的时间,那么我们应该用GMT时区再解析一次 sdf.setTimeZone(TimeZone.getTimeZone("GMT")); Date dateGMT = sdf.parse(cstTimeStr); Timestamp timestampGMT = new Timestamp(dateGMT.getTime()); // 这时,timestampGMT和timestampCST代表的时间点不同,相差6小时(因为CST和GMT相差6小时) ``` 但是,如果我们已经有了`timestampCST`对象(它是从CST时间字符串解析得到的),现在想得到同一个时间字符串在GMT时区所代表的时间点(即timestampGMT),我们无法直接通过`timestampCST`换得到,因为`timestampCST`已经是一个绝对的时间点(UTC时间),我们只能通过重新解析原始字符串来得到。 因此,如果用户的需求是情况2,那么我们必须回到原始字符串重新解析。 考虑到引用[1]的问题,它更可能是情况1:即已经有了一个`Timestamp`对象,想改变它的显示时区(不改变时间点)。所以,我们重点给出情况1的解决方案。 另外,Java 8的API更简洁,推荐使用。 总结:更改`java.sql.Timestamp`的时区显示,实际上是将同一个时间点用另一个时区来表示。我们可以通过换为`ZonedDateTime`来实现。 代码示例(情况1): ```java import java.sql.Timestamp; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; public class TimestampTimeZoneChange { public static void main(String[] args) { // 假设我们有一个从数据库获取的Timestamp对象(代表UTC时间Timestamp timestamp = Timestamp.valueOf("2023-01-01 12:00:00"); // 注意:Timestamp.valueOf(String)使用的字符串被解释为默认时区(JVM默认时区)的本地时间,然后换为UTC存储。 // 所以这里我们假设timestamp对象已经正确存储了时间点。 // 换为GMT时区显示 Instant instant = timestamp.toInstant(); ZonedDateTime gmtZdt = instant.atZone(ZoneId.of("GMT")); // 输出:GMT时区的日期时间 System.out.println("GMT time: " + gmtZdt); // 格式为ISO-8601 // 如果需要自定义格式 // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // String formatted = formatter.format(gmtZdt); } } ``` 注意:如果我们的时间戳字符串是用CST时区解析存储的,那么上面的代码会正确显示为GMT时间(即加上CST与GMT的时区差)。例如,如果原始字符串是CST时间中午12点,那么GMT时间就是18点(如果CST是UTC-6)。 但是,如果我们不知道原始时区,就无法正确换。因此,我们必须知道这个时间戳最初是哪个时区的本地时间。在上面的代码中,我们假设时间戳存储的是正确的UTC时间(这是数据库存储时间戳的常规做法)。 最后,如果用户需要将时间戳换为另一个时区后,再存储为`Timestamp`对象,那么注意:`Timestamp`对象总是代表UTC时间。所以,我们可以从`ZonedDateTime`换回`Timestamp`: ```java ZonedDateTime gmtZdt = ...; // 代表GMT时区的某个时间点 Instant instant = gmtZdt.toInstant(); Timestamp newTimestamp = Timestamp.from(instant); ``` 这样,`newTimestamp`存储的是这个时间点对应的UTC时间,与原始时间点相同(如果只是改变了时区显示,那么时间点不变)或者不同(如果是重新解析了字符串,则不同)。 因此,针对引用[1]的问题,我们可以这样回答: 要更改`java.sql.Timestamp`对象的时区(从CST到GMT)的显示,我们可以将其换为`ZonedDateTime`(指定为CST时区),然后换为GMT时区的`ZonedDateTime`。但是,请注意,`Timestamp`本身没有时区信息,我们只能通过以下步骤: 1. 将`Timestamp`换为`Instant`(得到绝对时间点)。 2. 用这个`Instant`和CST时区构造一个`ZonedDateTime`(这样我们就知道这个时间点最初在CST时区的表示)。 3. 然后,将这个`ZonedDateTime`换为GMT时区。 但实际上,如果我们只是想用GMT时区来显示这个时间点,那么步骤2可以省略,因为步骤1得到的`Instant`直接附加GMT时区即可。 如果用户希望将原始时间(解释为CST时区的时间换为同一个本地时间在GMT时区的时间点(即调整时间点),那么我们需要重新解析(如情况2)。 由于问题没有明确,我们给出两种可能: 可能性1(不改变时间点,只改变显示时区): 同一个时间点,在CST时区显示为2023-01-01 12:00:00,在GMT时区显示为2023-01-01 18:00:00。 可能性2(改变时间点,保持本地时间字符串不变): 同一个本地时间字符串(2023-01-01 12:00:00),在CST时区和GMT时区代表的时间点不同(相差6小时)。 根据引用[1]的问题描述,我推测是可能性1。因此,我们推荐使用`java.time`API进行换显示。 所以,我们最终回答如下: </think> ### Java中更改`java.sql.Timestamp`时区的方法 在Java中,`java.sql.Timestamp`本身不存储时区信息,它表示的是从**1970-01-01 00:00:00 UTC**开始的毫秒数(绝对时间点)。要更改其显示的时区,需要通过换操作实现。以下是两种核心方法: #### 方法1:使用`java.time` API(Java 8+ 推荐) ```java import java.sql.Timestamp; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; // 原始Timestamp(假设初始解释为CST时区) Timestamp originalTs = Timestamp.valueOf("2023-01-01 12:00:00"); // 换为目标时区(GMT) Instant instant = originalTs.toInstant(); // 获取绝对时间点 ZonedDateTime gmtTime = instant.atZone(ZoneId.of("GMT")); // 应用到GMT时区 // 结果输出(GMT时间) System.out.println("GMT时间: " + gmtTime); // 输出: 2023-01-01T18:00:00Z[GMT] ``` **原理**: 1. `toInstant()`提取UTC时间点 2. `atZone()`应用新时区规则[^2] 3. 自动处理时区偏移(如CST到GMT的+6小时) #### 方法2:使用`Calendar`(传统API) ```java import java.sql.Timestamp; import java.util.Calendar; import java.util.TimeZone; Timestamp timestamp = new Timestamp(System.currentTimeMillis()); // 创建GMT时区的Calendar Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.setTimeInMillis(timestamp.getTime()); // 获取换后的时间分量 int hour = gmtCal.get(Calendar.HOUR); // GMT小时数 int minute = gmtCal.get(Calendar.MINUTE); ``` ### 关键概念解析 1. **不可变性** `Timestamp`对象本身不可修改时区信息,所有换操作都返回新对象[^3]。 2. **时区换本质** 换公式可表示为: $$ T_{\text{new}} = T_{\text{UTC}} + \Delta_{\text{new}} $$ 其中$\Delta_{\text{new}}$是目标时区与UTC的偏移量。 3. **存储与显示分离原则** - 数据库存储:始终使用UTC时间戳 - 前端显示:按用户时区换 ```mermaid graph LR A[数据库 UTC 时间] --> B{Java应用} B --> C[用户时区换] C --> D[界面显示] ``` ### 最佳实践 1. **持久化策略** 始终以UTC时间存入数据库: ```java PreparedStatement stmt = conn.prepareStatement("INSERT INTO logs(time) VALUES (?)"); stmt.setTimestamp(1, new Timestamp(Instant.now().toEpochMilli())); // UTC存储 ``` 2. **时区换时机** - 数据库交互阶段:使用UTC时间戳 - 业务逻辑层:使用`ZonedDateTime` - 表示层:按需换为本地时间字符串 3. **全局时区配置** 在JVM启动参数中统一设置: ``` -Duser.timezone=GMT ``` > **重要提示**:避免直接修改`Timestamp`的内部值,所有时区换应通过时间点(Instant)进行[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值