Run Monthly Jobs on the 28th at Midnight | CronBase

cron expression Standard
$ 0 0 28 * *

At midnight on the twenty-eighth day of every month

The `0 0 28 * *` cron schedule executes a task exactly at midnight on the twenty-eighth day of every single month. This specific timing is highly reliable for monthly recurring billing, financial ledger reconciliation, and system report generation, as the twenty-eighth is guaranteed to exist in every month of the calendar year, including February.

Minute
0
Hour
0
Day of Month
28
Month
*
Day of Week
*

Next 5 Runs

  • in 16d 13h
  • in 46d 13h
  • in 77d 13h
  • in 107d 13h
  • in 138d 13h

* Tools

Code & Implementations

nodejs
const cron = require('node-cron');
const logger = require('./logger'); // Production logger abstraction

// Schedule task for 0 0 28 * * (Midnight on the 28th of every month)
cron.schedule('0 0 28 * *', async () => {
    logger.info('Starting monthly data archiving task...');
    try {
        await performMonthlyArchive();
        logger.info('Monthly data archiving completed successfully.');
    } catch (error) {
        logger.error('Failed to complete monthly archiving:', error);
        // Integrate notification hooks (e.g., Sentry, Slack, PagerDuty) here
    }
}, {
    scheduled: true,
    timezone: "UTC"
});

async function performMonthlyArchive() {
    // Simulate archive processing
    return new Promise((resolve) => setTimeout(resolve, 5000));
}
Setup notes

Install the required package with npm install node-cron and run this script as a daemon process using PM2 or a similar process manager.

Partner BetterStack

Monitor this schedule in production

Get alerted the moment this cron job fails, is late, or doesn't run. BetterStack tracks execution, duration, and output — no infrastructure required.

Platform Equivalents

AWS EventBridge

Standard cron expressions often need conversion for AWS EventBridge schedules.

EventBridge Rule
cron(0 0 28 * ? *)

Systemd Timer

OnCalendar*-*-28 00:00:00

my-task.timer
[Unit]
Description=Timer for cron expression: 0 0 28 * *

[Timer]
OnCalendar=*-*-28 00:00:00
Persistent=true

[Install]
WantedBy=timers.target

Frequently Asked Questions

Why is the 28th chosen instead of the 30th or 31st for monthly jobs?

The 28th is the highest day number that exists in every single month of the year, including February. Choosing the 30th or 31st would require complex custom logic to handle shorter months, making the 28th the safest choice for consistent monthly intervals.

How does Daylight Saving Time (DST) affect a midnight cron job?

If your server runs on local time, DST transitions can cause the midnight job to run twice or be skipped entirely. To prevent this, configure your cron daemon or application runtime to execute in Coordinated Universal Time (UTC).

What happens if the monthly job fails to run due to server downtime?

Standard cron has no built-in catch-up mechanism. You should use a tool like anacron, implement a state-based database flag to track execution, or use a scheduling framework with 'misfire' instructions to run missed executions upon recovery.

How can I prevent database connection timeouts during this heavy monthly run?

Introduce a random startup delay (jitter) of several minutes before the main execution logic begins. This staggers the initial database connections and prevents resource starvation, especially when multiple microservices trigger concurrent monthly tasks.

Can I restrict this monthly job to run only on weekdays?

Standard cron does not easily support '28th of the month AND only weekdays' in a single expression because day-of-month and day-of-week fields act as an OR relationship. You must handle this filter programmatically within your script or application code.

* Explore

Related expressions you might need

Was this helpful?

Last verified: