提交 c9a6f428 编写于 作者: M monosoul 提交者: Sam Brannen

Inverse condition to fix ISO-formatted Instant parsing

Prior to this commit, InstantFormatter was able to properly serialize
an Instant that is far in the future (or in the past), but it could not
properly deserialize it, because in such scenarios an ISO-formatted
Instant starts with a +/- sign.

This commit fixes this issue, while maintaining the previous contract,
and also introduces tests for InstantFormatter.

Closes gh-23895
上级 6ed6c08a
......@@ -40,14 +40,14 @@ public class InstantFormatter implements Formatter<Instant> {
@Override
public Instant parse(String text, Locale locale) throws ParseException {
if (text.length() > 0 && Character.isDigit(text.charAt(0))) {
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
return Instant.parse(text);
}
else {
if (text.length() > 0 && Character.isAlphabetic(text.charAt(0))) {
// assuming RFC-1123 value a la "Tue, 3 Jun 2008 11:05:30 GMT"
return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(text));
}
else {
// assuming UTC instant a la "2007-12-03T10:15:30.00Z"
return Instant.parse(text);
}
}
@Override
......
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.format.datetime.standard;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import java.text.ParseException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.stream.Stream;
import static java.time.Instant.MAX;
import static java.time.Instant.MIN;
import static java.time.ZoneId.systemDefault;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Andrei Nevedomskii
*/
@SuppressWarnings("ConstantConditions")
class InstantFormatterTests {
private final InstantFormatter instantFormatter = new InstantFormatter();
@ParameterizedTest
@ArgumentsSource(ISOSerializedInstantProvider.class)
void should_parse_an_ISO_formatted_string_representation_of_an_instant(String input) throws ParseException {
Instant expected = DateTimeFormatter.ISO_INSTANT.parse(input, Instant::from);
Instant actual = instantFormatter.parse(input, null);
assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@ArgumentsSource(RFC1123SerializedInstantProvider.class)
void should_parse_an_RFC1123_formatted_string_representation_of_an_instant(String input) throws ParseException {
Instant expected = DateTimeFormatter.RFC_1123_DATE_TIME.parse(input, Instant::from);
Instant actual = instantFormatter.parse(input, null);
assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@ArgumentsSource(RandomInstantProvider.class)
void should_serialize_an_instant_using_ISO_format_and_ignoring_locale(Instant input) {
String expected = DateTimeFormatter.ISO_INSTANT.format(input);
String actual = instantFormatter.print(input, null);
assertThat(actual).isEqualTo(expected);
}
private static class ISOSerializedInstantProvider extends RandomInstantProvider {
@Override
Stream<?> provideArguments() {
return randomInstantStream(MIN, MAX).map(DateTimeFormatter.ISO_INSTANT::format);
}
}
private static class RFC1123SerializedInstantProvider extends RandomInstantProvider {
// RFC-1123 supports only 4-digit years
private final Instant min = Instant.parse("0000-01-01T00:00:00.00Z");
private final Instant max = Instant.parse("9999-12-31T23:59:59.99Z");
@Override
Stream<?> provideArguments() {
return randomInstantStream(min, max)
.map(DateTimeFormatter.RFC_1123_DATE_TIME.withZone(systemDefault())::format);
}
}
private static class RandomInstantProvider implements ArgumentsProvider {
private static final long DATA_SET_SIZE = 10;
static final Random RANDOM = new Random();
Stream<?> provideArguments() {
return randomInstantStream(MIN, MAX);
}
@Override
public final Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return provideArguments().map(Arguments::of).limit(DATA_SET_SIZE);
}
Stream<Instant> randomInstantStream(Instant min, Instant max) {
return Stream.concat(
Stream.of(Instant.now()), // make sure that the data set includes current instant
RANDOM.longs(min.getEpochSecond(), max.getEpochSecond())
.mapToObj(Instant::ofEpochSecond)
);
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册