Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: import java.time types in TimestampUtils #2380

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
113 changes: 62 additions & 51 deletions pgjdbc/src/main/java/org/postgresql/jdbc/TimestampUtils.java
Expand Up @@ -24,6 +24,17 @@
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.IsoEra;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
Expand All @@ -42,16 +53,16 @@ public class TimestampUtils {
private static final char[][] NUMBERS;
private static final HashMap<String, TimeZone> GMT_ZONES = new HashMap<String, TimeZone>();
private static final int MAX_NANOS_BEFORE_WRAP_ON_ROUND = 999999500;
private static final java.time.Duration ONE_MICROSECOND = java.time.Duration.ofNanos(1000);
private static final Duration ONE_MICROSECOND = Duration.ofNanos(1000);
// LocalTime.MAX is 23:59:59.999_999_999, and it wraps to 24:00:00 when nanos exceed 999_999_499
// since PostgreSQL has microsecond resolution only
private static final java.time.LocalTime MAX_TIME = java.time.LocalTime.MAX.minus(java.time.Duration.ofNanos(500));
private static final java.time.OffsetDateTime MAX_OFFSET_DATETIME = java.time.OffsetDateTime.MAX.minus(java.time.Duration.ofMillis(500));
private static final java.time.LocalDateTime MAX_LOCAL_DATETIME = java.time.LocalDateTime.MAX.minus(java.time.Duration.ofMillis(500));
private static final LocalTime MAX_TIME = LocalTime.MAX.minus(Duration.ofNanos(500));
private static final OffsetDateTime MAX_OFFSET_DATETIME = OffsetDateTime.MAX.minus(Duration.ofMillis(500));
private static final LocalDateTime MAX_LOCAL_DATETIME = LocalDateTime.MAX.minus(Duration.ofMillis(500));
// low value for dates is 4713 BC
private static final java.time.LocalDate MIN_LOCAL_DATE = java.time.LocalDate.of(4713, 1, 1).with(java.time.temporal.ChronoField.ERA, java.time.chrono.IsoEra.BCE.getValue());
private static final java.time.LocalDateTime MIN_LOCAL_DATETIME = MIN_LOCAL_DATE.atStartOfDay();
private static final java.time.OffsetDateTime MIN_OFFSET_DATETIME = MIN_LOCAL_DATETIME.atOffset(java.time.ZoneOffset.UTC);
private static final LocalDate MIN_LOCAL_DATE = LocalDate.of(4713, 1, 1).with(ChronoField.ERA, IsoEra.BCE.getValue());
private static final LocalDateTime MIN_LOCAL_DATETIME = MIN_LOCAL_DATE.atStartOfDay();
private static final OffsetDateTime MIN_OFFSET_DATETIME = MIN_LOCAL_DATETIME.atOffset(ZoneOffset.UTC);

private static final @Nullable Field DEFAULT_TIME_ZONE_FIELD;

Expand Down Expand Up @@ -412,18 +423,18 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {
* @return null if s is null or a LocalTime of the parsed string s.
* @throws SQLException if there is a problem parsing s.
*/
public java.time.@PolyNull LocalTime toLocalTime(@PolyNull String s) throws SQLException {
public @PolyNull LocalTime toLocalTime(@PolyNull String s) throws SQLException {
if (s == null) {
return null;
}

if (s.equals("24:00:00")) {
return java.time.LocalTime.MAX;
return LocalTime.MAX;
}

try {
return java.time.LocalTime.parse(s);
} catch (java.time.format.DateTimeParseException nfe) {
return LocalTime.parse(s);
} catch (DateTimeParseException nfe) {
throw new PSQLException(
GT.tr("Bad value for type timestamp/date/time: {1}", s),
PSQLState.BAD_DATETIME_FORMAT, nfe);
Expand All @@ -438,7 +449,7 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {
* @return null if s is null or a LocalDateTime of the parsed string s.
* @throws SQLException if there is a problem parsing s.
*/
public java.time.@PolyNull LocalDateTime toLocalDateTime(@PolyNull String s) throws SQLException {
public @PolyNull LocalDateTime toLocalDateTime(@PolyNull String s) throws SQLException {
if (s == null) {
return null;
}
Expand All @@ -447,20 +458,20 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {

// convert postgres's infinity values to internal infinity magic value
if (slen == 8 && s.equals("infinity")) {
return java.time.LocalDateTime.MAX;
return LocalDateTime.MAX;
}

if (slen == 9 && s.equals("-infinity")) {
return java.time.LocalDateTime.MIN;
return LocalDateTime.MIN;
}

ParsedTimestamp ts = parseBackendTimestamp(s);

// intentionally ignore time zone
// 2004-10-19 10:23:54+03:00 is 2004-10-19 10:23:54 locally
java.time.LocalDateTime result = java.time.LocalDateTime.of(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.nanos);
LocalDateTime result = LocalDateTime.of(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.nanos);
if (ts.era == GregorianCalendar.BC) {
return result.with(java.time.temporal.ChronoField.ERA, java.time.chrono.IsoEra.BCE.getValue());
return result.with(ChronoField.ERA, IsoEra.BCE.getValue());
} else {
return result;
}
Expand All @@ -473,7 +484,7 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {
* @return null if s is null or a LocalDateTime of the parsed string s.
* @throws SQLException if there is a problem parsing s.
*/
public java.time.@PolyNull OffsetDateTime toOffsetDateTime(
public @PolyNull OffsetDateTime toOffsetDateTime(
@PolyNull String s) throws SQLException {
if (s == null) {
return null;
Expand All @@ -483,11 +494,11 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {

// convert postgres's infinity values to internal infinity magic value
if (slen == 8 && s.equals("infinity")) {
return java.time.OffsetDateTime.MAX;
return OffsetDateTime.MAX;
}

if (slen == 9 && s.equals("-infinity")) {
return java.time.OffsetDateTime.MIN;
return OffsetDateTime.MIN;
}

ParsedTimestamp ts = parseBackendTimestamp(s);
Expand All @@ -499,12 +510,12 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {
} else {
offsetSeconds = tz.get(Calendar.ZONE_OFFSET) / 1000;
}
java.time.ZoneOffset zoneOffset = java.time.ZoneOffset.ofTotalSeconds(offsetSeconds);
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(offsetSeconds);
// Postgres is always UTC
java.time.OffsetDateTime result = java.time.OffsetDateTime.of(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.nanos, zoneOffset)
.withOffsetSameInstant(java.time.ZoneOffset.UTC);
OffsetDateTime result = OffsetDateTime.of(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.nanos, zoneOffset)
.withOffsetSameInstant(ZoneOffset.UTC);
if (ts.era == GregorianCalendar.BC) {
return result.with(java.time.temporal.ChronoField.ERA, java.time.chrono.IsoEra.BCE.getValue());
return result.with(ChronoField.ERA, IsoEra.BCE.getValue());
} else {
return result;
}
Expand All @@ -516,10 +527,10 @@ private ParsedTimestamp parseBackendTimestamp(String str) throws SQLException {
* @param t the time value
* @return the matching offset date time
*/
public java.time.OffsetDateTime toOffsetDateTime(Time t) {
public OffsetDateTime toOffsetDateTime(Time t) {
// hardcode utc because the backend does not provide us the timezone
// hardcode UNIX epoch, JDBC requires OffsetDateTime but doesn't describe what date should be used
return t.toLocalTime().atDate(java.time.LocalDate.of(1970, 1, 1)).atOffset(java.time.ZoneOffset.UTC);
return t.toLocalTime().atDate(LocalDate.of(1970, 1, 1)).atOffset(ZoneOffset.UTC);
}

/**
Expand All @@ -529,18 +540,18 @@ public java.time.OffsetDateTime toOffsetDateTime(Time t) {
* @return The parsed local date time object.
* @throws PSQLException If binary format could not be parsed.
*/
public java.time.OffsetDateTime toOffsetDateTimeBin(byte[] bytes) throws PSQLException {
public OffsetDateTime toOffsetDateTimeBin(byte[] bytes) throws PSQLException {
ParsedBinaryTimestamp parsedTimestamp = this.toProlepticParsedTimestampBin(bytes);
if (parsedTimestamp.infinity == Infinity.POSITIVE) {
return java.time.OffsetDateTime.MAX;
return OffsetDateTime.MAX;
} else if (parsedTimestamp.infinity == Infinity.NEGATIVE) {
return java.time.OffsetDateTime.MIN;
return OffsetDateTime.MIN;
}

// hardcode utc because the backend does not provide us the timezone
// Postgres is always UTC
java.time.Instant instant = java.time.Instant.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos);
return java.time.OffsetDateTime.ofInstant(instant, java.time.ZoneOffset.UTC);
Instant instant = Instant.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos);
return OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
}

public synchronized @PolyNull Time toTime(
Expand Down Expand Up @@ -828,8 +839,8 @@ private static void appendEra(StringBuilder sb, Calendar cal) {
}
}

public synchronized String toString(java.time.LocalDate localDate) {
if (java.time.LocalDate.MAX.equals(localDate)) {
public synchronized String toString(LocalDate localDate) {
if (LocalDate.MAX.equals(localDate)) {
return "infinity";
} else if (localDate.isBefore(MIN_LOCAL_DATE)) {
return "-infinity";
Expand All @@ -843,7 +854,7 @@ public synchronized String toString(java.time.LocalDate localDate) {
return sbuf.toString();
}

public synchronized String toString(java.time.LocalTime localTime) {
public synchronized String toString(LocalTime localTime) {

sbuf.setLength(0);

Expand All @@ -862,7 +873,7 @@ public synchronized String toString(java.time.LocalTime localTime) {
return sbuf.toString();
}

public synchronized String toString(java.time.OffsetDateTime offsetDateTime) {
public synchronized String toString(OffsetDateTime offsetDateTime) {
if (offsetDateTime.isAfter(MAX_OFFSET_DATETIME)) {
return "infinity";
} else if (offsetDateTime.isBefore(MIN_OFFSET_DATETIME)) {
Expand All @@ -877,8 +888,8 @@ public synchronized String toString(java.time.OffsetDateTime offsetDateTime) {
// it relies on the fact that appendTime just truncates 000..999 nanosecond part
offsetDateTime = offsetDateTime.plus(ONE_MICROSECOND);
}
java.time.LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
java.time.LocalDate localDate = localDateTime.toLocalDate();
LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
LocalDate localDate = localDateTime.toLocalDate();
appendDate(sbuf, localDate);
sbuf.append(' ');
appendTime(sbuf, localDateTime.toLocalTime());
Expand All @@ -889,46 +900,46 @@ public synchronized String toString(java.time.OffsetDateTime offsetDateTime) {
}

/**
* Formats {@link java.time.LocalDateTime} to be sent to the backend, thus it adds time zone.
* Formats {@link LocalDateTime} to be sent to the backend, thus it adds time zone.
* Do not use this method in {@link java.sql.ResultSet#getString(int)}
* @param localDateTime The local date to format as a String
* @return The formatted local date
*/
public synchronized String toString(java.time.LocalDateTime localDateTime) {
public synchronized String toString(LocalDateTime localDateTime) {
if (localDateTime.isAfter(MAX_LOCAL_DATETIME)) {
return "infinity";
} else if (localDateTime.isBefore(MIN_LOCAL_DATETIME)) {
return "-infinity";
}

// LocalDateTime is always passed with time zone so backend can decide between timestamp and timestamptz
java.time.ZonedDateTime zonedDateTime = localDateTime.atZone(getDefaultTz().toZoneId());
ZonedDateTime zonedDateTime = localDateTime.atZone(getDefaultTz().toZoneId());
return toString(zonedDateTime.toOffsetDateTime());
}

private static void appendDate(StringBuilder sb, java.time.LocalDate localDate) {
int year = localDate.get(java.time.temporal.ChronoField.YEAR_OF_ERA);
private static void appendDate(StringBuilder sb, LocalDate localDate) {
int year = localDate.get(ChronoField.YEAR_OF_ERA);
int month = localDate.getMonthValue();
int day = localDate.getDayOfMonth();
appendDate(sb, year, month, day);
}

private static void appendTime(StringBuilder sb, java.time.LocalTime localTime) {
private static void appendTime(StringBuilder sb, LocalTime localTime) {
int hours = localTime.getHour();
int minutes = localTime.getMinute();
int seconds = localTime.getSecond();
int nanos = localTime.getNano();
appendTime(sb, hours, minutes, seconds, nanos);
}

private void appendTimeZone(StringBuilder sb, java.time.ZoneOffset offset) {
private void appendTimeZone(StringBuilder sb, ZoneOffset offset) {
int offsetSeconds = offset.getTotalSeconds();

appendTimeZone(sb, offsetSeconds);
}

private static void appendEra(StringBuilder sb, java.time.LocalDate localDate) {
if (localDate.get(java.time.temporal.ChronoField.ERA) == java.time.chrono.IsoEra.BCE.getValue()) {
private static void appendEra(StringBuilder sb, LocalDate localDate) {
if (localDate.get(ChronoField.ERA) == IsoEra.BCE.getValue()) {
sb.append(" BC");
}
}
Expand Down Expand Up @@ -1081,7 +1092,7 @@ public Time toTimeBin(@Nullable TimeZone tz, byte[] bytes) throws PSQLException
* @return The parsed time object.
* @throws PSQLException If binary format could not be parsed.
*/
public java.time.LocalTime toLocalTimeBin(byte[] bytes) throws PSQLException {
public LocalTime toLocalTimeBin(byte[] bytes) throws PSQLException {
if (bytes.length != 8) {
throw new PSQLException(GT.tr("Unsupported binary encoding of {0}.", "time"),
PSQLState.BAD_DATETIME_FORMAT);
Expand All @@ -1097,7 +1108,7 @@ public java.time.LocalTime toLocalTimeBin(byte[] bytes) throws PSQLException {
micros = ByteConverter.int8(bytes, 0);
}

return java.time.LocalTime.ofNanoOfDay(micros * 1000);
return LocalTime.ofNanoOfDay(micros * 1000);
}

/**
Expand Down Expand Up @@ -1233,18 +1244,18 @@ private ParsedBinaryTimestamp toProlepticParsedTimestampBin(byte[] bytes)
* @return The parsed local date time object.
* @throws PSQLException If binary format could not be parsed.
*/
public java.time.LocalDateTime toLocalDateTimeBin(byte[] bytes) throws PSQLException {
public LocalDateTime toLocalDateTimeBin(byte[] bytes) throws PSQLException {

ParsedBinaryTimestamp parsedTimestamp = this.toProlepticParsedTimestampBin(bytes);
if (parsedTimestamp.infinity == Infinity.POSITIVE) {
return java.time.LocalDateTime.MAX;
return LocalDateTime.MAX;
} else if (parsedTimestamp.infinity == Infinity.NEGATIVE) {
return java.time.LocalDateTime.MIN;
return LocalDateTime.MIN;
}

// hardcode utc because the backend does not provide us the timezone
// Postgres is always UTC
return java.time.LocalDateTime.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos, java.time.ZoneOffset.UTC);
return LocalDateTime.ofEpochSecond(parsedTimestamp.millis / 1000L, parsedTimestamp.nanos, ZoneOffset.UTC);
}

/**
Expand Down