Skip to content

Commit 600a1d5

Browse files
authored
Merge pull request #14760 from apache/java-20-date-time-formatting
Java 20 date time formatting
2 parents 707ee8b + 4c56864 commit 600a1d5

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

grails-doc/src/en/guide/upgrading/upgrading60x.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,8 @@ These are now removed in Grails 7. If you still need them, you can add them to y
260260
===== 12.7 Jar Artifact name changes
261261

262262
Jar artifacts produced by Grails Plugins will no longer have the suffix `-plain`.
263-
Please see ticket https://github.com/apache/grails-gradle-plugin/pull/347[#347] for details.
263+
Please see ticket https://github.com/apache/grails-gradle-plugin/pull/347[#347] for details.
264+
265+
===== 12.8 Java 20+ Date Formatting Changes
266+
267+
In Java 20+, https://cldr.unicode.org/downloads/cldr-42[Unicode CLDR42] was implemented which changed the space character preceding the period (AM or PM) in formatted date/time text from a standard space (" ") to a narrow non-breaking space (NNBSP: "\u202F"). Additionally, when using the LONG or FULL timeStyle with dateStyle, the date and time separator has changed from ' at ' to ', '. IE. January 5, 1941, 8:00:00 AM UTC vs. January 5, 1941 at 8:00:00 AM UTC

grails-doc/src/en/ref/Tags - GSP/formatDate.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ Formats `java.util.Date`, `java.time.LocalDate`, and `java.time.LocalDateTime` i
5757

5858
Attributes
5959

60+
WARNING: In Java 20+, https://cldr.unicode.org/downloads/cldr-42[Unicode CLDR42] was implemented which changed the space character preceding the period (AM or PM) in formatted date/time text from a standard space (" ") to a narrow non-breaking space (NNBSP: "\u202F"). Additionally, when using the LONG or FULL timeStyle with dateStyle, the date and time separator has changed from ' at ' to ', '. IE. January 5, 1941, 8:00:00 AM UTC vs. January 5, 1941 at 8:00:00 AM UTC
61+
6062
* `date` (required) - The date object to format. It could be the instance of `java.util.Date`, `java.time.LocalDate`, `java.time.LocalDateTime`.
6163
* `format` (optional) - The formatting pattern to use for the date, see {javase}java.base/java/text/SimpleDateFormat.html[SimpleDateFormat]
6264
* `formatName` (optional) - Look up `format` from the default MessageSource / ResourceBundle (i18n/*.properties file) with this key. If `format` and `formatName` are empty, `format` is looked up with '`default.date.format`' key. Defaults to 'yyyy-MM-dd HH:mm:ss z' if the key not specified

grails-gsp/plugin/src/test/groovy/org/grails/plugins/web/DefaultDateHelperSpec.groovy

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ class DefaultDateHelperSpec extends Specification {
9696
null | '8:00 AM'
9797
}
9898

99-
@PendingFeature
100-
@Requires({ !Jvm.current.isJava17() })
99+
@Requires({ Jvm.current.isJava20Compatible() })
101100
@Unroll
102-
void "Java 21+ - Full getTimeFormat for style #style returns #expected"(String style, String expected) {
101+
void "Java 20+ - getTimeFormat for style #style returns #expected"(String style, String expected) {
103102
given:
104103
DateTimeFormatter format
105104

@@ -111,8 +110,10 @@ class DefaultDateHelperSpec extends Specification {
111110
format.format(localTime) == expected
112111

113112
where:
114-
style | expected
115-
'FULL' | '8:00:00 AM UTC'
113+
style | expected
114+
'LONG' | '8:00:00\u202FAM UTC'
115+
'MEDIUM' | '8:00:00\u202FAM'
116+
null | '8:00\u202FAM'
116117
}
117118

118119
@Requires({ Jvm.current.isJava17() })
@@ -133,6 +134,24 @@ class DefaultDateHelperSpec extends Specification {
133134
'FULL' | '8:00:00 AM Coordinated Universal Time'
134135
}
135136

137+
@Requires({ Jvm.current.isJava20Compatible() })
138+
@Unroll
139+
void "Java 20+ - Full getTimeFormat for style #style returns #expected"(String style, String expected) {
140+
given:
141+
DateTimeFormatter format
142+
143+
when:
144+
format = helper.getTimeFormat(style, ZoneId.of('UTC'), Locale.ENGLISH)
145+
146+
then:
147+
format.zone == ZoneId.of('UTC')
148+
format.format(localTime) == expected
149+
150+
where:
151+
style | expected
152+
'FULL' | '8:00:00\u202FAM Coordinated Universal Time'
153+
}
154+
136155
@Requires({ jvm.isJava8() })
137156
@Unroll("for getDateTimeFormat(#dateStyle, #timeStyle) => #expected")
138157
void "Java 8 - test getDateTimeFormat"(String dateStyle, String timeStyle, String expected) {
@@ -175,6 +194,27 @@ class DefaultDateHelperSpec extends Specification {
175194
null | null | '1/5/41, 8:00 AM'
176195
}
177196

197+
@Requires({ Jvm.current.isJava20Compatible() })
198+
@Unroll("for getDateTimeFormat(#dateStyle, #timeStyle) => #expected")
199+
void "Java 20+ - test getDateTimeFormat"(String dateStyle, String timeStyle, String expected) {
200+
given:
201+
DateTimeFormatter format
202+
203+
when:
204+
format = helper.getDateTimeFormat(dateStyle, timeStyle, ZoneId.of('UTC'), Locale.ENGLISH)
205+
206+
then:
207+
format.zone == ZoneId.of('UTC')
208+
format.format(LocalDateTime.of(localDate, localTime)) == expected
209+
210+
where:
211+
dateStyle | timeStyle | expected
212+
'FULL' | 'FULL' | 'Sunday, January 5, 1941, 8:00:00\u202FAM Coordinated Universal Time'
213+
'LONG' | 'LONG' | 'January 5, 1941, 8:00:00\u202FAM UTC'
214+
'MEDIUM' | 'MEDIUM' | 'Jan 5, 1941, 8:00:00\u202FAM'
215+
null | null | '1/5/41, 8:00\u202FAM'
216+
}
217+
178218
void "test supportsDatePickers"() {
179219
expect:
180220
helper.supportsDatePicker(Date)

0 commit comments

Comments
 (0)