3

所以我一直在寻找如何正确解析传入的日期时间,问题是这个字符串也包含显然由于某种原因无法解析的区域。举一个传入日期时间字符串的例子: 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 替换 Z,但这不起作用我认为它不起作用,因为加号或减号不存在。仅供参考,由于 Microsoft Graph API 在检索日历事件时,我收到了这种格式的日期。

关于如何正确格式化此日期的任何想法?

编辑:这来自 Microsoft Graph。基本上他们给出了一个日期作为对象:

"start": {
    "dateTime": "2021-10-05T10:00:00.0000000",
    "timeZone": "UTC"
}

这是解释此日期对象的文档页面: dateTimeTimeZone 资源类型

更新:

我终于能够解决这个日期问题,我所做的如下:

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()

这样,日期将正确转换为正确的时区和正确的日期/时间。

4

4 回答 4

3

正如我从您提供的文档中看到的那样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)
于 2021-10-05T11:04:45.703 回答
2

对于示例中的最后 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

请注意,解析Windows 当前支持的时区并不容易(除了 from UTC),但日历 API 支持的时区(大部分)足以创建java.time.ZoneId.

于 2021-10-05T11:12:33.150 回答
2

您的日期时间字符串没有时区信息

您的日期时间字符串2021-10-05T10:00:00.0000000没有时区信息。.0000000代表一秒的分数,到目前为止,它java.time能够处理高达 9 位的精度(即纳秒精度)。

由于它没有时区信息,因此它表示本地日期时间,因此应解析为LocalDateTime.

DateTimeFormatter您的日期时间字符串不需要

现代日期时间 API 基于ISO 8601DateTimeFormatter ,只要日期时间字符串符合 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

ONLINE DEMO

如何ZonedDateTime退出LocalDateTime实例?

您可以使用LocalDateTime#atZone将附加 a 转换ZoneIdLocalDateTime结果为 a ZonedDateTime

ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));

注意:如果你需要一个Instant,你可以从这个瞬间得到它, ZonedDateTime例如

Instant instant = zdt.toInstant();

AnInstant表示时间线上的一个瞬时点,通常以UTC时间表示。Z输出中的 是零时区偏移的时区指示符。它代表 Zulu 并指定Etc/UTC时区(时区偏移量为+00:00小时)。

Trail: Date Time了解有关现代日期时间 API *的更多信息。


* 如果您正在为一个 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请通过 desugaring 检查可用的 Java 8+ API。请注意,Android 8.0 Oreo 已经提供java.time.

于 2021-10-09T09:48:34.933 回答
1

作为补充:您的文档中提到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. 我的 parse 方法首先尝试这个格式化程序。它失败了UTCPacific/Honolulu。当DateTimeParseException被捕获时,该方法接下来会尝试ZoneId.of其他答案中也使用的方法。它处理文档中提到的UTC所有时区 ID区域/城市格式。

ZoneId将从我的方法中获得的与解析的结合起来,LocalDateTime以获得ZonedDateTimedeHaar 已经在他们的答案中显示的方式。

于 2021-10-09T13:23:27.960 回答