private static int julianDateFloor()

in core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java [1006:1091]


  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);
    }
  }