当前位置: 首页 > 知识库问答 >
问题:

日期到OffsetDateTime的字符串

令狐功
2023-03-14

我正在将日期/日期时间字符串转换为OffsetDateTime,我有一种日期时间格式,它可能有以下值之一:

yyyy-MM-dd, yyyy/MM/dd

有时有时间和没有时间,我需要将其转换为OffsetDateTime

我已经尝试了下面的代码

// for format yyyy-MM-dd
DateTimeFormatter DATE_FORMAT = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd")
                        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                        .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
                        .toFormatter();

因为没有时间,我将它设置为默认值,但是当我试图解析时

OffsetDateTime.parse("2016-06-06", DATE_FORMAT)

它抛出的错误类似于

线程"main"java.time.format.DateTimeParseException中的异常:无法解析文本'2016-06-06':无法从TemporalAccess:{}获取OffsetDateTime,ISO解析为2016-06-06T00:00类型java.time.format.Parsed

有人能帮我解决这个问题吗?

共有3个答案

钱震博
2023-03-14

尝试这种方式:

if (!StringUtils.isEmpty(stringDate)){
        OffsetDateTime offsetDateTime = 
        OffsetDateTime.from(LocalDate.parse(stringDate, 
        DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy/MM/dd]")));
    }
夏昊
2023-03-14

< code>OffsetDateTime需要知道相对于UTC的时区偏移量,因此您需要为此提供一个默认值。为<代码>计时字段提供默认值。偏移量_秒:

DateTimeFormatter DATE_FORMAT = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd")
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
        .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
        .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
        .toFormatter();

或者,您拥有的格式对于< code>LocalDateTime就足够了。

董宜然
2023-03-14

要创建< code>OffsetDateTime,您需要日期(日、月和年)、时间(小时、分钟、秒和纳秒)和偏移量(与UTC的差异)。

您的输入只有日期,因此您必须构建其余的,或者为它们假设默认值。

要分析这两种格式(yyyy-MM-ddyy/MM/dd),您可以使用带有可选模式的DateTimeFormatter(由[]]分隔)并分析为本地日期(因为您只有日期字段):

// parse yyyy-MM-dd or yyyy/MM/dd
DateTimeFormatter parser = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy/MM/dd]");

// parse yyyy-MM-dd
LocalDate dt = LocalDate.parse("2016-06-06", parser);

// or parse yyyy/MM/dd
LocalDate dt = LocalDate.parse("2016/06/06", parser);

您也可以使用这个(稍微复杂一点,但工作方式相同):

// year followed by - or /, followed by month, followed by - or /, followed by day
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy[-][/]MM[-][/]dd");

然后,您可以设置构建< code>LocalDateTime的时间:

// set time to midnight
LocalDateTime ldt = dt.atStartOfDay();

// set time to 2:30 PM
LocalDateTime ldt = dt.atTime(14, 30);

或者,您也可以使用<code>解析默认值</code>,正如@greg的回答中所解释的:

// parse yyyy-MM-dd or yyyy/MM/dd
DateTimeFormatter parser = new DateTimeFormatterBuilder().appendPattern("[yyyy-MM-dd][yyyy/MM/dd]")
    // set hour to zero
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    // set minute to zero
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // create formatter
    .toFormatter();
// parse the LocalDateTime, time will be set to 00:00
LocalDateTime ldt = LocalDateTime.parse("2016-06-06", parser);

请注意,我必须将小时和分钟设置为零。您还可以将秒(ChronoField.SECOND_OF_MINUTE)和纳秒(chronof ield.NANO_OF _SECOND)设置为零,但设置小时和分钟足以将所有其他字段设置为零。

您告诉我您想使用系统的默认偏移量。这有点棘手。

“系统的默认偏移量”将取决于系统的默认时区。一个时区可以有多个偏移量,具体取决于您在时间线中的时间。

我将使用系统的默认时区(美国/圣保罗)作为示例。在下面的代码中,我使用的是ZoneId。systemDefault(),但请记住,这在每个系统/环境中都是不同的。对于下面的所有示例,请记住ZoneId。systemDefault()返回美国/圣保罗。如果要获取特定的分区,应使用ZoneId。“zone_name”)-实际上这是首选。

首先,您必须获取 LocalDateTime 在指定时区的有效偏移量列表:

// using the parser with parseDefaulting
LocalDateTime ldt = LocalDateTime.parse("2016-06-06", parser);

// get all valid offsets for the date/time, in the specified timezone
List<ZoneOffset> validOffsets = ZoneId.systemDefault().getRules().getValidOffsets(ldt);

根据javadoc,对于任何给定的本地日期时间,< code>validOffsets列表大小可以是零、一或二。

对于大多数情况,只有一个有效偏移量。在这种情况下,很难获得OffsetDateTime

// most common case: just one valid offset
OffsetDateTime odt = ldt.atOffset(validOffsets.get(0));

其他情况(零或两个有效偏移)通常是由于夏令时更改 (DST) 而发生的。

在圣保罗时区,夏令时将于2017年10月15日开始:在午夜,时钟向前移动到凌晨1点,时差从< code>-03:00变为< code>-02:00。这意味着从00:00到00:59的所有本地时间都不存在——你也可以认为时钟从23:59直接变为01:00。

因此,在圣保罗时区,该日期没有有效的偏移量:

// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime ldt = LocalDateTime.parse("2017-10-15", parser);
// system's default timezone is America/Sao_Paulo
List<ZoneOffset> validOffsets = ZoneId.systemDefault().getRules().getValidOffsets(ldt);
System.out.println(validOffsets.size()); // zero

没有有效的偏移量,所以您必须决定在这种情况下做什么(使用“默认”的偏移量?抛出异常?).< br >即使您的时区今天没有DST,它也可能在过去有(过去的日期可能是这种情况),或者在未来有(因为任何国家的DST和偏移量都是由政府和法律定义的,不能保证将来没有人会改变)。

但是,如果创建一个分区日期时间,结果将不同:

// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime ldt = LocalDateTime.parse("2017-10-15", parser);
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());

< code>zdt变量将为< code > 2017-10-15t 01:00-02:00[America/Sao _ Paulo]-时间和偏移量在< code>-02:00偏移量时自动调整为凌晨1点。

并且存在两个有效偏移量的情况。在圣保罗,DST 将于 2018 2 月 18 日结束:午夜时分,时钟将向 1 小时后移到 17日的晚上 11 点,偏移量将从 -02:00 更改为 -03:00。这意味着 23:00 到 23:59 之间的所有本地时间将同时存在两次,两种偏移量。

因为我将默认时间设置为午夜,所以只有一个有效的偏移量。但是假设我决定使用默认时间23:00:

// parse yyyy-MM-dd or yyyy/MM/dd
parser = new DateTimeFormatterBuilder().appendPattern("[yyyy-MM-dd][yyyy/MM/dd]")
    // *** set hour to 11 PM ***
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 23)
    // set minute to zero
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // create formatter
    .toFormatter();

// February 18th 2018 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 17th exist twice
LocalDateTime ldt = LocalDateTime.parse("2018-02-17", parser);
// system's default timezone is America/Sao_Paulo
List<ZoneOffset> validOffsets = ZoneId.systemDefault().getRules().getValidOffsets(ldt);
System.out.println(validOffsets.size()); // 2

LocalDateTime将有2个有效的偏移量。在这种情况下,您必须选择其中之一:

// DST offset: 2018-02-17T23:00-02:00
OffsetDateTime dst = ldt.atOffset(validOffsets.get(0));

// non-DST offset: 2018-02-17T23:00-03:00
OffsetDateTime nondst = ldt.atOffset(validOffsets.get(1));

但是,如果您创建一个 ZonedDateTime,它将使用第一个偏移量作为默认值:

// February 18th 2018 at midnight, DST ends in Sao Paulo
LocalDateTime ldt = LocalDateTime.parse("2018-02-17", parser);
// system's default timezone is America/Sao_Paulo
List<ZoneOffset> validOffsets = ZoneId.systemDefault().getRules().getValidOffsets(ldt);

// by default it uses DST offset
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());

zdt将是2018-02-17T23:00-02:00[America/Sao_Paulo]-注意它默认使用DST偏移量(-02:00)。

如果您想要DST结束后的偏移量,您可以执行以下操作:

// get offset after DST ends
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault()).withLaterOffsetAtOverlap();

zdt将是2018-02-17T23:00-03:00[America/Sao_Paulo]-它使用偏移量-03:00(DST结束后)。

只是提醒一下,系统的默认时区甚至可以在运行时更改,最好使用特定的时区名称(比如< code > zoneid . of(" America/Sao _ Paulo "))。您可以通过调用< code > zoneid . getavailablezoneids()来获取可用时区的列表(并选择最适合您系统的时区)。

 类似资料:
  • 问题内容: 如何将字符串日期格式转换为日期,我的日期字符串格式为 接下来,我没有运气尝试。 以上所有语句都给出了解析错误。 问题答案: 请阅读的文档time.Parse: 该布局通过显示参考时间(定义为 2006年1月2日星期一15:04:05-0700 如果它是值,将被解释;它用作输入格式的示例。然后将对输入字符串进行相同的解释。 所以正确的格式是

  • 问题内容: 如何在python中将字符串转换为日期对象? 该字符串是:(对应于格式:) 我不想要datetime.datetime对象,而是想要datetime.date。 问题答案: 您可以在Python包中使用:

  • 问题内容: 我已经写了这个功能: 当我通过日期以及获取输出日期作为 我要去哪里的时候?还做什么,如果我想只得到和 任何帮助表示赞赏 问题答案: 找到以下解决方案…。发布它,因为它也可以帮助其他人:) 输出: 2014-04-24T11:15:00.000 + 02:00

  • 问题内容: 我在这里有点迷路,我认为我一切都很好,但仍然无法正常工作(PaseException 帮助高度赞赏! 问题答案: 对我来说很好。 也许你可以尝试

  • 我有一个日期的字符串格式,但它来自csv文件:20200520T0200,假设它的格式为(yyyyMMdd/T/24小时格式)。 我已经设法读取了csv文件中的行,并将其分离到数组缓冲区中。 我的问题是我不能将字符串格式化成日期,因为我需要使用日期来计算一些值。因为我将使用这个格式化程序来格式化我的arraybuffer的第一个元素的所有值,这是带有字符串“20200406T0300,等等,等等”

  • 我对OffsetDateTime的用法非常陌生,我正在尝试将OffsetDateTime字符串与OffsetDateTime进行比较。以这种方式在java中使用now(), 但我正在学习java。时间总体安排所有3种情况下的DateTimeParseException。 然而,如果我将2个OffsetDateTime字符串与CompareTo方法进行比较,它的工作就很好了。 有没有人能在这方面给我