我在字符串中有一个时间戳,我正在使用DateTimeFormatter来解析字符串,如下所示并将其分配给时间戳类型变量
import java.sql.Timestamp
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAccessor
import java.time.Instant
String myTime = "2020-08-03T20:15:49"
String myTimeFormat = "yyyy-MM-dd'T'HH:mm:ss"
DateTimeFormatter timestampFormatter = DateTimeFormatter.ofPattern(myTimeFormat);
TemporalAccessor ta = timestampFormatter.parse(tempValue);
// getting error that Cannot create Instant from java.time.format.Parsed
Timestamp finalTime = Timestamp.from(Instant.from(ta));
如何将其转换为java.sql.Timestamp?
上下文:我正在尝试将 Spark 数据帧中的字符串列(使用时间戳格式)转换为时间戳列,并且我在我的 udf 中使用上述逻辑(使用 udf,因为我除了强制转换之外还需要执行其他检查),从而尝试转换为时间戳以应用具有此列作为时间戳的 Spark 架构
参考: https://spark.apache.org/docs/latest/sql-ref-datatypes.html
你不需要DateTimeFormatter
现代日期-时间 API 基于 ISO 8601,只要日期-时间字符串符合 ISO 8601 标准,就不需要显式使用DateTimeFormatter
对象。
一旦解析为LocalDateTime
,就可以使用Timestamp#valueOf
获取java.sql.Timestamp
。
演示:
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class Main {
public static void main(String[] args) {
String myTime = "2020-08-03T20:15:49";
LocalDateTime ldt = LocalDateTime.parse(myTime);
Timestamp finalTime = Timestamp.valueOf(ldt);
System.out.println(finalTime);
}
}
输出:
2020-08-03 20:15:49.0
在线演示
注意:java.util
日期-时间 API 及其格式 APISimpleDateFormat
已过时且容易出错。由于java.sql.Timestamp
扩展了java.util.Date
,它继承了同样的缺点。建议完全停止使用它们,并切换到现代日期-时间 API*。查看此答案和此答案以了解如何将java.time
API 与 JDBC 一起使用。
要了解有关现代日期-时间 API 的更多信息,请参阅跟踪:日期时间。
* 出于任何原因,如果你必须坚持使用 Java 6 或 Java 7,你可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请查看通过脱糖提供的 Java 8+ API 和如何在 Android Project 中使用 ThreeTenABP。
你的问题不是你不能创建一个Timestamp
:而是你不能创建一个Instant
。
Instant
标识时间轴上的单个点,通过与 Unix 纪元 (1970-1-1 00:00:00 UTC) 的偏移量标识。
输入的问题在于它没有标识时区。因此,它不能唯一标识单个时间点,因为 2020-08-03T20:15:49 与伦敦 vs 纽约 vs 上海 vs 德里(例如)的时刻不同。
因此:将字符串解析为LocalDateTime
;然后指定时区;然后转换为即时;然后转换为时间戳:
LocalDateTime ldt = LocalDateTime.parse(myTime, timestampFormatter);
// Or whichever time zone.
Instant instant = ldt.atZone(ZoneId.of("UTC")).toInstant();
Timestamp finalTime = Timestamp.from(instant);
什么是时间戳?
维基百科将时间戳定义为
字符序列或编码信息,标识何时 发生了某些事件...
因此,您的字符串不是时间戳,或者至少只有在我们知道它包含的日期和时间假定哪个时区(或 UTC 偏移量)时才可以被视为时间戳。如今,大多数 IT 系统并不局限于一个时区,因此通常建议在时间戳中包含 UTC 偏移量信息和/或将其保留为 UTC。我假设您要求使用一种用于SQL数据库的老式java.sql.Timestamp
。根据您对建议的遵守情况,您将在SQL和Java中需要不同的类型。
- 建议:使用显式偏移量,最好是 UTC。对于大多数数据库引擎,这意味着使用其
timestamp with time zone
或timestamptz
数据类型。从 4.2 开始的 JDBC 标准说你应该在 Java 中使用OffsetDateTime
。许多驱动程序也处理Instant
,我们通常更喜欢Java中明确时间戳的类。您尝试创建Instant
可能会暗示这与您的意图一致。 - 不建议:使用隐式偏移量,最好是 UTC。许多旧应用程序将使用自己的时区。在任何情况下,在SQL中使用
timestamp
(没有时区),在Java中使用LocalDateTime
。字符串中缺少偏移量可能暗示这是您的方法。
你提到的java.sql.Timestamp
类设计得很差,实际上是在已经设计不佳的java.util.Date
类之上的真正黑客。因此,Timestamp
不在我建议将 tiemstamp 值发送到数据库的类之列,无论是用于存储还是用于查询。
将时间戳保存到 SQL
下面是使用OffsetDateTime
和自定义假定时区的代码示例。
String myTime = "2020-08-03T20:15:49";
OffsetDateTime odt = LocalDateTime.parse(myTime)
.atZone(ZoneId.of("Asia/Colombo"))
.toOffsetDateTime();
PreparedStatement ps = yourDatabaseConnection
.prepareStatement("insert into your_table(your_timestamptz_column) values (?);");
ps.setObject(1, odt);
ps.executeUpdate();
从 JDBC 4.2 开始,setObject
方法接受包括OffsetDateTime
的 java.time 类型。
如果您的时间字符串是 UTC,则转换为OffsetDateTime
会更简单一些:
OffsetDateTime odt = LocalDateTime.parse(myTime).atOffset(ZoneOffset.UTC);
使用Instant
:您可以简单地转换之前的OffsetDateTime
:
Instant inst = odt.toInstant();
现在,您可以按照我们之前传递odt
相同的方式将inst
传递给setObject()
。
如果你在SQL中使用没有时区timestamp
,在Java中使用LocalDateTime
,Arvind Kumar Avinash的答案已经显示了解析字符串的简单方法。也可以按照与上述相同的方式将LocalDateTime
传递给setObject()
。
顺便说一句,我们通常既不需要也不想使用TemporalAccessor
界面。其文档说:
此接口是框架级接口,不应 广泛用于应用程序代码。。