Skip to content

Commit

Permalink
#758 Express getDate, getTime and getTimestamp in terms of LocalDate,…
Browse files Browse the repository at this point in the history
… LocalTime and LocalDateTime

Remove legacy types from DatatypeCoder.
Also replace MaxFbTimePrecision.INSTANCE with FbDateTimeConversions.FB_TIME_UNIT
  • Loading branch information
mrotteveel committed Jul 26, 2023
1 parent 17e2458 commit f19dc6e
Show file tree
Hide file tree
Showing 19 changed files with 544 additions and 916 deletions.
49 changes: 43 additions & 6 deletions src/docs/asciidoc/release_notes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,17 @@ For compatibility with use on the classpath, it is recommended to also provide t

For more information, see also https://github.com/FirebirdSQL/jaybird/blob/master/devdoc/jdp/jdp-2023-13-modularization-of-jaybird.adoc[jdp-2023-13: Modularization of Jaybird^].

[#timestamp-localdate-localtime]
=== `TIMESTAMP` fields now accept `LocalDate` and `LocalTime`

The JDBC specification does not specify support for `LocalDate` and `LocalTime` on `TIMESTAMP` (without time zone).
However, when we introduced support for the `java.time` types, we implemented support for getting `LocalDate` and `LocalTime` (through `getObject`), but did not provide support for setting values of those types (through `setObject`) on `TIMESTAMP`.

We have now addressed this inconsistency, by also introducing support for setting these types on `TIMESTAMP` with the following behaviour:

* `setObject(..., localTime)` sets a `LocalDateTime` derived as `LocalDate.EPOCH.atTime(localTime)` (i.e. on 1970-01-01)
* `setObject(..., localDate)` sets a `LocalDateTime` derived as `localDate.atStartOfDay()` (i.e. at 00:00:00)
// TODO add major changes

[#potentially-breaking-changes]
Expand Down Expand Up @@ -890,9 +901,19 @@ This results in some minor differences:

* `getString(...)` on a `TIME` field will now render fractional seconds if available
* `setString(...)` on a `TIME` field now has seconds optional and accepts fractional seconds
* `setTime(...)` on a `TIME` field will not set sub-second values (previously this could vary with the millisecond value wrapped by `java.sql.Time`)
* `getString(...)` on a `TIMESTAMP` field will now render without `.0` at the end if the value does not have fractional seconds (e.g. `2023-07-22 12:43:45` instead of `2023-07-22 12:43:45.0`)
* `setString(...)` on a `TIMESTAMP` field now has seconds optional
* `setString(...)` on a `TIMESTAMP` field now also accepts ISO 8601 datetime strings (that is, with a `T` as a separator instead of a space, for example, `2023-07-22 12:43:45` and `2023-07-22T12:43:45` are now both accepted)
* `setDate(...)` on a `TIMESTAMP` field now sets time to 00:00:00 (previously this could vary with the millisecond value wrapped by `java.sql.Date`)
* `setTime(...)` on a `TIMESTAMP` field will now always set at 1970-01-01, and will not set sub-second values (previously this could vary with the millisecond value wrapped by `java.sql.Time`)
* `setTimestamp(...)` on a `CHAR`/`VARCHAR`/`BLOB SUB_TYPE TEXT` field will now set the value without `.0` at the end if the value does not have fractional seconds (e.g. `2023-07-22 12:43:45` instead of `2023-07-22 12:43:45.0`)
* `getTimestamp(...)` on a `CHAR`/`VARCHAR`/`BLOB SUB_TYPE TEXT` field will now also parse ISO 8601 datetime strings (that is, with a `T` as a separator instead of a space, for example, `2023-07-22 12:43:45` and `2023-07-22T12:43:45` are now both accepted), and seconds are now optional
* `getTime(...)` on a `CHAR`/`VARCHAR`/`BLOB SUB_TYPE TEXT` field will now parse values without seconds and values with fractional seconds.
Though it can parse it, the resulting value will not include fractional seconds.
* `setDate(..., Calendar)` on a `CHAR`/`VARCHAR`/`BLOB SUB_TYPE TEXT` field will now use the `Calendar` to rebase the date, this can result in an off-by-one difference in the date compared to previous versions (depending on the time zone set on the `Calendar`)
* `getDate(..., Calendar)` on a `CHAR`/`VARCHAR`/`BLOB SUB_TYPE TEXT` field will now use the `Calendar` to rebase the date, this can result in an off-by-one difference in the date compared to previous versions (depending on the time zone set on the `Calendar`)
* The `TypeConversionException` thrown by `getDate(...)`, `getTime(...)` and `getTimestamp(...)` on unsupported types may now report `java.time.LocalDate`, `java.time.LocalTime` or `java.time.LocalDateTime` as the type in its error message instead of `java.sql.Date`, `java.sql.Time`, or `java.sql.Timestamp`

// TODO Document compatibility issues

Expand Down Expand Up @@ -1208,21 +1229,37 @@ The new package is not exported from the module.
* `DbMetadataMediator` was moved to package `org.firebirdsql.jdbc` for module accessibility reasons.
* `DatatypeCoder`
** `encodeTimestamp(Timestamp, Calendar, boolean)` was removed;
use `encodeTimestamp(Timestamp, Calendar)`
there is no replacement
** `decodeTimestamp(Timestamp, Calendar, boolean)` was removed;
use `decodeTimestamp(Timestamp, Calendar)`
** `encodeTime(Time, Calendar, boolean)` was removed;
use `encodeTime(Time, Calendar)`
** `decodeTime(Time, Calendar, boolean)` was removed;
use `decodeTime(Time, Calendar)`
there is no replacement
** `encodeTimestampCalendar(Timestamp, Calendar)` was removed;
use `encodeLocalDateTime(LocalDateTime)`
** `decodeTimestampCalendar(byte[], Calendar)` was removed;
use `decodeLocalDateTime(byte[])`
** `encodeTimestampRaw(DatatypeCoder.RawDateTimeStruct)` was removed;
use `encodeLocalDateTime(LocalDateTime)`
** `decodeTimestampRaw(byte[])` was removed;
use `decodeLocalDateTime(byte[])`
** `encodeTime(Time, Calendar, boolean)` was removed;
there is no replacement
** `decodeTime(Time, Calendar, boolean)` was removed;
there is no replacement
** `encodeTimeCalendar(Time, Calendar)` was removed;
use `encodeLocalTime(LocalTime)`
** `decodeTimeCalendar(byte[], Calendar)` was removed;
use `decodeLocalTime(byte[])`
** `encodeTimeRaw(DatatypeCoder.RawDateTimeStruct)` was removed;
use `encodeLocalTime(LocalTime)`
** `decodeTimeRaw(byte[])` was removed;
use `decodeLocalTime(byte[])`
** `encodeDate(Date, Calendar)` was removed;
there is no replacement
** `decodeDate(Date, Calendar)` was removed;
there is no replacement
** `encodeDateCalendar(Date, Calendar)` was removed;
use `encodeLocalDate(LocalDate)`
** `decodeDateCalendar(byte[], Calendar)` was removed;
use `decodeLocalDate(byte[])`
** `encodeDateRaw(DatatypeCoder.RawDateTimeStruct)` was removed;
use `encodeLocalDate(LocalDate)`
** `decodeDateRaw(byte[])` was removed;
Expand Down
135 changes: 0 additions & 135 deletions src/main/org/firebirdsql/gds/ng/DatatypeCoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@
import java.io.Reader;
import java.io.Writer;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
Expand Down Expand Up @@ -259,138 +256,6 @@ public interface DatatypeCoder {
*/
Reader createReader(InputStream in);

/**
* Encode a {@code Timestamp} using a given {@code Calendar}.
*
* @param val
* value to be encoded
* @param c
* calendar to use for encoding, may be {@code null}
* @return encoded {@code Timestamp}, or {@code null} if {@code val} is {@code null}
*/
Timestamp encodeTimestamp(Timestamp val, Calendar c);

/**
* Encode a {@code Timestamp} as a byte array of 8 bytes.
*
* @param val
* value to be encoded
* @param c
* calendar to use for time zone calculation
* @return {@code val} encoded as a byte array, or {@code null} if {@code val} is {@code null}
*/
byte[] encodeTimestampCalendar(Timestamp val, Calendar c);

/**
* Decode a {@code Timestamp} value using a given {@code Calendar}.
*
* @param val
* value to be decoded
* @param c
* calendar to use in decoding, may be {@code null}
* @return encoded {@code Timestamp}, or {@code null} if {@code val} is {@code null}
*/
Timestamp decodeTimestamp(Timestamp val, Calendar c);

/**
* Decode a {@code Timestamp} from {@code buf} from the first 8 bytes.
*
* @param buf
* byte array of sufficient size
* @param c
* calendar to use for time zone calculation
* @return {@code Timestamp} decoded from {@code buf}, or {@code null} if {@code buf} is {@code null}
*/
Timestamp decodeTimestampCalendar(byte[] buf, Calendar c);

/**
* Encode a given {@code Time} value using a given {@code Calendar}.
*
* @param val
* value to be encoded
* @param c
* calendar to use in the encoding, may be {@code null}
* @return encoded {@code Time}, or {@code null} if {@code val} is {@code null}
*/
Time encodeTime(Time val, Calendar c);

/**
* Encode a {@code Time} value as a byte array of 4 bytes.
*
* @param val
* value to be encoded
* @param c
* calendar to use for time zone calculation
* @return {@code val} encoded as a byte array, or {@code null} if {@code val} is {@code null}
*/
byte[] encodeTimeCalendar(Time val, Calendar c);

/**
* Decode a {@code Time} value using a given {@code Calendar}.
*
* @param val
* value to be decoded
* @param c
* calendar to used in the decoding, may be {@code null}
* @return decoded {@code Time}, or {@code null} if {@code val} is {@code null}
*/
Time decodeTime(Time val, Calendar c);

/**
* Decode a {@code Time} value from {@code buf} from the first 4 bytes.
*
* @param buf
* byte array of sufficient size
* @param c
* calendar to use for time zone calculation
* @return {@code Time} decoded from {@code buf}, or {@code null} if {@code buf} is {@code null}
*/
Time decodeTimeCalendar(byte[] buf, Calendar c);

/**
* Encode a given {@code Date} value using a given {@code Calendar}.
*
* @param val
* value to be encoded
* @param c
* calendar to use in the encoding, may be {@code null}
* @return encoded {@code Date}, or {@code null} if {@code val} is {@code null}
*/
Date encodeDate(Date val, Calendar c);

/**
* Encode a {@code Date} value as a {@code byte} array of 4 bytes.
*
* @param val
* value to be encoded
* @param c
* calendar to use for time zone calculation
* @return {@code val} encoded as a byte array, or {@code null} if {@code val} is {@code null}
*/
byte[] encodeDateCalendar(Date val, Calendar c);

/**
* Decode a {@code Date} value using a given {@code Calendar}.
*
* @param val
* value to be decoded
* @param c
* calendar to use in the decoding, may be {@code null}
* @return decoded {@code Date}, or {@code null} if {@code val} is {@code null}
*/
Date decodeDate(Date val, Calendar c);

/**
* Decode a {@code Date} value from {@code buf} from the first 4 bytes.
*
* @param buf
* byte array of sufficient size
* @param c
* calendar to use for time zone calculation
* @return {@code Date} decoded from {@code buf}, or {@code null} if {@code buf} is {@code null}
*/
Date decodeDateCalendar(byte[] buf, Calendar c);

/**
* Decode a boolean from {@code buf} from the first byte.
*
Expand Down
Loading

0 comments on commit f19dc6e

Please sign in to comment.