Datum plvdate_isbizday (PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int y, m, d; holiday_desc hd; if (0 != ((1 << j2day(day+POSTGRES_EPOCH_JDATE)) & nonbizdays)) return false; if (NULL != bsearch(&day, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) return false; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d); hd.month = m; hd.day = d; if (use_easter && (m == 3 || m == 4)) { easter_sunday(y, &d, &m); if (m == hd.month && (d == hd.day || d+1 == hd.day)) return false; } PG_RETURN_BOOL (NULL == bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)); }
static int ora_diff_bizdays(DateADT day1, DateADT day2) { int d, days; int y, m, auxd; holiday_desc hd; int cycle_c = 0; bool start_is_bizday = false; DateADT aux_day; if (day1 > day2) { aux_day = day1; day1 = day2; day2 = aux_day; } d = j2day(day1+POSTGRES_EPOCH_JDATE); days = 0; while (day1 <= day2) { ++ cycle_c; d = (d+1) % 7; d = (d < 0) ? 6:d; day1 += 1; if ((1 << d) & nonbizdays) continue; if (NULL != bsearch(&day1, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) continue; j2date(day1 + POSTGRES_EPOCH_JDATE, &y, &m, &auxd); hd.day = (char) auxd; hd.month = (char) m; if (use_easter && (m == 3 || m == 4)) { easter_sunday(y, &auxd, &m); if (m == hd.month && (auxd == hd.day || d+1 == hd.day)) continue; } if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) continue; days += 1; if (cycle_c == 1) start_is_bizday = true; } if (include_start && start_is_bizday && days >= 1) days -= 1; return days; }
Datum next_day(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *day_txt = PG_GETARG_TEXT_PP(1); const char *str = VARDATA_ANY(day_txt); int len = VARSIZE_ANY_EXHDR(day_txt); int off; int d = -1; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY /* Check mru_weekdays first for performance. */ if (mru_weekdays) { if ((d = weekday_search(mru_weekdays, str, len)) >= 0) goto found; else mru_weekdays = NULL; } #endif /* * Oracle uses only 3 heading characters of the input. * Ignore all trailing characters. */ if (len >= 3 && (d = ora_seq_prefix_search(str, ora_days, 3)) >= 0) goto found; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY do { int i; int encoding = GetDatabaseEncoding(); for (i = 0; i < lengthof(WEEKDAYS); i++) { if (encoding == WEEKDAYS[i].encoding) { if ((d = weekday_search(&WEEKDAYS[i], str, len)) >= 0) { mru_weekdays = &WEEKDAYS[i]; goto found; } } } } while(0); #endif CHECK_SEQ_SEARCH(-1, "DAY/Day/day"); found: off = d - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); }
/* next_day(date, integer) is not documented in Oracle manual, but ... */ Datum next_day_by_index(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int idx = PG_GETARG_INT32(1); int off; /* * off is 1..7 (Sun..Sat). * * TODO: It should be affected by NLS_TERRITORY. For example, * 1..7 should be interpreted as Mon..Sun in GERMAN. */ CHECK_SEQ_SEARCH((idx < 1 || 7 < idx) ? -1 : 0, "DAY/Day/day"); /* j2day returns 0..6 as Sun..Sat */ off = (idx - 1) - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); }
static DateADT ora_add_bizdays(DateADT day, int days) { int d, dx; int y, m, auxd; holiday_desc hd; d = j2day(day+POSTGRES_EPOCH_JDATE); dx = days > 0? 1 : -1; while (days != 0) { d = (d+dx) % 7; d = (d < 0) ? 6:d; day += dx; if ((1 << d) & nonbizdays) continue; if (NULL != bsearch(&day, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) continue; j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &auxd); hd.day = (char) auxd; hd.month = (char) m; if (use_easter && (m == 3 || m == 4)) { easter_sunday(y, &auxd, &m); if (m == hd.month && (auxd == hd.day || d+1 == hd.day)) continue; } if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) continue; days -= dx; } return day; }
static int ora_diff_bizdays(DateADT day1, DateADT day2) { int d, days; int y, m, auxd; holiday_desc hd; int loops = 0; bool start_is_bizday = false; DateADT aux_day; if (day1 > day2) { aux_day = day1; day1 = day2; day2 = aux_day; } /* d is incremented on start of cycle, so now I have to decrease one */ d = j2day(day1+POSTGRES_EPOCH_JDATE-1); days = 0; while (day1 <= day2) { loops++; day1 += 1; d = (d+1) % 7; if ((1 << d) & nonbizdays) continue; if (NULL != bsearch(&day1, exceptions, exceptions_c, sizeof(DateADT), dateadt_comp)) continue; j2date(day1 + POSTGRES_EPOCH_JDATE, &y, &m, &auxd); hd.day = (char) auxd; hd.month = (char) m; if (easter_holidays(day1, y, m)) continue; if (NULL != bsearch(&hd, holidays, holidays_c, sizeof(holiday_desc), holiday_desc_comp)) continue; /* now the day have to be bizday, remember if first day was bizday */ if (loops == 1) start_is_bizday = true; days += 1; } /* * decrease result when first day was bizday, but we don't want * calculate first day. */ if ( start_is_bizday && !include_start && days > 0) days -= 1; return days; }