Skip to content

Commit 7c6c703

Browse files
committed
Merge pull request #18772 from knittl
* gh-18772: Polish "Enable users to provide custom time and datetime formats" Enable users to provide custom time and datetime formats Closes gh-18772
2 parents 6921fda + 95e5d4e commit 7c6c703

File tree

9 files changed

+407
-40
lines changed

9 files changed

+407
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.web.format;
18+
19+
import java.time.format.DateTimeFormatter;
20+
import java.time.format.ResolverStyle;
21+
22+
import org.springframework.util.StringUtils;
23+
24+
/**
25+
* {@link DateTimeFormatter Formatters} for dates, times, and date-times.
26+
*
27+
* @author Andy Wilkinson
28+
* @since 2.3.0
29+
*/
30+
public class DateTimeFormatters {
31+
32+
private DateTimeFormatter dateFormatter;
33+
34+
private String datePattern;
35+
36+
private DateTimeFormatter timeFormatter;
37+
38+
private DateTimeFormatter dateTimeFormatter;
39+
40+
/**
41+
* Configures the date format using the given {@code pattern}.
42+
* @param pattern the pattern for formatting dates
43+
* @return {@code this} for chained method invocation
44+
*/
45+
public DateTimeFormatters dateFormat(String pattern) {
46+
this.dateFormatter = formatter(pattern);
47+
this.datePattern = pattern;
48+
return this;
49+
}
50+
51+
/**
52+
* Configures the time format using the given {@code pattern}.
53+
* @param pattern the pattern for formatting times
54+
* @return {@code this} for chained method invocation
55+
*/
56+
public DateTimeFormatters timeFormat(String pattern) {
57+
this.timeFormatter = formatter(pattern);
58+
return this;
59+
}
60+
61+
/**
62+
* Configures the date-time format using the given {@code pattern}.
63+
* @param pattern the pattern for formatting date-times
64+
* @return {@code this} for chained method invocation
65+
*/
66+
public DateTimeFormatters dateTimeFormat(String pattern) {
67+
this.dateTimeFormatter = formatter(pattern);
68+
return this;
69+
}
70+
71+
DateTimeFormatter getDateFormatter() {
72+
return this.dateFormatter;
73+
}
74+
75+
String getDatePattern() {
76+
return this.datePattern;
77+
}
78+
79+
DateTimeFormatter getTimeFormatter() {
80+
return this.timeFormatter;
81+
}
82+
83+
DateTimeFormatter getDateTimeFormatter() {
84+
return this.dateTimeFormatter;
85+
}
86+
87+
boolean isCustomized() {
88+
return this.dateFormatter != null || this.timeFormatter != null || this.dateTimeFormatter != null;
89+
}
90+
91+
private static DateTimeFormatter formatter(String pattern) {
92+
return StringUtils.hasText(pattern)
93+
? DateTimeFormatter.ofPattern(pattern).withResolverStyle(ResolverStyle.SMART) : null;
94+
}
95+
96+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
package org.springframework.boot.autoconfigure.web.format;
1818

1919
import java.time.format.DateTimeFormatter;
20-
import java.time.format.ResolverStyle;
20+
import java.util.function.Consumer;
21+
import java.util.function.Supplier;
2122

2223
import org.springframework.format.datetime.DateFormatter;
2324
import org.springframework.format.datetime.DateFormatterRegistrar;
@@ -28,7 +29,6 @@
2829
import org.springframework.format.number.money.MonetaryAmountFormatter;
2930
import org.springframework.format.support.DefaultFormattingConversionService;
3031
import org.springframework.util.ClassUtils;
31-
import org.springframework.util.StringUtils;
3232

3333
/**
3434
* {@link org.springframework.format.support.FormattingConversionService} dedicated to web
@@ -46,48 +46,67 @@ public class WebConversionService extends DefaultFormattingConversionService {
4646
private static final boolean JSR_354_PRESENT = ClassUtils.isPresent("javax.money.MonetaryAmount",
4747
WebConversionService.class.getClassLoader());
4848

49-
private final String dateFormat;
50-
5149
/**
5250
* Create a new WebConversionService that configures formatters with the provided date
5351
* format, or register the default ones if no custom format is provided.
5452
* @param dateFormat the custom date format to use for date conversions
53+
* @deprecated since 2.3.0 in favor of
54+
* {@link #WebConversionService(DateTimeFormatters)}
5555
*/
56+
@Deprecated
5657
public WebConversionService(String dateFormat) {
58+
this(new DateTimeFormatters().dateFormat(dateFormat));
59+
}
60+
61+
/**
62+
* Create a new WebConversionService that configures formatters with the provided
63+
* date, time, and date-time formats, or registers the default if no custom format is
64+
* provided.
65+
* @param dateTimeFormatters the formatters to use for date, time, and date-time
66+
* formatting
67+
* @since 2.3.0
68+
*/
69+
public WebConversionService(DateTimeFormatters dateTimeFormatters) {
5770
super(false);
58-
this.dateFormat = StringUtils.hasText(dateFormat) ? dateFormat : null;
59-
if (this.dateFormat != null) {
60-
addFormatters();
71+
if (dateTimeFormatters.isCustomized()) {
72+
addFormatters(dateTimeFormatters);
6173
}
6274
else {
6375
addDefaultFormatters(this);
6476
}
6577
}
6678

67-
private void addFormatters() {
79+
private void addFormatters(DateTimeFormatters dateTimeFormatters) {
6880
addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
6981
if (JSR_354_PRESENT) {
7082
addFormatter(new CurrencyUnitFormatter());
7183
addFormatter(new MonetaryAmountFormatter());
7284
addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
7385
}
74-
registerJsr310();
75-
registerJavaDate();
86+
registerJsr310(dateTimeFormatters);
87+
registerJavaDate(dateTimeFormatters);
7688
}
7789

78-
private void registerJsr310() {
90+
private void registerJsr310(DateTimeFormatters dateTimeFormatters) {
7991
DateTimeFormatterRegistrar dateTime = new DateTimeFormatterRegistrar();
80-
if (this.dateFormat != null) {
81-
dateTime.setDateFormatter(
82-
DateTimeFormatter.ofPattern(this.dateFormat).withResolverStyle(ResolverStyle.SMART));
83-
}
92+
configure(dateTimeFormatters::getDateFormatter, dateTime::setDateFormatter);
93+
configure(dateTimeFormatters::getTimeFormatter, dateTime::setTimeFormatter);
94+
configure(dateTimeFormatters::getDateTimeFormatter, dateTime::setDateTimeFormatter);
8495
dateTime.registerFormatters(this);
8596
}
8697

87-
private void registerJavaDate() {
98+
private void configure(Supplier<DateTimeFormatter> supplier, Consumer<DateTimeFormatter> consumer) {
99+
DateTimeFormatter formatter = supplier.get();
100+
if (formatter != null) {
101+
consumer.accept(formatter);
102+
}
103+
}
104+
105+
private void registerJavaDate(DateTimeFormatters dateTimeFormatters) {
88106
DateFormatterRegistrar dateFormatterRegistrar = new DateFormatterRegistrar();
89-
if (this.dateFormat != null) {
90-
DateFormatter dateFormatter = new DateFormatter(this.dateFormat);
107+
String datePattern = dateTimeFormatters.getDatePattern();
108+
if (datePattern != null) {
109+
DateFormatter dateFormatter = new DateFormatter(datePattern);
91110
dateFormatterRegistrar.setFormatter(dateFormatter);
92111
}
93112
dateFormatterRegistrar.registerFormatters(this);

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
3636
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
3737
import org.springframework.boot.autoconfigure.web.ResourceProperties;
38+
import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;
3839
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
40+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties.Format;
3941
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4042
import org.springframework.boot.convert.ApplicationConversionService;
4143
import org.springframework.boot.web.codec.CodecCustomizer;
@@ -203,7 +205,9 @@ public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
203205
@Bean
204206
@Override
205207
public FormattingConversionService webFluxConversionService() {
206-
WebConversionService conversionService = new WebConversionService(this.webFluxProperties.getDateFormat());
208+
Format format = this.webFluxProperties.getFormat();
209+
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
210+
.dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
207211
addFormatters(conversionService);
208212
return conversionService;
209213
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.web.reactive;
1818

1919
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
2021
import org.springframework.util.StringUtils;
2122

2223
/**
@@ -33,10 +34,7 @@ public class WebFluxProperties {
3334
*/
3435
private String basePath;
3536

36-
/**
37-
* Date format to use. For instance, `dd/MM/yyyy`.
38-
*/
39-
private String dateFormat;
37+
private final Format format = new Format();
4038

4139
/**
4240
* Path pattern used for static resources.
@@ -64,12 +62,19 @@ private String cleanBasePath(String basePath) {
6462
return candidate;
6563
}
6664

65+
@Deprecated
66+
@DeprecatedConfigurationProperty(replacement = "spring.webflux.format.date")
6767
public String getDateFormat() {
68-
return this.dateFormat;
68+
return this.format.getDate();
6969
}
7070

71+
@Deprecated
7172
public void setDateFormat(String dateFormat) {
72-
this.dateFormat = dateFormat;
73+
this.format.setDate(dateFormat);
74+
}
75+
76+
public Format getFormat() {
77+
return this.format;
7378
}
7479

7580
public String getStaticPathPattern() {
@@ -80,4 +85,47 @@ public void setStaticPathPattern(String staticPathPattern) {
8085
this.staticPathPattern = staticPathPattern;
8186
}
8287

88+
public static class Format {
89+
90+
/**
91+
* Date format to use, for example `dd/MM/yyyy`.
92+
*/
93+
private String date;
94+
95+
/**
96+
* Time format to use, for example `HH:mm:ss`.
97+
*/
98+
private String time;
99+
100+
/**
101+
* Date-time format to use, for example `yyyy-MM-dd HH:mm:ss`.
102+
*/
103+
private String dateTime;
104+
105+
public String getDate() {
106+
return this.date;
107+
}
108+
109+
public void setDate(String date) {
110+
this.date = date;
111+
}
112+
113+
public String getTime() {
114+
return this.time;
115+
}
116+
117+
public void setTime(String time) {
118+
this.time = time;
119+
}
120+
121+
public String getDateTime() {
122+
return this.dateTime;
123+
}
124+
125+
public void setDateTime(String dateTime) {
126+
this.dateTime = dateTime;
127+
}
128+
129+
}
130+
83131
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
5252
import org.springframework.boot.autoconfigure.web.ResourceProperties;
5353
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
54+
import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;
5455
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
56+
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.Format;
5557
import org.springframework.boot.context.properties.EnableConfigurationProperties;
5658
import org.springframework.boot.convert.ApplicationConversionService;
5759
import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter;
@@ -427,7 +429,9 @@ private boolean isReadable(Resource resource) {
427429
@Bean
428430
@Override
429431
public FormattingConversionService mvcConversionService() {
430-
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
432+
Format format = this.mvcProperties.getFormat();
433+
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
434+
.dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
431435
addFormatters(conversionService);
432436
return conversionService;
433437
}

0 commit comments

Comments
 (0)