in core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java [1040:1125]
private static int julianDateFloor(TimeUnitRange range, int julian,
boolean floor) {
// this shifts the epoch back to astronomical year -4800 instead of the
// start of the Christian era in year AD 1 of the proleptic Gregorian
// calendar.
int j = julian + 32044;
int g = j / 146097;
int dg = j % 146097;
int c = (dg / 36524 + 1) * 3 / 4;
int dc = dg - c * 36524;
int b = dc / 1461;
int db = dc % 1461;
int a = (db / 365 + 1) * 3 / 4;
int da = db - a * 365;
// integer number of full years elapsed since March 1, 4801 BC
int y = g * 400 + c * 100 + b * 4 + a;
// integer number of full months elapsed since the last March 1
int m = (da * 5 + 308) / 153 - 2;
// number of days elapsed since day 1 of the month
int d = da - (m + 4) * 153 / 5 + 122;
int year = y - 4800 + (m + 2) / 12;
int month = (m + 2) % 12 + 1;
int day = d + 1;
switch (range) {
case MILLENNIUM:
return floor
? ymdToUnixDate(1000 * ((year + 999) / 1000) - 999, 1, 1)
: ymdToUnixDate(1000 * ((year + 999) / 1000) + 1, 1, 1);
case CENTURY:
return floor
? ymdToUnixDate(100 * ((year + 99) / 100) - 99, 1, 1)
: ymdToUnixDate(100 * ((year + 99) / 100) + 1, 1, 1);
case DECADE:
return floor
? ymdToUnixDate(10 * (year / 10), 1, 1)
: ymdToUnixDate(10 * (1 + year / 10), 1, 1);
case YEAR:
if (!floor && (month > 1 || day > 1)) {
++year;
}
return ymdToUnixDate(year, 1, 1);
case ISOYEAR:
final int isoWeek = getIso8601WeekNumber(julian, year, month, day);
final int dowMon = Math.floorMod(julian, 7); // mon=0, sun=6
final int isoYearFloor = julian - 7 * (isoWeek - 1) - dowMon;
if (floor || isoYearFloor == julian) {
return isoYearFloor - EPOCH_JULIAN;
} else {
// CEIL of this date is the FLOOR of the date 53 weeks later.
// (Usually 52 weeks later, sometimes 53 weeks later.)
return julianDateFloor(range, isoYearFloor + 7 * 53, true);
}
case QUARTER:
final int q = (month - 1) / 3;
if (!floor) {
if (month - 1 > q * 3 || day > 1) {
if (q == 3) {
++year;
month = 1;
} else {
month = q * 3 + 4;
}
}
} else {
month = q * 3 + 1;
}
return ymdToUnixDate(year, month, 1);
case MONTH:
if (!floor && day > 1) {
++month;
}
return ymdToUnixDate(year, month, 1);
case WEEK:
final int dow = Math.floorMod(julian + 1, 7); // sun=0, sat=6
int offset = dow;
if (!floor && offset > 0) {
offset -= 7;
}
return ymdToUnixDate(year, month, day) - offset;
case DAY:
return ymdToUnixDate(year, month, day);
default:
throw new AssertionError(range);
}
}