Run on the 1st and 15th of Every Month | CronBase
0 0 1,15 * * At midnight on the first and fifteenth day of every month
The `0 0 1,15 * *` cron expression schedules a task to execute at exactly midnight (12:00 AM) on the first and fifteenth days of every month. This semi-monthly cadence is commonly used for processing payroll, generating bi-weekly financial statements, executing recurring billing cycles, and performing mid-month data archival tasks.
- Minute
- 0
- Hour
- 0
- Day of Month
- 1,15
- Month
- *
- Day of Week
- *
Next 5 Runs
- in 6d 3h
- in 20d 3h
- in 37d 3h
- in 51d 3h
- in 67d 3h
* Tools
Code & Implementations
# Add this line to your crontab using the 'crontab -e' command\n0 0 1,15 * * /usr/local/bin/run-biweekly-billing.sh >> /var/log/billing.log 2>&1 › Setup notes
Open your user crontab editor using bash, paste this line at the bottom, and ensure the target execution script is marked as executable.
const cron = require('node-cron');\nconst { exec } = require('child_process');\n\n// Schedule task to run on the 1st and 15th of the month at midnight UTC\ncron.schedule('0 0 1,15 * *', () => {\n console.log('Starting semi-monthly processing job...');\n exec('/usr/local/bin/process-payroll.sh', (error, stdout, stderr) => {\n if (error) {\n console.error(`Execution error: ${error.message}`);\n return;\n }\n if (stderr) {\n console.warn(`Warnings: ${stderr}`);\n }\n console.log(`Output: ${stdout}`);\n });\n}, {\n scheduled: true,\n timezone: \"UTC\"\n}); › Setup notes
Install node-cron package via npm, then run this script as a background daemon process using PM2 or systemd.
from apscheduler.schedulers.blocking import BlockingScheduler\nimport logging\nimport subprocess\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\ndef run_biweekly_task():\n logger.info(\"Executing scheduled bi-weekly task\")\n try:\n result = subprocess.run([\"/usr/local/bin/backup-db.sh\"], capture_output=True, text=True, check=True)\n logger.info(f\"Task completed: {result.stdout}\")\n except subprocess.CalledProcessError as e:\n logger.error(f\"Task failed with error: {e.stderr}\")\n\nscheduler = BlockingScheduler(timezone=\"UTC\")\n# Trigger on the 1st and 15th day of every month at midnight\nscheduler.add_job(run_biweekly_task, 'cron', day='1,15', hour=0, minute=0)\n\ntry:\n scheduler.start()\nexcept (KeyboardInterrupt, SystemExit):\n pass › Setup notes
Install the apscheduler library using pip, then execute this script to begin the scheduling loop.
package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os/exec\"\n\t\"time\"\n\n\t\"github.com/robfig/cron/v3\"\n)\n\nfunc main() {\n\t// Use UTC to avoid DST complications\n\tnyc, err := time.LoadLocation(\"UTC\")\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to load timezone: %v\", err)\n\t}\n\n\tc := cron.New(cron.WithLocation(nyc))\n\t\n\t_, err = c.AddFunc(\"0 0 1,15 * *\", func() {\n\t\tlog.Println(\"Starting semi-monthly database cleanup...\")\n\t\tcmd := exec.Command(\"/usr/local/bin/cleanup.sh\")\n\t\tout, err := cmd.CombinedOutput()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Execution failed: %v, Output: %s\", err, string(out))\n\t\t\treturn\n\t\t}\n\t\tlog.Printf(\"Execution succeeded: %s\", string(out))\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to schedule cron job: %v\", err)\n\t}\n\n\tc.Start()\n\tselect {}\n} › Setup notes
Initialize a Go module, import the robfig/cron/v3 package, and run the main function to handle scheduling natively.
package com.example.cron;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SemiMonthlyScheduler {\n private static final Logger logger = LoggerFactory.getLogger(SemiMonthlyScheduler.class);\n\n // Standard Spring cron: second, minute, hour, day-of-month, month, day-of-week\n @Scheduled(cron = \"0 0 0 1,15 *\", zone = \"UTC\")\n public void executeSemiMonthlyJob() {\n logger.info(\"Starting scheduled semi-monthly ledger reconciliation...\");\n try {\n // Business logic goes here\n logger.info(\"Ledger reconciliation completed successfully.\");\n } catch (Exception e) {\n logger.error(\"Error executing ledger reconciliation: \", e);\n }\n }\n} › Setup notes
Enable scheduling in your Spring Boot main application class using @EnableScheduling, then add this component to your codebase.
apiVersion: batch/v1\nkind: CronJob\nmetadata:\n name: semi-monthly-billing-job\n namespace: default\nspec:\n schedule: \"0 0 1,15 * *\"\n concurrencyPolicy: Forbid\n successfulJobsHistoryLimit: 3\n failedJobsHistoryLimit: 5\n jobTemplate:\n spec:\n template:\n spec:\n containers:\n - name: billing-executor\n image: billing-service:latest\n command: [\"/bin/sh\", \"-c\", \"/app/run-billing.sh\"]\n restartPolicy: OnFailure › Setup notes
Save this manifest to a YAML file and apply it using 'kubectl apply -f manifest.yaml' to provision the CronJob in your cluster.
Last verified:
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.
cron(0 0 1,15 * ? *) Systemd Timer
OnCalendar*-*-01,15 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 1,15 * *
[Timer]
OnCalendar=*-*-01,15 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How can I handle timezone changes for a twice-monthly cron job?
To prevent Daylight Saving Time (DST) shifts from causing duplicate runs or missed executions, configure your cron runner or host server to operate entirely in UTC. This ensures execution occurs at the exact same physical interval regardless of seasonal clock changes.
What happens if the server is offline during the scheduled execution time?
Standard cron does not catch up on missed executions. If your server is offline at midnight on the 1st or 15th, the job will not run until the next scheduled date. For critical tasks, use a tool like anacron or implement a startup check that detects missed runs.
How can I test this cron schedule without waiting for the 1st or 15th?
You can simulate the execution by temporarily modifying the cron expression to run in the next few minutes (e.g., `*/5 * * * *`) or by manually triggering the underlying script or Kubernetes CronJob using `kubectl create job --from=cronjob/my-job`.
Can I schedule this job to run only on weekdays if the 1st or 15th falls on a weekend?
Standard cron cannot natively combine day-of-month and day-of-week with an 'AND' condition; it treats them as 'OR'. To achieve this, you must run the cron job on the 1st and 15th, and then use an inline shell script check like `[ $(date +%u) -le 5 ]` to exit early on weekends.
Why is running a resource-heavy database backup at midnight on these days risky?
Midnight is a highly contested slot where many default system maintenance tasks, log rotations, and automated backups trigger simultaneously. This causes resource contention. Shifting your schedule to an off-peak time like 02:15 AM reduces CPU and disk I/O bottlenecks.
* Explore
Related expressions you might need
Last verified: