我需要将具有用户指定的区域设置和时区的任何传入日期时间字符串解析为唯一的模式,以便稍后将其正确存储在数据库中:
String inputDatetime = "Mon Dec 21 21:18:37 GMT 2020";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withLocale(Locale.getDefault()).withZone(ZoneOffset.UTC);
TemporalAccessor date = fmt.parse(inputDatetime);
但我得到以下错误:
java.time.format.DateTimeParseException: Text 'Mon Dec 21 21:18:37 GMT 2020' could not be parsed at index 0
这个代码有什么问题?
2条答案
按热度按时间ndasle7k1#
假设你的数据库有
timestamp with time zone
数据类型,这是您应该用来存储字符串中的日期和时间。您的输入字符串明确地定义了一个时间点,也定义了一个时间点timestamp with time zone
.接下来,不应将日期时间存储为数据库喜欢的特定格式的字符串。存储适当的日期时间对象。由于JDBC4.2,这意味着对象的类型来自java.time,这是您已经在使用的现代java日期和时间api。那你就不需要关心格式了。一切都为你准备好了。如果数据库数据类型为
timestamp with time zone
,存储OffsetDateTime
进入那个专栏。相反,它是timestamp
没有时区或datetime
,而不是存储LocalDateTime
. jdbc驱动程序的文档应该会提供更多的细节。这个代码有什么问题?
我发现你的代码有不止一个问题。
正如您在评论中所说的,您正在尝试使用带模式的格式化程序来解析字符串
yyyy-MM-dd HH:mm:ss
,但你的线显然不在yyyy-MM-dd HH:mm:ss
格式。所以这是注定要失败的。更具体地说,格式字符串以yyyy
例如2020年。因此格式化程序希望在字符串的开头找到一个四位数的年份数字。相反,它发现Mon
并抛出异常。异常消息通知我们字符串could not be parsed at index 0
. 索引0是字符串的开头,其中Mon
是。我不确定,但似乎你一直混淆输入和输出格式。将日期时间从一种格式的字符串转换为另一种格式的字符串需要两个操作:首先,使用描述原始字符串格式的格式化程序将字符串解析为日期时间对象。
其次,使用描述结果字符串格式的格式化程序将datetime格式化为字符串。
因为原始字符串是英语的,所以在解析它时必须使用讲英语的区域设置。使用
Locale.getDefault()
会在讲英语的设备上工作,当有一天你在另一种语言设置的设备上运行它时会突然失败。所以这是个坏主意。TemporalAccessor
是一个我们很少使用的低级接口。而是将字符串解析为ZonedDateTime
因为它包含日期、时间和时区(在一个字符串中)GMT
计算为时区)。如果要将日期时间格式化为
DateTimeFormatter
-正如我所说,我不认为这是你应该想要的-以下是可行的:输出:
2020-12-21 21:18:37
cgyqldqp2#
正如您已经猜到的,错误的根本原因是日期时间字符串中的模式与您在中使用的模式不匹配
DateTimeFormatter
. 如果已经知道获取日期时间字符串的所有日期时间模式,则可以创建DateTimeFormatter
具有多个可选模式(通过将模式括在方括号中)。如果您收到一个未知模式的日期时间(即您尚未输入的模式DateTimeFormatter
),您可以根据需要抛出或处理异常。我需要将具有用户指定的区域设置和时区的任何传入日期时间字符串解析为唯一的模式,以便稍后将其正确存储在数据库中:
这个要求有两个部分:a。解析并将用户指定的区域设置和时区中的日期时间转换为等效的日期时间
UTC
(不仅是推荐的,而且是某些数据库所要求的,例如。PostgreSQL
)b。保存到数据库中。满足第一部分要求的步骤是:
由于接收到的日期时间位于用户指定的时区中,请忽略日期时间字符串中包含的时区并将其解析为
LocalDateTime
.转换
LocalDateTime
至ZonedDateTime
在用户指定的时区。转换此
ZonedDateTime
至ZonedDateTime
在utc。最后,转换
ZonedDateTime
至OffsetDateTime
.一旦你有
OffsetDateTime
,您可以将其存储到数据库中,如下所示:您可以使用以下测试线束来测试需求的第一部分:
示例运行: