From d30856980076080b1e3b0a0147fbeb3dfa555350 Mon Sep 17 00:00:00 2001 From: Vedran Djakovic Date: Wed, 4 Mar 2026 14:43:19 +0100 Subject: [PATCH] feat: Add cron.dom_dow_and_logic parameter to control days logic Currently, pg_cron follows the Vixie cron standard where a configured day-of-month (DOM) and day-of-week (DOW) are combined with OR logic. This makes it impossible to schedule jobs that must satisfy both a day-of-month and a day-of-week configuration. A common use case is scheduling a job to run on the "first Sunday of every month." With the default OR logic, an expression like '0 5 1-7 * 0' would run at 5:00 AM on days 1 through 7 of the month AND on every Sunday of the month. Which does not have much practical value. This commit introduces a new parameter, `cron.dom_dow_and_logic`, to give users control over this behavior. When set to `true`, pg_cron will use AND logic when both DOM and DOW fields are configured. With this feature enabled, the expression '0 5 1-7 * 0' runs only on the day that is both within the first 7 days of the month AND is a Sunday. --- src/pg_cron.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pg_cron.c b/src/pg_cron.c index 0426071..430a34c 100644 --- a/src/pg_cron.c +++ b/src/pg_cron.c @@ -157,6 +157,7 @@ static void bgw_generate_returned_message(StringInfoData *display_msg, ErrorData char *CronTableDatabaseName = "postgres"; static bool CronLogStatement = true; static bool CronLogRun = true; +static bool CronDomDowAndLogic = false; /* global variables */ static int CronTaskStartTimeout = 10000; /* maximum connection time */ @@ -327,6 +328,16 @@ _PG_init(void) GUC_SUPERUSER_ONLY, check_timezone, NULL, NULL); + DefineCustomBoolVariable( + "cron.dom_dow_and_logic", + gettext_noop("Use AND logic for day-of-month and day-of-week."), + NULL, + &CronDomDowAndLogic, + false, + PGC_SIGHUP, + GUC_SUPERUSER_ONLY, + NULL, NULL, NULL); + /* set up common data for all our workers */ worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; worker.bgw_start_time = BgWorkerStart_RecoveryFinished; @@ -952,7 +963,7 @@ ShouldRunTask(entry *schedule, TimestampTz currentTime, bool doWild, if (bit_test(schedule->minute, minute) && bit_test(schedule->hour, hour) && bit_test(schedule->month, month) && - ((schedule->flags & (DOM_STAR | DOW_STAR)) != 0 + ((CronDomDowAndLogic || (schedule->flags & (DOM_STAR | DOW_STAR)) != 0) ? (thisdom && thisdow) : (thisdom || thisdow))) {