MaxGekk commented on a change in pull request #25336: [SPARK-28017][SQL]
Support additional levels of truncations by DATE_TRUNC/TRUNC
URL: https://github.com/apache/spark/pull/25336#discussion_r311631054
##########
File path:
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala
##########
@@ -617,91 +617,107 @@ object DateTimeUtils {
(date - localDate.getDayOfMonth) + localDate.lengthOfMonth()
}
- // Visible for testing.
- private[sql] val TRUNC_TO_YEAR = 1
- private[sql] val TRUNC_TO_MONTH = 2
- private[sql] val TRUNC_TO_QUARTER = 3
- private[sql] val TRUNC_TO_WEEK = 4
- private[sql] val TRUNC_TO_DAY = 5
- private[sql] val TRUNC_TO_HOUR = 6
- private[sql] val TRUNC_TO_MINUTE = 7
- private[sql] val TRUNC_TO_SECOND = 8
+ // The constants are visible for testing purpose only.
private[sql] val TRUNC_INVALID = -1
+ // The levels from TRUNC_TO_WEEK to TRUNC_TO_MILLENNIUM are used in
truncations
+ // of DATE and TIMESTAMP values.
+ private[sql] val TRUNC_TO_WEEK = 0
+ private[sql] val TRUNC_TO_MONTH = 1
+ private[sql] val TRUNC_TO_QUARTER = 2
+ private[sql] val TRUNC_TO_YEAR = 3
+ private[sql] val TRUNC_TO_DECADE = 4
+ private[sql] val TRUNC_TO_CENTURY = 5
+ private[sql] val TRUNC_TO_MILLENNIUM = 6
+ private[sql] val MAX_LEVEL_OF_DATE_TRUNC = TRUNC_TO_MILLENNIUM
+ // The levels from TRUNC_TO_MICROSECOND to TRUNC_TO_DAY are used in
truncations
+ // of TIMESTAMP values only.
+ private[sql] val TRUNC_TO_MICROSECOND = 7
+ private[sql] val TRUNC_TO_MILLISECOND = 8
+ private[sql] val TRUNC_TO_SECOND = 9
+ private[sql] val TRUNC_TO_MINUTE = 10
+ private[sql] val TRUNC_TO_HOUR = 11
+ private[sql] val TRUNC_TO_DAY = 12
+ private[sql] val MAX_LEVEL_OF_TIMESTAMP_TRUNC = TRUNC_TO_DAY
/**
* Returns the trunc date from original date and trunc level.
- * Trunc level should be generated using `parseTruncLevel()`, should only be
1 or 2.
+ * Trunc level should be generated using `parseTruncLevel()`, should be
between 0 and 6.
*/
def truncDate(d: SQLDate, level: Int): SQLDate = {
- if (level == TRUNC_TO_YEAR) {
- d - DateTimeUtils.getDayInYear(d) + 1
- } else if (level == TRUNC_TO_MONTH) {
- d - DateTimeUtils.getDayOfMonth(d) + 1
- } else {
- // caller make sure that this should never be reached
- sys.error(s"Invalid trunc level: $level")
+ def truncToYearLevel(divider: Int, adjust: Int): SQLDate = {
+ val oldYear = getYear(d)
+ var newYear = Math.floorDiv(oldYear, divider)
+ if (adjust > 0 && Math.floorMod(oldYear, divider) == 0) {
+ newYear -= 1
+ }
+ newYear = newYear * divider + adjust
+ localDateToDays(LocalDate.of(newYear, 1, 1))
+ }
+ level match {
+ case TRUNC_TO_WEEK => getNextDateForDayOfWeek(d - 7, MONDAY)
+ case TRUNC_TO_MONTH => d - DateTimeUtils.getDayOfMonth(d) + 1
+ case TRUNC_TO_QUARTER =>
+ localDateToDays(daysToLocalDate(d).`with`(IsoFields.DAY_OF_QUARTER,
1L))
Review comment:
I copied-pasted the existing implementation of quarter truncation but I
haven't found `getDayInQuarter` in `DateTimeUtils`.
----------------------------------------------------------------
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.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]