Dar*_*noj 5 java datetime date datetime-format java-8
编辑 :
我打开了一个错误,并且已被 Oracle 确认。您可以在此处遵循解决方案:https://bugs.java.com/bugdatabase/view_bug.do ?bug_id=JDK-8216414
我正在与一个 LDAP 存储库交互,该存储库存储一个人的出生日期以及时间和时区,如下所示:
我找不到使用相同模式解析和格式化生日的方法。
以下代码适用于格式化,但不适用于解析:
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);
Run Code Online (Sandbox Code Playgroud)
以下代码适用于解析,但不适用于格式化
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);
Run Code Online (Sandbox Code Playgroud)
哪种模式可以同时满足解析和格式化?
我是否被迫使用两种不同的模式?
我这么问是因为该模式是在属性文件中配置的。我只想在此属性文件中配置 1 个模式。我想外部化该模式,因为 LDAP 不是我项目的一部分,它是共享资源,并且我不能保证格式不会更改。
我建议:
\n\n LocalDate date = LocalDate.of(2018, Month.DECEMBER, 27);\n String pattern = "yyyyMMddHHmmssxx";\n DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);\n\n // Outputs 20181227000000+0000\n String formatted = date.atStartOfDay(ZoneOffset.UTC).format(birthdateFormat);\n System.out.println(formatted);\n\n // Parses to 2018-12-27T00:00Z\n OffsetDateTime odt = OffsetDateTime.parse("20181227000000+0000", birthdateFormat);\n System.out.println(odt);\n // Validate\n if (! odt.toLocalTime().equals(LocalTime.MIN)) {\n System.out.println("Unexpected time of day: " + odt);\n }\n if (! odt.getOffset().equals(ZoneOffset.UTC)) {\n System.out.println("Unexpected time zone offset: " + odt);\n }\n // Converts to 2018-12-27\n date = odt.toLocalDate();\n System.out.println(date);\nRun Code Online (Sandbox Code Playgroud)\n\nLDAP 字符串表示日期、时间和 UTC 偏移量。好的解决方案是尊重这一点,并在格式化时生成所有这些(将一天中的时间设置为 00:00 并将偏移量设置为 0)并解析所有这些(最多也验证它们以捕获是否出现任何意外)。如果您知道如何进行LocalDate和之间的转换,则非常简单。OffsetDateTime
编辑 3:允许配置模式
\n\n\n\n\n\xe2\x80\xa6 模式在属性文件中配置\xe2\x80\xa6 我只想在此属性文件中配置 1\n 模式。
\n\n\xe2\x80\xa6 我不保证格式不能改变。
\n
考虑到该模式可能有一天不包含一天中的时间和/或没有 UTC 偏移量,请在上面的代码中使用此格式化程序:
\n\n DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()\n .appendPattern(pattern)\n .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)\n .toFormatter()\n .withZone(ZoneOffset.UTC);\nRun Code Online (Sandbox Code Playgroud)\n\n这定义了一天中的默认时间(午夜)和默认偏移量 (0)。只要在 LDAP 的字符串中定义了时间和偏移量,就不会使用默认值。
\n\n如果您认为它变得太复杂,那么使用两种配置的格式,一种用于格式化,一种用于解析,可能是您最好的解决方案(最不烦人的解决方案)。
\n\n编辑:避免类型转换
\n\n我认为上面的解决方案很好。LocalDate但是,如果您坚持避免从ZonedDateTimeusingatStartOfDay到OffsetDateTimeusing 的转换toLocalDate,可以通过以下技巧实现:
DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()\n .appendValue(ChronoField.YEAR, 4, 4, SignStyle.NEVER)\n .appendValue(ChronoField.MONTH_OF_YEAR, 2, 2, SignStyle.NEVER)\n .appendValue(ChronoField.DAY_OF_MONTH, 2, 2, SignStyle.NEVER)\n .appendLiteral("000000+0000")\n .toFormatter();\n\n // Outputs 20181227000000+0000\n String formatted = date.format(birthdateFormat);\n System.out.println(formatted);\n\n // Parses into 2018-12-27\n date = LocalDate.parse("20181227000000+0000", birthdateFormat);\n System.out.println(date);\nRun Code Online (Sandbox Code Playgroud)\n\n我指定每个字段的确切宽度,以便格式化程序可以知道在解析时在字符串中的何处分隔它们。
\n\n编辑2:这是解析中的错误吗?
\n\n我立即期望yyyyMMdd\'000000+0000\'能够同时进行格式化和解析。您可以尝试向 Oracle 提交错误并查看他们的说法,但我不会\xe2\x80\x99 太乐观。