Skip to content

Commit 599d534

Browse files
committed
Merge branch '6.1.x'
2 parents 68d9e5d + bbbb7c3 commit 599d534

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,70 @@ void isoDate(String propertyValue) {
339339
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("2021-03-02");
340340
}
341341

342+
/**
343+
* {@link SimpleDateBean#styleDateTimeWithFallbackPatternsForPreAndPostJdk20}
344+
* configures "SS" as the date/time style to use. Thus, we have to be aware
345+
* of the following if we do not configure fallback patterns for parsing.
346+
*
347+
* <ul>
348+
* <li>JDK &le; 19 requires a standard space before the "PM".
349+
* <li>JDK &ge; 20 requires a narrow non-breaking space (NNBSP) before the "PM".
350+
* </ul>
351+
*
352+
* <p>To avoid compatibility issues between JDK versions, we have configured
353+
* two fallback patterns which emulate the "SS" style: <code>"MM/dd/yy h:mm a"</code>
354+
* matches against a standard space before the "PM", and <code>"MM/dd/yy h:mm&#92;u202Fa"</code>
355+
* matches against a narrow non-breaking space (NNBSP) before the "PM".
356+
*
357+
* <p>Thus, the following should theoretically be supported on any JDK (or at least
358+
* JDK 17 - 23, where we have tested it).
359+
*
360+
* @see #patternDateTime(String)
361+
*/
362+
@ParameterizedTest(name = "input date: {0}") // gh-33151
363+
@ValueSource(strings = {"10/31/09, 12:00 PM", "10/31/09, 12:00\u202FPM"})
364+
void styleDateTime_PreAndPostJdk20(String propertyValue) {
365+
String propertyName = "styleDateTimeWithFallbackPatternsForPreAndPostJdk20";
366+
MutablePropertyValues propertyValues = new MutablePropertyValues();
367+
propertyValues.add(propertyName, propertyValue);
368+
binder.bind(propertyValues);
369+
BindingResult bindingResult = binder.getBindingResult();
370+
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
371+
String value = binder.getBindingResult().getFieldValue(propertyName).toString();
372+
// Since the "SS" style is always used for printing and the underlying format
373+
// changes depending on the JDK version, we cannot be certain that a normal
374+
// space is used before the "PM". Consequently we have to use a regular
375+
// expression to match against any Unicode space character (\p{Zs}).
376+
assertThat(value).startsWith("10/31/09").matches(".+?12:00\\p{Zs}PM");
377+
}
378+
379+
/**
380+
* To avoid the use of Locale-based styles (such as "MM") for
381+
* {@link SimpleDateBean#patternDateTimeWithFallbackPatternForPreAndPostJdk20}, we have configured a
382+
* primary pattern (<code>"MM/dd/yy h:mm a"</code>) that matches against a standard space
383+
* before the "PM" and a fallback pattern (<code>"MM/dd/yy h:mm&#92;u202Fa"</code> that matches
384+
* against a narrow non-breaking space (NNBSP) before the "PM".
385+
*
386+
* <p>Thus, the following should theoretically be supported on any JDK (or at least
387+
* JDK 17 - 23, where we have tested it).
388+
*
389+
* @see #styleDateTime(String)
390+
*/
391+
@ParameterizedTest(name = "input date: {0}") // gh-33151
392+
@ValueSource(strings = {"10/31/09 3:45 PM", "10/31/09 3:45\u202FPM"})
393+
void patternDateTime_PreAndPostJdk20(String propertyValue) {
394+
String propertyName = "patternDateTimeWithFallbackPatternForPreAndPostJdk20";
395+
MutablePropertyValues propertyValues = new MutablePropertyValues();
396+
propertyValues.add(propertyName, propertyValue);
397+
binder.bind(propertyValues);
398+
BindingResult bindingResult = binder.getBindingResult();
399+
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
400+
String value = binder.getBindingResult().getFieldValue(propertyName).toString();
401+
// Since the "MM/dd/yy h:mm a" primary pattern is always used for printing, we
402+
// can be certain that a normal space is used before the "PM".
403+
assertThat(value).matches("10/31/09 3:45 PM");
404+
}
405+
342406
@Test
343407
void patternDateWithUnsupportedPattern() {
344408
String propertyValue = "210302";
@@ -389,12 +453,23 @@ private static class SimpleDateBean {
389453
@DateTimeFormat(style = "S-", fallbackPatterns = { "yyyy-MM-dd", "yyyyMMdd", "yyyy.MM.dd" })
390454
private Date styleDateWithFallbackPatterns;
391455

456+
// "SS" style matches either a standard space or a narrow non-breaking space (NNBSP) before AM/PM,
457+
// depending on the version of the JDK.
458+
// Fallback patterns match a standard space OR a narrow non-breaking space (NNBSP) before AM/PM.
459+
@DateTimeFormat(style = "SS", fallbackPatterns = { "M/d/yy, h:mm a", "M/d/yy, h:mm\u202Fa" })
460+
private Date styleDateTimeWithFallbackPatternsForPreAndPostJdk20;
461+
392462
@DateTimeFormat(pattern = "M/d/yy h:mm")
393463
private Date patternDate;
394464

395465
@DateTimeFormat(pattern = "yyyy-MM-dd", fallbackPatterns = { "M/d/yy", "yyyyMMdd", "yyyy.MM.dd" })
396466
private Date patternDateWithFallbackPatterns;
397467

468+
// Primary pattern matches a standard space before AM/PM.
469+
// Fallback pattern matches a narrow non-breaking space (NNBSP) before AM/PM.
470+
@DateTimeFormat(pattern = "MM/dd/yy h:mm a", fallbackPatterns = "MM/dd/yy h:mm\u202Fa")
471+
private Date patternDateTimeWithFallbackPatternForPreAndPostJdk20;
472+
398473
@DateTimeFormat(iso = ISO.DATE)
399474
private Date isoDate;
400475

@@ -459,6 +534,14 @@ public void setStyleDateWithFallbackPatterns(Date styleDateWithFallbackPatterns)
459534
this.styleDateWithFallbackPatterns = styleDateWithFallbackPatterns;
460535
}
461536

537+
public Date getStyleDateTimeWithFallbackPatternsForPreAndPostJdk20() {
538+
return this.styleDateTimeWithFallbackPatternsForPreAndPostJdk20;
539+
}
540+
541+
public void setStyleDateTimeWithFallbackPatternsForPreAndPostJdk20(Date styleDateTimeWithFallbackPatternsForPreAndPostJdk20) {
542+
this.styleDateTimeWithFallbackPatternsForPreAndPostJdk20 = styleDateTimeWithFallbackPatternsForPreAndPostJdk20;
543+
}
544+
462545
public Date getPatternDate() {
463546
return this.patternDate;
464547
}
@@ -475,6 +558,14 @@ public void setPatternDateWithFallbackPatterns(Date patternDateWithFallbackPatte
475558
this.patternDateWithFallbackPatterns = patternDateWithFallbackPatterns;
476559
}
477560

561+
public Date getPatternDateTimeWithFallbackPatternForPreAndPostJdk20() {
562+
return this.patternDateTimeWithFallbackPatternForPreAndPostJdk20;
563+
}
564+
565+
public void setPatternDateTimeWithFallbackPatternForPreAndPostJdk20(Date patternDateTimeWithFallbackPatternForPreAndPostJdk20) {
566+
this.patternDateTimeWithFallbackPatternForPreAndPostJdk20 = patternDateTimeWithFallbackPatternForPreAndPostJdk20;
567+
}
568+
478569
public Date getIsoDate() {
479570
return this.isoDate;
480571
}

spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,41 @@ private void styleLocalTime(String propertyValue) {
618618
assertThat(bindingResult.getFieldValue(propertyName)).asString().matches("12:00:00\\p{Zs}PM");
619619
}
620620

621+
/**
622+
* {@link DateTimeBean#styleLocalTimeWithFallbackPatternsForPreAndPostJdk20}
623+
* configures "-M" as the time style to use. Thus, we have to be aware
624+
* of the following if we do not configure fallback patterns for parsing.
625+
*
626+
* <ul>
627+
* <li>JDK &le; 19 requires a standard space before the "PM".
628+
* <li>JDK &ge; 20 requires a narrow non-breaking space (NNBSP) before the "PM".
629+
* </ul>
630+
*
631+
* <p>To avoid compatibility issues between JDK versions, we have configured
632+
* two fallback patterns which emulate the "-M" style: <code>"HH:mm:ss a"</code>
633+
* matches against a standard space before the "PM", and <code>"HH:mm:ss&#92;u202Fa"</code>
634+
* matches against a narrow non-breaking space (NNBSP) before the "PM".
635+
*
636+
* <p>Thus, the following should theoretically be supported on any JDK (or at least
637+
* JDK 17 - 23, where we have tested it).
638+
*/
639+
@ParameterizedTest(name = "input date: {0}") // gh-33151
640+
@ValueSource(strings = { "12:00:00 PM", "12:00:00\u202FPM" })
641+
void styleLocalTime_PreAndPostJdk20(String propertyValue) {
642+
String propertyName = "styleLocalTimeWithFallbackPatternsForPreAndPostJdk20";
643+
MutablePropertyValues propertyValues = new MutablePropertyValues();
644+
propertyValues.add(propertyName, propertyValue);
645+
binder.bind(propertyValues);
646+
BindingResult bindingResult = binder.getBindingResult();
647+
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
648+
String value = binder.getBindingResult().getFieldValue(propertyName).toString();
649+
// Since the "-M" style is always used for printing and the underlying format
650+
// changes depending on the JDK version, we cannot be certain that a normal
651+
// space is used before the "PM". Consequently we have to use a regular
652+
// expression to match against any Unicode space character (\p{Zs}).
653+
assertThat(value).matches("12:00:00\\p{Zs}PM");
654+
}
655+
621656
@ParameterizedTest(name = "input date: {0}")
622657
@ValueSource(strings = {"2021-03-02T12:00:00", "2021-03-02 12:00:00", "3/2/21 12:00"})
623658
void isoLocalDateTime(String propertyValue) {
@@ -695,6 +730,12 @@ public static class DateTimeBean {
695730
@DateTimeFormat(style = "-M", fallbackPatterns = {"HH:mm:ss", "HH:mm"})
696731
private LocalTime styleLocalTimeWithFallbackPatterns;
697732

733+
// "-M" style matches either a standard space or a narrow non-breaking space (NNBSP) before AM/PM,
734+
// depending on the version of the JDK.
735+
// Fallback patterns match a standard space OR a narrow non-breaking space (NNBSP) before AM/PM.
736+
@DateTimeFormat(style = "-M", fallbackPatterns = {"HH:mm:ss a", "HH:mm:ss\u202Fa"})
737+
private LocalTime styleLocalTimeWithFallbackPatternsForPreAndPostJdk20;
738+
698739
private LocalDateTime localDateTime;
699740

700741
@DateTimeFormat(style = "MM")
@@ -798,6 +839,15 @@ public void setStyleLocalTimeWithFallbackPatterns(LocalTime styleLocalTimeWithFa
798839
this.styleLocalTimeWithFallbackPatterns = styleLocalTimeWithFallbackPatterns;
799840
}
800841

842+
public LocalTime getStyleLocalTimeWithFallbackPatternsForPreAndPostJdk20() {
843+
return this.styleLocalTimeWithFallbackPatternsForPreAndPostJdk20;
844+
}
845+
846+
public void setStyleLocalTimeWithFallbackPatternsForPreAndPostJdk20(
847+
LocalTime styleLocalTimeWithFallbackPatternsForPreAndPostJdk20) {
848+
this.styleLocalTimeWithFallbackPatternsForPreAndPostJdk20 = styleLocalTimeWithFallbackPatternsForPreAndPostJdk20;
849+
}
850+
801851
public LocalDateTime getLocalDateTime() {
802852
return this.localDateTime;
803853
}

0 commit comments

Comments
 (0)