Kotlin 日期解析无法正常工作
Kotlin date parsing is not working properly
所以我一直在寻找如何正确解析传入的日期时间,问题是这个字符串也包含区域,显然由于某种原因无法解析。
举一个传入日期时间字符串的例子:
2021-10-05T10:00:00.0000000
现在我尝试了以下操作:
var dateTimeString = "2021-10-05T10:00:00.0000000"
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
var date = LocalDate.parse(dateTimeString, formatter)
我尝试用 ZZZZ 和 ZZZZ 替换 Z,但是没有用我认为它不起作用,因为加号或减号不存在。仅供参考,由于 Microsoft Graph API 在检索日历事件时,我收到了这种格式的日期。
知道应该如何正确设置此日期的格式吗?
编辑:这来自 Microsoft Graph。基本上他们给出了一个日期作为对象:
"start": {
"dateTime": "2021-10-05T10:00:00.0000000",
"timeZone": "UTC"
}
这是解释此日期对象的文档页面:dateTimeTimeZone resource type。
更新:
我终于能够解决这个日期问题,我所做的是:
var inputDateTime = "2021-10-05T10:00:00.0000000"
var inputTimeZone = "UTC"
var zonedDateTime = ZonedDateTime.parse(
inputDateTime,
DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of(inputTimeZone))
).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
这样,日期将被正确转换为正确的时区和正确的 Date/Time。
正如我从您提供的文档中看到的那样https://docs.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
dateTime String A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).
timeZone String Represents a time zone, for example, "Pacific Standard Time". See below for more possible values.
dateTime
对象没有编码区域。所有 7 个零都代表几分之一秒。在这种情况下,它是常规的 ISO_DATE_TIME
,您不需要创建自己的格式化程序。
下面的代码应该可以工作
var dateTimeString = "2021-10-05T10:00:00.0000000"
var date = LocalDate.parse(dateTimeString, DateTimeFormatter.ISO_DATE_TIME)
如果您示例中的最后 4 位数字 String
不代表时区:
在没有格式化程序的情况下解析它(不需要,因为如果最后 4 位数字只是秒的附加分数,它将是完美的 ISO 标准),而且 考虑时区 你使用 JSON:
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
fun main() {
// the time String from JSON
var dateTimeString = "2021-10-05T10:00:00.0000000"
// the zone from JSON (may not always work, but does with UTC)
var timeZone = "UTC"
// create the zone from the timezone String
var zoneId = ZoneId.of(timeZone)
// then parse the time String using plain LocalDateTime and add the zone afterwards
var zdt: ZonedDateTime = LocalDateTime.parse(dateTimeString).atZone(zoneId)
// print some results
println("Full ZonedDateTime: ${zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}")
println("(Local)Date only: ${zdt.toLocalDate()}")
}
Full ZonedDateTime: 2021-10-05T10:00:00Z[UTC]
(Local)Date only: 2021-10-05
请注意,解析 time zones currently supported by Windows won't work this easy (except from UTC
), but the time zones supported by the calendar API(大部分)足以创建 java.time.ZoneId
。
您的日期时间字符串没有时区信息
您的日期时间字符串 2021-10-05T10:00:00.0000000
没有时区信息。 .0000000
表示秒的小数部分,截至目前,java.time
能够处理多达 9 位精度(即纳秒精度)。
由于它没有时区信息,它表示本地日期时间,因此应解析为 LocalDateTime
。
您的日期时间字符串不需要 DateTimeFormatter
现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 ISO 8601 标准.您的日期时间字符串已经是 ISO 8601 格式。
演示:
import java.time.LocalDateTime;
public class Main {
public static void main(String args[]) {
var dateTimeString = "2021-10-05T10:00:00.0000000";
var ldt = LocalDateTime.parse(dateTimeString);
System.out.println(ldt);
}
}
输出:
2021-10-05T10:00
如何从 LocalDateTime
实例中获取 ZonedDateTime
?
您可以使用 LocalDateTime#atZone
将附加 ZoneId
转换为 LocalDateTime
,从而生成 ZonedDateTime
。
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));
注意:如果你需要一个Instant
,你可以从ZonedDateTime
的这一刻得到它,例如
Instant instant = zdt.toInstant();
零时区偏移的 Instant
represents an instantaneous point on the timeline, normally represented in UTC time. The Z
in the output is the timezone designator。它代表祖鲁语并指定 Etc/UTC
时区(时区偏移量为 +00:00
小时)。
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
作为补充:您的文档提到 Pacific Standard Time
作为时区字符串,可能作为 MS Graph dateTimeTimeZone 的一部分出现。我不认为其他答案可以解决这个问题,所以我想在 Java.
中展示你是如何处理它的
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzzz", Locale.ENGLISH);
static ZoneId parseZone(String timeZoneString) {
try {
return ZoneId.from(ZONE_FORMATTER.parse(timeZoneString));
} catch (DateTimeParseException dtpe) {
return ZoneId.of(timeZoneString);
}
}
我相信这可以处理文档中提到的字符串以及您问题中的 UTC
。我只演示三个不同的:
String[] msTimeZoneStrings = { "UTC", "Pacific Standard Time", "Pacific/Honolulu" };
for (String zoneString : msTimeZoneStrings) {
ZoneId zid = parseZone(zoneString);
System.out.format("%-21s parsed to %s%n", zoneString, zid);
}
输出:
UTC parsed to UTC
Pacific Standard Time parsed to America/Los_Angeles
Pacific/Honolulu parsed to Pacific/Honolulu
在我使用的格式化程序中,zzzz
用于时区名称,如 Pacific Standard Time
。我的解析方法首先尝试这个格式化程序。 UTC
和 Pacific/Honolulu
失败。当 DateTimeParseException
被捕获时,该方法接下来会尝试其他答案中也使用的 ZoneId.of
方法。它处理文档中提到的 UTC
和所有时区 ID sin region/city 格式。
将从我的方法获得的 ZoneId
与解析的 LocalDateTime
结合起来,得到 ZonedDateTime
deHaar 已经在他们的答案中显示的方式。
所以我一直在寻找如何正确解析传入的日期时间,问题是这个字符串也包含区域,显然由于某种原因无法解析。
举一个传入日期时间字符串的例子:
2021-10-05T10:00:00.0000000
现在我尝试了以下操作:
var dateTimeString = "2021-10-05T10:00:00.0000000"
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
var date = LocalDate.parse(dateTimeString, formatter)
我尝试用 ZZZZ 和 ZZZZ 替换 Z,但是没有用我认为它不起作用,因为加号或减号不存在。仅供参考,由于 Microsoft Graph API 在检索日历事件时,我收到了这种格式的日期。
知道应该如何正确设置此日期的格式吗?
编辑:这来自 Microsoft Graph。基本上他们给出了一个日期作为对象:
"start": {
"dateTime": "2021-10-05T10:00:00.0000000",
"timeZone": "UTC"
}
这是解释此日期对象的文档页面:dateTimeTimeZone resource type。
更新:
我终于能够解决这个日期问题,我所做的是:
var inputDateTime = "2021-10-05T10:00:00.0000000"
var inputTimeZone = "UTC"
var zonedDateTime = ZonedDateTime.parse(
inputDateTime,
DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of(inputTimeZone))
).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
这样,日期将被正确转换为正确的时区和正确的 Date/Time。
正如我从您提供的文档中看到的那样https://docs.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
dateTime String A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).
timeZone String Represents a time zone, for example, "Pacific Standard Time". See below for more possible values.
dateTime
对象没有编码区域。所有 7 个零都代表几分之一秒。在这种情况下,它是常规的 ISO_DATE_TIME
,您不需要创建自己的格式化程序。
下面的代码应该可以工作
var dateTimeString = "2021-10-05T10:00:00.0000000"
var date = LocalDate.parse(dateTimeString, DateTimeFormatter.ISO_DATE_TIME)
如果您示例中的最后 4 位数字 String
不代表时区:
在没有格式化程序的情况下解析它(不需要,因为如果最后 4 位数字只是秒的附加分数,它将是完美的 ISO 标准),而且 考虑时区 你使用 JSON:
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
fun main() {
// the time String from JSON
var dateTimeString = "2021-10-05T10:00:00.0000000"
// the zone from JSON (may not always work, but does with UTC)
var timeZone = "UTC"
// create the zone from the timezone String
var zoneId = ZoneId.of(timeZone)
// then parse the time String using plain LocalDateTime and add the zone afterwards
var zdt: ZonedDateTime = LocalDateTime.parse(dateTimeString).atZone(zoneId)
// print some results
println("Full ZonedDateTime: ${zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}")
println("(Local)Date only: ${zdt.toLocalDate()}")
}
Full ZonedDateTime: 2021-10-05T10:00:00Z[UTC]
(Local)Date only: 2021-10-05
请注意,解析 time zones currently supported by Windows won't work this easy (except from UTC
), but the time zones supported by the calendar API(大部分)足以创建 java.time.ZoneId
。
您的日期时间字符串没有时区信息
您的日期时间字符串 2021-10-05T10:00:00.0000000
没有时区信息。 .0000000
表示秒的小数部分,截至目前,java.time
能够处理多达 9 位精度(即纳秒精度)。
由于它没有时区信息,它表示本地日期时间,因此应解析为 LocalDateTime
。
您的日期时间字符串不需要 DateTimeFormatter
现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 ISO 8601 标准.您的日期时间字符串已经是 ISO 8601 格式。
演示:
import java.time.LocalDateTime;
public class Main {
public static void main(String args[]) {
var dateTimeString = "2021-10-05T10:00:00.0000000";
var ldt = LocalDateTime.parse(dateTimeString);
System.out.println(ldt);
}
}
输出:
2021-10-05T10:00
如何从 LocalDateTime
实例中获取 ZonedDateTime
?
您可以使用 LocalDateTime#atZone
将附加 ZoneId
转换为 LocalDateTime
,从而生成 ZonedDateTime
。
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));
注意:如果你需要一个Instant
,你可以从ZonedDateTime
的这一刻得到它,例如
Instant instant = zdt.toInstant();
零时区偏移的 Instant
represents an instantaneous point on the timeline, normally represented in UTC time. The Z
in the output is the timezone designator。它代表祖鲁语并指定 Etc/UTC
时区(时区偏移量为 +00:00
小时)。
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
作为补充:您的文档提到 Pacific Standard Time
作为时区字符串,可能作为 MS Graph dateTimeTimeZone 的一部分出现。我不认为其他答案可以解决这个问题,所以我想在 Java.
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzzz", Locale.ENGLISH);
static ZoneId parseZone(String timeZoneString) {
try {
return ZoneId.from(ZONE_FORMATTER.parse(timeZoneString));
} catch (DateTimeParseException dtpe) {
return ZoneId.of(timeZoneString);
}
}
我相信这可以处理文档中提到的字符串以及您问题中的 UTC
。我只演示三个不同的:
String[] msTimeZoneStrings = { "UTC", "Pacific Standard Time", "Pacific/Honolulu" };
for (String zoneString : msTimeZoneStrings) {
ZoneId zid = parseZone(zoneString);
System.out.format("%-21s parsed to %s%n", zoneString, zid);
}
输出:
UTC parsed to UTC Pacific Standard Time parsed to America/Los_Angeles Pacific/Honolulu parsed to Pacific/Honolulu
在我使用的格式化程序中,zzzz
用于时区名称,如 Pacific Standard Time
。我的解析方法首先尝试这个格式化程序。 UTC
和 Pacific/Honolulu
失败。当 DateTimeParseException
被捕获时,该方法接下来会尝试其他答案中也使用的 ZoneId.of
方法。它处理文档中提到的 UTC
和所有时区 ID sin region/city 格式。
将从我的方法获得的 ZoneId
与解析的 LocalDateTime
结合起来,得到 ZonedDateTime
deHaar 已经在他们的答案中显示的方式。