Skip to content

Commit 7bae0e3

Browse files
committed
Polishing.
Add support for offset representation variants (short and full). [#509][resolves #510] Signed-off-by: Mark Paluch <[email protected]>
1 parent 4a3b384 commit 7bae0e3

File tree

4 files changed

+110
-6
lines changed

4 files changed

+110
-6
lines changed

src/main/java/io/r2dbc/postgresql/codec/AbstractTemporalCodec.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private Temporal decodeTemporal(ByteBuf buffer, PostgresqlObjectId dataType, @Nu
118118
return EpochTime.fromLong(buffer.readLong()).toLocalDateTime();
119119
}
120120

121-
return PostgresqlDateTimeFormatter.INSTANCE.parse(ByteBufUtils.decode(buffer), LocalDateTime::from);
121+
return PostgresqlDateTimeFormatter.parse(ByteBufUtils.decode(buffer), LocalDateTime::from);
122122
case DATE:
123123
case DATE_ARRAY:
124124
if (FORMAT_BINARY == format) {
@@ -139,7 +139,7 @@ private Temporal decodeTemporal(ByteBuf buffer, PostgresqlObjectId dataType, @Nu
139139
return EpochTime.fromLong(buffer.readLong()).toInstant().atOffset(OffsetDateTime.now().getOffset());
140140
}
141141

142-
return PostgresqlDateTimeFormatter.INSTANCE.parse(ByteBufUtils.decode(buffer), ZonedDateTime::from);
142+
return PostgresqlDateTimeFormatter.parse(ByteBufUtils.decode(buffer), ZonedDateTime::from);
143143
case TIMETZ:
144144
case TIMETZ_ARRAY:
145145
if (FORMAT_BINARY == format) {
@@ -148,7 +148,7 @@ private Temporal decodeTemporal(ByteBuf buffer, PostgresqlObjectId dataType, @Nu
148148
return OffsetTime.of(LocalTime.ofNanoOfDay(timeNano), ZoneOffset.ofTotalSeconds(offsetSec));
149149
}
150150

151-
return PostgresqlTimeFormatter.INSTANCE.parse(ByteBufUtils.decode(buffer), OffsetTime::from);
151+
return PostgresqlTimeFormatter.parse(ByteBufUtils.decode(buffer), OffsetTime::from);
152152
}
153153

154154
throw new UnsupportedOperationException(String.format("Cannot decode value for type %s, format %s", dataType, format));

src/main/java/io/r2dbc/postgresql/codec/PostgresqlDateTimeFormatter.java

+54-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import java.time.format.DateTimeFormatter;
2020
import java.time.format.DateTimeFormatterBuilder;
21+
import java.time.format.DateTimeParseException;
2122
import java.time.format.SignStyle;
23+
import java.time.temporal.TemporalQuery;
2224

2325
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
2426
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
@@ -30,7 +32,7 @@
3032

3133
class PostgresqlDateTimeFormatter {
3234

33-
static final DateTimeFormatter INSTANCE =
35+
private static final DateTimeFormatter FULL_OFFSET =
3436
new DateTimeFormatterBuilder()
3537
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
3638
.appendLiteral('-')
@@ -48,8 +50,58 @@ class PostgresqlDateTimeFormatter {
4850
.appendFraction(NANO_OF_SECOND, 0, 9, true)
4951
.optionalEnd()
5052
.optionalStart()
51-
.appendOffset("+HH:mm:ss", "+00:00:00")
53+
.appendOffset("+HH:MM:ss", "+00:00:00")
5254
.optionalEnd()
5355
.toFormatter();
5456

57+
private static final DateTimeFormatter SHORT_OFFSET =
58+
new DateTimeFormatterBuilder()
59+
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
60+
.appendLiteral('-')
61+
.appendValue(MONTH_OF_YEAR, 2)
62+
.appendLiteral('-')
63+
.appendValue(DAY_OF_MONTH, 2)
64+
.appendLiteral(' ')
65+
.appendValue(HOUR_OF_DAY, 2)
66+
.appendLiteral(':')
67+
.appendValue(MINUTE_OF_HOUR, 2)
68+
.optionalStart()
69+
.appendLiteral(':')
70+
.appendValue(SECOND_OF_MINUTE, 2)
71+
.optionalStart()
72+
.appendFraction(NANO_OF_SECOND, 0, 9, true)
73+
.optionalEnd()
74+
.optionalStart()
75+
.appendOffset("+HH:mm", "+00:00")
76+
.optionalEnd()
77+
.toFormatter();
78+
79+
/**
80+
* Fully parses the text producing an object of the specified type.
81+
* Attempts to parse the text using {@link #SHORT_OFFSET} first, then {@link #FULL_OFFSET}.
82+
* <p>
83+
* Most applications should use this method for parsing.
84+
* It parses the entire text to produce the required date-time.
85+
* For example:
86+
* <pre>
87+
* LocalDateTime dt = parse(str, LocalDateTime::from);
88+
* </pre>
89+
* If the parse completes without reading the entire length of the text,
90+
* or a problem occurs during parsing or merging, then an exception is thrown.
91+
*
92+
* @param <T> the type of the parsed date-time
93+
* @param text the text to parse, not null
94+
* @param query the query defining the type to parse to, not null
95+
* @return the parsed date-time, not null
96+
* @throws DateTimeParseException if unable to parse the requested result
97+
*/
98+
static <T> T parse(CharSequence text, TemporalQuery<T> query) {
99+
100+
try {
101+
return SHORT_OFFSET.parse(text, query);
102+
} catch (DateTimeParseException e) {
103+
return FULL_OFFSET.parse(text, query);
104+
}
105+
}
106+
55107
}

src/main/java/io/r2dbc/postgresql/codec/PostgresqlTimeFormatter.java

+47-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.time.format.DateTimeFormatter;
2020
import java.time.format.DateTimeFormatterBuilder;
21+
import java.time.format.DateTimeParseException;
22+
import java.time.temporal.TemporalQuery;
2123

2224
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
2325
import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
@@ -26,7 +28,7 @@
2628

2729
class PostgresqlTimeFormatter {
2830

29-
static final DateTimeFormatter INSTANCE =
31+
private static final DateTimeFormatter SHORT_OFFSET =
3032
new DateTimeFormatterBuilder()
3133
.appendValue(HOUR_OF_DAY, 2)
3234
.appendLiteral(':')
@@ -42,4 +44,48 @@ class PostgresqlTimeFormatter {
4244
.optionalEnd()
4345
.toFormatter();
4446

47+
private static final DateTimeFormatter FULL_OFFSET =
48+
new DateTimeFormatterBuilder()
49+
.appendValue(HOUR_OF_DAY, 2)
50+
.appendLiteral(':')
51+
.appendValue(MINUTE_OF_HOUR, 2)
52+
.optionalStart()
53+
.appendLiteral(':')
54+
.appendValue(SECOND_OF_MINUTE, 2)
55+
.optionalStart()
56+
.appendFraction(NANO_OF_SECOND, 0, 9, true)
57+
.optionalEnd()
58+
.optionalStart()
59+
.appendOffset("+HH:MM:ss", "+00:00")
60+
.optionalEnd()
61+
.toFormatter();
62+
63+
/**
64+
* Fully parses the text producing an object of the specified type.
65+
* Attempts to parse the text using {@link #SHORT_OFFSET} first, then {@link #FULL_OFFSET}.
66+
* <p>
67+
* Most applications should use this method for parsing.
68+
* It parses the entire text to produce the required date-time.
69+
* For example:
70+
* <pre>
71+
* OffsetTime dt = parse(str, OffsetTime::from);
72+
* </pre>
73+
* If the parse completes without reading the entire length of the text,
74+
* or a problem occurs during parsing or merging, then an exception is thrown.
75+
*
76+
* @param <T> the type of the parsed date-time
77+
* @param text the text to parse, not null
78+
* @param query the query defining the type to parse to, not null
79+
* @return the parsed date-time, not null
80+
* @throws DateTimeParseException if unable to parse the requested result
81+
*/
82+
static <T> T parse(CharSequence text, TemporalQuery<T> query) {
83+
84+
try {
85+
return SHORT_OFFSET.parse(text, query);
86+
} catch (DateTimeParseException e) {
87+
return FULL_OFFSET.parse(text, query);
88+
}
89+
}
90+
4591
}

src/test/java/io/r2dbc/postgresql/codec/OffsetTimeCodecUnitTests.java

+6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ void decode() {
5252

5353
assertThat(new OffsetTimeCodec(TEST).decode(encode(TEST, "21:16:41.123456-09:00"), dataType, FORMAT_TEXT, OffsetTime.class))
5454
.isEqualTo(offsetTime);
55+
56+
assertThat(new OffsetTimeCodec(TEST).decode(encode(TEST, "21:16:41.123456-09"), dataType, FORMAT_TEXT, OffsetTime.class))
57+
.isEqualTo(offsetTime);
58+
59+
assertThat(new OffsetTimeCodec(TEST).decode(encode(TEST, "21:16:41.123456-09:00:00"), dataType, FORMAT_TEXT, OffsetTime.class))
60+
.isEqualTo(offsetTime);
5561
}
5662

5763
@Test

0 commit comments

Comments
 (0)