将字符串转换为即时
Posted
技术标签:
【中文标题】将字符串转换为即时【英文标题】:Converting string to Instant 【发布时间】:2018-10-22 07:16:07 【问题描述】:我正在尝试使用 java 8 或 utils 包将字符串中的日期时间转换为即时。
例如。
String requestTime = "04:30 PM, Sat 5/12/2018";
到
Instant reqInstant should result in 2018-05-12T20:30:00.000Z
reqString 位于美国/多伦多时区。
这是我尝试过的
String strReqDelTime = "04:30 PM, Sat 5/12/2018";
Date date = new SimpleDateFormat("hh:mm a, EEE MM/dd/yyyy").parse(requestTime);
Instant reqInstant = date.toInstant();
以上代码结果为"2018-05-12T23:30:00Z"
。
感谢任何帮助。
【问题讨论】:
你可以尝试调用 sdf.setTimeZone("your TZ") @DanilaZharenkov 我试过了,但它给出了“2018-05-12T16:30:00Z”Instant
不是String
也没有format
,你能准确描述一下你想要什么吗?
抱歉,我编辑了我的问题。我预计 Instant 将导致 2018-05-12T20:30:00.000Z 出现在美国/多伦多时区的“04:30 PM,Sat 5/12/2018”
无需将现代类 (Instant
) 与有问题的遗留类 (Date
& SimpleDateFormat
) 混为一谈。仅使用 java.time 类;它们完全取代了旧的。
【参考方案1】:
Instant.parse(String) 格式正确
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:您可以在此处阅读说明 [https://www.baeldung.com/java-string-to-date]
String requestTime = "04:30 PM, Sat 5/12/2018 America/Toronto";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a, EEE M/dd/yyyy z");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(requestTime, formatter);
System.out.println(zonedDateTime.toInstant());
【讨论】:
在英语语言环境中运行时,它在我的 Java 17 上正常工作。为了让它在其他语言环境中工作,我们需要在格式化程序中指定语言环境。无论如何,它比您以前(现已删除)的答案要好得多。【参考方案3】:tl;博士
修复未填充月份和日期的格式模式。 仅使用 java.time 类,切勿使用旧类。人为的例子:
LocalDateTime.parse( // Parse as an indeterminate `LocalDate`, devoid of time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline.
"04:30 PM, Sat 5/12/2018" , // This input uses a poor choice of format. Whenever possible, use standard ISO 8601 formats when exchanging date-time values as text. Conveniently, the java.time classes use the standard formats by default when parsing/generating strings.
DateTimeFormatter.ofPattern( "hh:mm a, EEE M/d/uuuu" , Locale.US ) // Use single-character `M` & `d` when the number lacks a leading padded zero for single-digit values.
) // Returns a `LocalDateTime` object.
.atZone( // Apply a zone to that unzoned `LocalDateTime`, giving it meaning, determining a point on the timeline.
ZoneId.of( "America/Toronto" ) // Always specify a proper time zone with `Contintent/Region` format, never a 3-4 letter pseudo-zone such as `PST`, `CST`, or `IST`.
) // Returns a `ZonedDateTime`. `toString` → 2018-05-12T16:30-04:00[America/Toronto].
.toInstant() // Extract a `Instant` object, always in UTC by definition.
.toString() // Generate a String in standard ISO 8601 format representing the value within this `Instant` object. Note that this string is *generated*, not *contained*.
2018-05-12T20:30:00Z
使用一位数的格式化模式
您在格式化模式中使用了MM
,这意味着任何一位数的值(1 月至 9 月)都将显示带有填充的前导零。
但是您的输入缺少填充的前导零。所以使用单个M
。
我期望的每月日期同上:d
而不是 dd
。
仅使用 java.time
您正在使用有缺陷的旧日期时间类(Date
和SimpleDateFormat
),这些类在多年前已被 java.time 类取代。新的阶级完全取代了旧的阶级。无需将传统与现代混为一谈。
LocalDateTime
解析为LocalDateTime
,因为您的输入字符串缺少time zone 或offset-from-UTC 的任何指示符。这样的值是不是一个时刻,是不是时间轴上的一个点。这只是大约 26-27 小时范围内的一组潜在时刻。
String input = "04:30 PM, Sat 5/12/2018";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm a, EEE M/d/uuuu" , Locale.US ); // Specify locale to determine human language and cultural norms used in translating that input string.
LocalDateTime ldt = LocalDateTime.parse( input , f );
ldt.toString(): 2018-05-12T16:30
ZonedDateTime
如果您确定输入旨在使用加拿大多伦多地区人们使用的挂钟时间来表示某个时刻,请应用ZoneId
来获取ZonedDateTime
对象。
分配时区为您未分区的LocalDateTime
赋予意义。现在我们有一个时刻,时间轴上的一个点。
ZoneId z = ZoneId.of( "America/Toronto" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Give meaning to that `LocalDateTime` by assigning the context of a particular time zone. Now we have a moment, a point on the timeline.
zdt.toString(): 2018-05-12T16:30-04:00[美国/多伦多]
Instant
要查看与UTC 相同的时刻,请提取Instant
。同一时刻,不同的挂钟时间。
Instant instant = zdt.toInstant() ;
instant.toString(): 2018-05-12T20:30:00Z
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date
、Calendar
和 SimpleDateFormat
。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.*
类。
从哪里获得 java.time 类?
Java SE 8、Java SE 9、Java SE 10 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6 和 Java SE 7 ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…。ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval
、YearWeek
、YearQuarter
和more。
【讨论】:
感谢您的中肯解释!!这解决了我的问题。 非常广泛和好的答案,非常感谢!请您评论一下DateTimeFormatter.ofPattern( "hh:mm a, EEE M/d/uuuu" , Locale.US )
中区域设置的使用情况吗?该文档说“区域设置会影响格式化和解析的某些方面。例如,ofLocalizedDate
提供了一个使用区域设置特定日期格式的格式化程序。”我真的不明白它如何影响解析,因为解析是由提供的模式决定的......?对语言环境的更改(隐式)如何影响规定的解析模式?
@JanusVarmarken Locale
确定用于本地化的人类语言和文化规范,例如用于翻译星期几的名称,以及决定逗号与句点、大写等问题、缩写、元素顺序等。
LocalDateTime.parse() 存在问题 - 如果您的模式不包含时间,则 parse() 将抛出异常,因此您必须添加两个 try 块,例如(伪代码):fun解析():即时? = 尝试 LocalDateTime.parse() 捕捉 尝试 LocalDate.parse() 捕捉 null 【参考方案4】:
您的计算机(服务器)中的时区似乎是美国太平洋夏令时 (GMT-7),但您希望得到美国东部夏令时 (GMT-4) 的结果。
Instant.toString() 以 ISO-8601 格式返回 UTC (GMT+0) DateTime。 (末尾的“Z”表示 UTC)。
SimpleDateFormat 威胁计算机默认时区中的 DateTime 字符串,如果未指定。而且您的输入没有指定时区。
因此,您需要对输入的时区进行处理。
PS。在东部夏令时的我的机器上,你的代码给我的结果完全符合你的预期。
【讨论】:
正确答案。以上是关于将字符串转换为即时的主要内容,如果未能解决你的问题,请参考以下文章
将字符串时间戳解析为即时抛出不受支持的字段:InstantSeconds
我将使用啥代码将类似 SQL 的表达式即时转换为正则表达式?