ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java-使用不必要的时间和时区解析和格式化LocalDate

2019-10-24 21:59:49  阅读:207  来源: 互联网

标签:java-8 datetime-format datetime java date


编辑:

我打开了一个错误,并已被Oracle确认.您可以在此处遵循分辨率:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8216414

我正在与一个LDAP存储库交互,该存储库以如下所示的时间和时区存储一个人的生日:

>如果生日是“ 27-12-2018”,则LDAP字符串是“ 20181227000000 0000”.

我找不到使用相同模式解析和格式化生日的方法.

以下代码适用于格式化,但不适用于解析:

LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMdd'000000+0000'";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

// Outputs correctly 20181227000000+0000
date.format(birthdateFormat);

// Throw a DatetimeParseException at index 0
date = LocalDate.parse("20181227000000+0000", birthdateFormat);

以下代码可很好地用于解析,但不适用于格式化

LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMddkkmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

// Throws a UnsupportedTemporalTypeException for ClockHourOfDay not supported
// Anyway I would have an unwanted string with non zero hour, minute, second, timezone
date.format(birthdateFormat);

// Parse correctly the date to 27-12-2018
date = LocalDate.parse("20181227000000+0000", birthdateFormat);

哪种模式可以同时满足解析和格式化要求?

我是否被迫使用2种不同的模式?

我问是因为模式是在属性文件中配置的.我只想在此属性文件中配置1个模式.我想外部化该模式,因为LDAP不是我的项目的一部分,它是共享资源,并且我不能保证格式不能更改.

解决方法:

我建议:

    LocalDate date = LocalDate.of(2018, Month.DECEMBER, 27);
    String pattern = "yyyyMMddHHmmssxx";
    DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

    // Outputs 20181227000000+0000
    String formatted = date.atStartOfDay(ZoneOffset.UTC).format(birthdateFormat);
    System.out.println(formatted);

    // Parses to 2018-12-27T00:00Z
    OffsetDateTime odt = OffsetDateTime.parse("20181227000000+0000", birthdateFormat);
    System.out.println(odt);
    // Validate
    if (! odt.toLocalTime().equals(LocalTime.MIN)) {
        System.out.println("Unexpected time of day: " + odt);
    }
    if (! odt.getOffset().equals(ZoneOffset.UTC)) {
        System.out.println("Unexpected time zone offset: " + odt);
    }
    // Converts to 2018-12-27
    date = odt.toLocalDate();
    System.out.println(date);

LDAP字符串代表日期,时间和UTC偏移量.好的解决方案是尊重这一点,并在格式化(将一天中的时间设置为00:00并将偏移量设置为0)并解析回所有内容时生成所有这些内容(最多也可以验证它们,以防出现任何意外).当您知道如何时,LocalDate和OffsetDateTime之间的转换非常简单.

编辑3:允许配置模式

… the pattern is configured in a property file… I want to configure 1
pattern only in this property file.

… I have no guarantee that the format cannot change.

要考虑到模式有一天可能不包含一天中的时间和/或没有UTC偏移的可能性,请在上面的代码中使用以下格式化程序:

    DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
            .appendPattern(pattern)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter()
            .withZone(ZoneOffset.UTC);

这定义了默认时间(午夜)和默认偏移量(0).只要在LDAP的字符串中定义了时间和偏移量,就不会使用默认值.

如果您觉得它太复杂了,那么使用两种配置的格式(一种用于格式化,另一种用于解析)可能是最适合您的解决方案(最讨厌的解决方案).

编辑:避免类型转换

我认为以上是不错的解决方案.但是,如果您坚持要避免使用atStartOfDay从LocalDate到ZonedDateTime的转换,以及使用toLocalDate从OffsetDateTime的转换,则可以通过以下技巧实现:

    DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4, 4, SignStyle.NEVER)
            .appendValue(ChronoField.MONTH_OF_YEAR, 2, 2, SignStyle.NEVER)
            .appendValue(ChronoField.DAY_OF_MONTH, 2, 2, SignStyle.NEVER)
            .appendLiteral("000000+0000")
            .toFormatter();

    // Outputs 20181227000000+0000
    String formatted = date.format(birthdateFormat);
    System.out.println(formatted);

    // Parses into 2018-12-27
    date = LocalDate.parse("20181227000000+0000", birthdateFormat);
    System.out.println(date);

我正在指定每个字段的确切宽度,以便格式化程序可以在解析时知道在字符串中将其分隔的位置.

编辑2:这是解析错误吗?

我会立即期望yyyyMMdd’000000 0000’同时用于格式化和解析.您可以尝试向Oracle提交错误,然后看看他们怎么说,尽管我不会太乐观.

标签:java-8,datetime-format,datetime,java,date
来源: https://codeday.me/bug/20191024/1923756.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有