-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-29486][SQL] CalendarInterval should have 3 fields: months, days and microseconds #26134
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
Changes from 7 commits
44d66d6
4979e1e
f09b529
0db5b7a
ce879c2
4ee8354
3d954d6
05042e8
4c31401
064be74
211543f
0778f9a
3a6518a
4d8383c
1ac157e
aac92bd
076ce42
3d62a24
2edd8a0
4e97bc0
0e87e2d
2f90189
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,14 +111,13 @@ public static CalendarInterval fromCaseInsensitiveString(String s) { | |
| } | ||
|
|
||
| long months = toLong(m.group(1)) * 12 + toLong(m.group(2)); | ||
| long microseconds = toLong(m.group(3)) * MICROS_PER_WEEK; | ||
| microseconds += toLong(m.group(4)) * MICROS_PER_DAY; | ||
| microseconds += toLong(m.group(5)) * MICROS_PER_HOUR; | ||
| long days = toLong(m.group(3)) * 7 + toLong(m.group(4)); | ||
| long microseconds = toLong(m.group(5)) * MICROS_PER_HOUR; | ||
| microseconds += toLong(m.group(6)) * MICROS_PER_MINUTE; | ||
| microseconds += toLong(m.group(7)) * MICROS_PER_SECOND; | ||
| microseconds += toLong(m.group(8)) * MICROS_PER_MILLI; | ||
| microseconds += toLong(m.group(9)); | ||
| return new CalendarInterval((int) months, microseconds); | ||
| return new CalendarInterval((int) months, (int) days, microseconds); | ||
| } | ||
|
|
||
| public static long toLongWithRange(String fieldName, | ||
|
|
@@ -154,7 +153,7 @@ public static CalendarInterval fromYearMonthString(String s) throws IllegalArgum | |
| int sign = m.group(1) != null && m.group(1).equals("-") ? -1 : 1; | ||
| int years = (int) toLongWithRange("year", m.group(2), 0, Integer.MAX_VALUE); | ||
| int months = (int) toLongWithRange("month", m.group(3), 0, 11); | ||
| result = new CalendarInterval(sign * (years * 12 + months), 0); | ||
| result = new CalendarInterval(sign * (years * 12 + months), 0, 0); | ||
| } catch (Exception e) { | ||
| throw new IllegalArgumentException( | ||
| "Error parsing interval year-month string: " + e.getMessage(), e); | ||
|
|
@@ -195,7 +194,7 @@ public static CalendarInterval fromDayTimeString(String s, String from, String t | |
| } else { | ||
| try { | ||
| int sign = m.group(1) != null && m.group(1).equals("-") ? -1 : 1; | ||
| long days = m.group(2) == null ? 0 : toLongWithRange("day", m.group(3), | ||
| int days = m.group(2) == null ? 0 : (int) toLongWithRange("day", m.group(3), | ||
|
||
| 0, Integer.MAX_VALUE); | ||
| long hours = 0; | ||
| long minutes; | ||
|
|
@@ -231,8 +230,8 @@ public static CalendarInterval fromDayTimeString(String s, String from, String t | |
| throw new IllegalArgumentException( | ||
| String.format("Cannot support (interval '%s' %s to %s) expression", s, from, to)); | ||
| } | ||
| result = new CalendarInterval(0, sign * ( | ||
| days * MICROS_PER_DAY + hours * MICROS_PER_HOUR + minutes * MICROS_PER_MINUTE + | ||
| result = new CalendarInterval(0, sign * days, sign * ( | ||
| hours * MICROS_PER_HOUR + minutes * MICROS_PER_MINUTE + | ||
| seconds * MICROS_PER_SECOND + nanos / 1000L)); | ||
| } catch (Exception e) { | ||
| throw new IllegalArgumentException( | ||
|
|
@@ -260,46 +259,46 @@ public static CalendarInterval fromSingleUnitString(String unit, String s) | |
| case "year": | ||
| int year = (int) toLongWithRange("year", m.group(1), | ||
| Integer.MIN_VALUE / 12, Integer.MAX_VALUE / 12); | ||
| result = new CalendarInterval(year * 12, 0L); | ||
| result = new CalendarInterval(year * 12, 0, 0L); | ||
| break; | ||
| case "month": | ||
| int month = (int) toLongWithRange("month", m.group(1), | ||
| Integer.MIN_VALUE, Integer.MAX_VALUE); | ||
| result = new CalendarInterval(month, 0L); | ||
| result = new CalendarInterval(month, 0, 0L); | ||
| break; | ||
| case "week": | ||
| long week = toLongWithRange("week", m.group(1), | ||
| Long.MIN_VALUE / MICROS_PER_WEEK, Long.MAX_VALUE / MICROS_PER_WEEK); | ||
| result = new CalendarInterval(0, week * MICROS_PER_WEEK); | ||
| int week = (int) toLongWithRange("week", m.group(1), | ||
| Integer.MIN_VALUE / 7, Integer.MAX_VALUE / 7); | ||
| result = new CalendarInterval(0, week * 7, 0L); | ||
| break; | ||
| case "day": | ||
| long day = toLongWithRange("day", m.group(1), | ||
| Long.MIN_VALUE / MICROS_PER_DAY, Long.MAX_VALUE / MICROS_PER_DAY); | ||
| result = new CalendarInterval(0, day * MICROS_PER_DAY); | ||
| int day = (int) toLongWithRange("day", m.group(1), | ||
| Integer.MIN_VALUE, Integer.MAX_VALUE); | ||
| result = new CalendarInterval(0, day, 0L); | ||
| break; | ||
| case "hour": | ||
| long hour = toLongWithRange("hour", m.group(1), | ||
| Long.MIN_VALUE / MICROS_PER_HOUR, Long.MAX_VALUE / MICROS_PER_HOUR); | ||
| result = new CalendarInterval(0, hour * MICROS_PER_HOUR); | ||
| result = new CalendarInterval(0, 0, hour * MICROS_PER_HOUR); | ||
| break; | ||
| case "minute": | ||
| long minute = toLongWithRange("minute", m.group(1), | ||
| Long.MIN_VALUE / MICROS_PER_MINUTE, Long.MAX_VALUE / MICROS_PER_MINUTE); | ||
| result = new CalendarInterval(0, minute * MICROS_PER_MINUTE); | ||
| result = new CalendarInterval(0, 0, minute * MICROS_PER_MINUTE); | ||
| break; | ||
| case "second": { | ||
| long micros = parseSecondNano(m.group(1)); | ||
| result = new CalendarInterval(0, micros); | ||
| result = new CalendarInterval(0, 0, micros); | ||
| break; | ||
| } | ||
| case "millisecond": | ||
| long millisecond = toLongWithRange("millisecond", m.group(1), | ||
| Long.MIN_VALUE / MICROS_PER_MILLI, Long.MAX_VALUE / MICROS_PER_MILLI); | ||
| result = new CalendarInterval(0, millisecond * MICROS_PER_MILLI); | ||
| result = new CalendarInterval(0, 0, millisecond * MICROS_PER_MILLI); | ||
| break; | ||
| case "microsecond": { | ||
| long micros = Long.parseLong(m.group(1)); | ||
| result = new CalendarInterval(0, micros); | ||
| result = new CalendarInterval(0, 0, micros); | ||
| break; | ||
| } | ||
| } | ||
|
|
@@ -332,31 +331,35 @@ public static long parseSecondNano(String secondNano) throws IllegalArgumentExce | |
| } | ||
|
|
||
| public final int months; | ||
| public final int days; | ||
| public final long microseconds; | ||
|
|
||
| public long milliseconds() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method will return different values because you exclude days from microseconds |
||
| return this.microseconds / MICROS_PER_MILLI; | ||
| } | ||
|
|
||
| public CalendarInterval(int months, long microseconds) { | ||
| public CalendarInterval(int months, int days, long microseconds) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @LinhongLiu Could you send out a follow up PR to document why we need
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sure, will do. |
||
| this.months = months; | ||
| this.days = days; | ||
| this.microseconds = microseconds; | ||
| } | ||
|
|
||
| public CalendarInterval add(CalendarInterval that) { | ||
| int months = this.months + that.months; | ||
| int days = this.days + that.days; | ||
| long microseconds = this.microseconds + that.microseconds; | ||
| return new CalendarInterval(months, microseconds); | ||
| return new CalendarInterval(months, days, microseconds); | ||
| } | ||
|
|
||
| public CalendarInterval subtract(CalendarInterval that) { | ||
| int months = this.months - that.months; | ||
| int days = this.days - that.days; | ||
| long microseconds = this.microseconds - that.microseconds; | ||
| return new CalendarInterval(months, microseconds); | ||
| return new CalendarInterval(months, days, microseconds); | ||
| } | ||
|
|
||
| public CalendarInterval negate() { | ||
| return new CalendarInterval(-this.months, -this.microseconds); | ||
| return new CalendarInterval(-this.months, -this.days, -this.microseconds); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -365,12 +368,12 @@ public boolean equals(Object other) { | |
| if (other == null || !(other instanceof CalendarInterval)) return false; | ||
|
|
||
| CalendarInterval o = (CalendarInterval) other; | ||
| return this.months == o.months && this.microseconds == o.microseconds; | ||
| return this.months == o.months && this.days == o.days && this.microseconds == o.microseconds; | ||
|
||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return 31 * months + (int) microseconds; | ||
| return 31 * (31 * months + days) + (int) microseconds; | ||
|
||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -382,12 +385,13 @@ public String toString() { | |
| appendUnit(sb, months % 12, "month"); | ||
| } | ||
|
|
||
| if (days != 0) { | ||
| appendUnit(sb, days / 7, "week"); | ||
| appendUnit(sb, days % 7, "day"); | ||
| } | ||
|
|
||
| if (microseconds != 0) { | ||
| long rest = microseconds; | ||
| appendUnit(sb, rest / MICROS_PER_WEEK, "week"); | ||
| rest %= MICROS_PER_WEEK; | ||
| appendUnit(sb, rest / MICROS_PER_DAY, "day"); | ||
| rest %= MICROS_PER_DAY; | ||
| appendUnit(sb, rest / MICROS_PER_HOUR, "hour"); | ||
| rest %= MICROS_PER_HOUR; | ||
| appendUnit(sb, rest / MICROS_PER_MINUTE, "minute"); | ||
|
|
@@ -397,7 +401,7 @@ public String toString() { | |
| appendUnit(sb, rest / MICROS_PER_MILLI, "millisecond"); | ||
| rest %= MICROS_PER_MILLI; | ||
| appendUnit(sb, rest, "microsecond"); | ||
| } else if (months == 0) { | ||
| } else if (months == 0 && days == 0) { | ||
| sb.append(" 0 microseconds"); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to catch int overflow by
Math.toIntExactinstead of silently ignore it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe we can change this to long
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid range of dates/timestamps is [0..10000). So, we should support days up to
10000 * 366 = 3660000. Evenintis so much but it is ok.