snuyanzin commented on code in PR #29690:
URL: https://github.com/apache/flink/pull/29690#discussion_r4452565103
##########
flink-table/flink-table-common/src/main/java/org/apache/flink/table/data/utils/VariantCastUtils.java:
##########
@@ -240,42 +256,107 @@ private static String decimalTarget(int precision, int
scale) {
}
/**
- * Reads a timestamp variant as the target {@code TIMESTAMP}. {@link
Variant#getDateTime()}
- * accepts both the microsecond ({@link Variant.Type#TIMESTAMP}) and
nanosecond ({@link
- * Variant.Type#TIMESTAMP_NS}) encodings. Fractional seconds beyond the
target precision are
- * truncated, the same as a regular {@code TIMESTAMP} to {@code
TIMESTAMP(p)} cast.
+ * Reads a timestamp variant as the target {@code TIMESTAMP}. A {@code
TIMESTAMP_LTZ} value is
+ * shifted into the session time zone, the same as a regular {@code
TIMESTAMP_LTZ} to {@code
+ * TIMESTAMP} cast. Fractional seconds beyond the target precision are
truncated.
*/
- public static TimestampData toTimestamp(Variant variant, int precision) {
- final Variant.Type type = variant.getType();
- if (type == Variant.Type.TIMESTAMP || type ==
Variant.Type.TIMESTAMP_NS) {
- return DateTimeUtils.truncate(
- TimestampData.fromLocalDateTime(variant.getDateTime()),
precision);
+ public static TimestampData toTimestamp(Variant variant, int precision,
ZoneId sessionZone) {
+ final LocalDateTime dateTime = toLocalDateTime(variant, sessionZone);
+ if (dateTime == null) {
+ throw unsupportedKind(variant, String.format("TIMESTAMP(%d)",
precision));
}
- throw unsupportedKind(variant, String.format("TIMESTAMP(%d)",
precision));
+ return TimestampData.fromLocalDateTime(
+ dateTime.withNano(truncateNanos(dateTime.getNano(),
precision)));
}
- /** Reads a timestamp with local time zone variant. See {@link
#toTimestamp(Variant, int)}. */
- public static TimestampData toTimestampLtz(Variant variant, int precision)
{
- final Variant.Type type = variant.getType();
- if (type == Variant.Type.TIMESTAMP_LTZ || type ==
Variant.Type.TIMESTAMP_LTZ_NS) {
- return DateTimeUtils.truncate(
- TimestampData.fromInstant(variant.getInstant()),
precision);
+ /**
+ * Reads a timestamp variant as the target {@code TIMESTAMP_LTZ}. A {@code
TIMESTAMP} value is
+ * read as a wall-clock time in the session time zone, the same as a
regular {@code TIMESTAMP}
+ * to {@code TIMESTAMP_LTZ} cast. Fractional seconds beyond the target
precision are truncated.
+ */
+ public static TimestampData toTimestampLtz(Variant variant, int precision,
ZoneId sessionZone) {
+ final Instant instant;
+ switch (variant.getType()) {
+ case TIMESTAMP_LTZ:
+ case TIMESTAMP_LTZ_NS:
+ instant = variant.getInstant();
+ break;
+ case TIMESTAMP:
+ case TIMESTAMP_NS:
+ instant =
variant.getDateTime().atZone(sessionZone).toInstant();
+ break;
+ default:
+ throw unsupportedKind(variant,
String.format("TIMESTAMP_LTZ(%d)", precision));
}
- throw unsupportedKind(variant, String.format("TIMESTAMP_LTZ(%d)",
precision));
+ return TimestampData.fromInstant(
+ Instant.ofEpochSecond(
+ instant.getEpochSecond(),
truncateNanos(instant.getNano(), precision)));
}
/**
- * Reads a time variant as the target {@code TIME}. The runtime TIME
representation is
- * millisecond-of-day, so a variant's microseconds are dropped and any
fractional seconds beyond
- * the target precision are then truncated, the same as a regular {@code
TIME} to {@code
- * TIME(p)} cast.
+ * Reads a date or timestamp variant as the target {@code DATE}, in days
since the epoch. A
+ * timestamp keeps its date, read in the session time zone for a {@code
TIMESTAMP_LTZ}.
*/
- public static int toTime(Variant variant, int precision) {
+ public static int toDate(Variant variant, ZoneId sessionZone) {
+ if (variant.getType() == Variant.Type.DATE) {
+ return (int) variant.getDate().toEpochDay();
+ }
+ final LocalDateTime dateTime = toLocalDateTime(variant, sessionZone);
+ if (dateTime == null) {
+ throw unsupportedKind(variant, "DATE");
+ }
+ return (int) dateTime.toLocalDate().toEpochDay();
+ }
+
+ /**
+ * Reads a time or timestamp variant as the target {@code TIME}. A
timestamp keeps its time of
+ * day, read in the session time zone for a {@code TIMESTAMP_LTZ}. The
runtime TIME
+ * representation is millisecond-of-day, so a variant's microseconds are
dropped and any
+ * fractional seconds beyond the target precision are then truncated, the
same as a regular
+ * {@code TIME} to {@code TIME(p)} cast.
+ */
+ public static int toTime(Variant variant, int precision, ZoneId
sessionZone) {
+ final LocalTime time;
if (variant.getType() == Variant.Type.TIME) {
- return DateTimeUtils.applyTimePrecisionTruncation(
- DateTimeUtils.toInternal(variant.getTime()), precision);
+ time = variant.getTime();
+ } else {
+ final LocalDateTime dateTime = toLocalDateTime(variant,
sessionZone);
+ if (dateTime == null) {
+ throw unsupportedKind(variant, String.format("TIME(%d)",
precision));
+ }
+ time = dateTime.toLocalTime();
}
- throw unsupportedKind(variant, String.format("TIME(%d)", precision));
+ return DateTimeUtils.applyTimePrecisionTruncation(
+ DateTimeUtils.toInternal(time), precision);
+ }
+
+ /**
+ * Reads a timestamp variant as a wall-clock time, shifting a {@code
TIMESTAMP_LTZ} into the
+ * session time zone. Returns {@code null} for any other kind, so that the
caller builds the
+ * error message only when the cast fails.
+ */
+ private static @Nullable LocalDateTime toLocalDateTime(Variant variant,
ZoneId sessionZone) {
+ switch (variant.getType()) {
+ case TIMESTAMP:
+ case TIMESTAMP_NS:
+ return variant.getDateTime();
+ case TIMESTAMP_LTZ:
+ case TIMESTAMP_LTZ_NS:
+ return LocalDateTime.ofInstant(variant.getInstant(),
sessionZone);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Zeroes the fractional-second digits beyond the precision. A java.time
nano-of-second is never
+ * negative, so this also truncates toward the past before 1970, unlike
dividing an epoch
+ * millisecond.
+ */
+ private static int truncateNanos(int nanoOfSecond, int precision) {
+ return precision >= TIMESTAMP_NANOS_PRECISION
+ ? nanoOfSecond
+ : nanoOfSecond - nanoOfSecond % NANOS_PER_DIGIT[precision];
Review Comment:
It seems to be different from DateTimeUtils.truncate, is it intended?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]