Run Bi-Annual Tasks on Jan 1 and Jul 1 | CronBase
0 0 1 1,7 * At midnight on the opening day of January and July.
This cron expression schedules a job to run twice a year at midnight on the first day of January and July. It is commonly used for bi-annual maintenance, semi-annual financial reporting, long-term database archiving, and compliance auditing tasks that only need execution every six months.
- Minute
- 0
- Hour
- 0
- Day of Month
- 1
- Month
- 1,7
- Day of Week
- *
Next 5 Runs
- in 159d 3h
- in 340d 3h
- in 524d 3h
- in 706d 3h
- in 890d 3h
* Tools
Code & Implementations
#!/usr/bin/env bash
# Production-grade script to register the bi-annual cron job
# and execute a backup/cleanup task safely with logging.
set -euo pipefail
LOG_FILE="/var/log/biannual-job.log"
exec >> "$LOG_FILE" 2>&1
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Starting bi-annual maintenance task..."
# Real-world task: Rotate long-term archives
if tar -czf /backups/archive-$(date +%Y-%m).tar.gz /data/audit; then
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Task completed successfully."
else
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] ERROR: Task failed." >&2
exit 1
fi › Setup notes
Add this script to the system crontab using crontab -e with the line 0 0 1 1,7 * /path/to/script.sh to ensure it executes at midnight on January 1st and July 1st.
// Node.js production bi-annual task runner using node-cron
const cron = require('node-cron');
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
transports: [new winston.transports.Console()]
});
// Schedule for 0 0 1 1,7 * (Standard cron format)
cron.schedule('0 0 1 1,7 *', async () => {
logger.info('Starting scheduled bi-annual database cleanup and audit...');
try {
// Simulate long-running maintenance task
await performBiannualMaintenance();
logger.info('Bi-annual maintenance completed successfully.');
} catch (error) {
logger.error('Failed to execute bi-annual task:', error);
// In production, integrate with PagerDuty or Sentry here
}
}, {
scheduled: true,
timezone: "UTC"
});
async function performBiannualMaintenance() {
return new Promise((resolve) => setTimeout(resolve, 5000));
} › Setup notes
Install node-cron and winston via npm. This script schedules the job using the standard five-field cron format, running in UTC timezone to avoid daylight saving issues.
# Python production bi-annual task runner using APScheduler
import logging
from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def run_biannual_audit():
logger.info("Executing bi-annual audit and data archiving process...")
try:
# Place business logic here
logger.info("Bi-annual process completed successfully.")
except Exception as e:
logger.error(f"Critical error during bi-annual execution: {str(e)}", exc_info=True)
if __name__ == "__main__":
scheduler = BlockingScheduler()
# 0 0 1 1,7 * translates to month='1,7', day=1, hour=0, minute=0
trigger = CronTrigger(month='1,7', day=1, hour=0, minute=0, timezone='UTC')
scheduler.add_job(run_biannual_audit, trigger=trigger, id='biannual_job')
logger.info("Starting scheduler for bi-annual job (Jan 1 and Jul 1)...")
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped.") › Setup notes
Install apscheduler via pip. The script configures a BlockingScheduler with a cron trigger set to run at midnight UTC on the first of January and July.
package main
import (
"log"
"os"
"time"
"github.com/robfig/cron/v3"
)
func main() {
logger := log.New(os.Stdout, "[BiAnnualJob] ", log.LstdFlags|log.LUTC)
// Standard cron parser (5 fields)
c := cron.New(cron.WithParser(cron.NewParser(
cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow,
)))
_, err := c.AddFunc("0 0 1 1,7 *", func() {
logger.Println("Starting bi-annual data purge and compilation...")
defer logger.Println("Finished bi-annual data purge.")
err := executePurge()
if err != nil {
logger.Printf("ERROR: Bi-annual execution failed: %v", err)
}
})
if err != nil {
logger.Fatalf("Failed to schedule cron job: %v", err)
}
logger.Println("Scheduler running...")
c.Start()
// Keep the process alive
select {}
}
func executePurge() error {
// Simulate work
time.Sleep(2 * time.Second)
return nil
} › Setup notes
Initialize your Go module and import github.com/robfig/cron/v3. Use the standard parser configuration to match the 5-field cron schedule format accurately.
package com.example.cron;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class BiAnnualTaskScheduler {
private static final Logger logger = LoggerFactory.getLogger(BiAnnualTaskScheduler.class);
// Spring's cron syntax supports 6 fields (second, minute, hour, day, month, day of week)
// We map "0 0 1 1,7 *" to "0 0 0 1 1,7 *" (adding seconds field)
@Scheduled(cron = "0 0 0 1 1,7 *", zone = "UTC")
public void executeBiAnnualTask() {
logger.info("Starting scheduled bi-annual system reconciliation...");
try {
performReconciliation();
logger.info("Bi-annual system reconciliation completed successfully.");
} catch (Exception e) {
logger.error("CRITICAL: Bi-annual system reconciliation failed!", e);
// Implement alerting integration here (e.g., Slack/PagerDuty hook)
}
}
private void performReconciliation() throws Exception {
// Business logic goes here
Thread.sleep(3000);
}
} › Setup notes
In a Spring Boot application, enable scheduling with @EnableScheduling. Note that Spring's standard cron format requires a 6th field for seconds, mapped as 0 0 0 1 1,7 *.
apiVersion: batch/v1
kind: CronJob
metadata:
name: biannual-cleanup-job
namespace: default
spec:
schedule: "0 0 1 1,7 *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup-executor
image: busybox:1.36
command:
- /bin/sh
- -c
- "echo 'Starting bi-annual tasks'; sleep 10; echo 'Tasks finished successfully'"
restartPolicy: OnFailure › Setup notes
Apply this manifest using kubectl apply -f cronjob.yaml. The concurrencyPolicy: Forbid prevents overlapping executions, and limits keep the execution history clean.
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 1,7 ? *) Systemd Timer
OnCalendar*-01,07-01 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 1 1,7 *
[Timer]
OnCalendar=*-01,07-01 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How can I test a job that only runs twice a year?
Do not wait six months to test. Use a manual trigger mechanism or temporary schedule (like running every minute in a staging environment) to validate the business logic, and verify the cron definition separately using syntax parsers or dry-run tools.
What happens to this cron job during Daylight Saving Time transitions?
Since the job runs at midnight on January 1st and July 1st, DST transitions (which typically occur in March/April and October/November) will not directly affect the execution hours. However, always run your cron daemon on UTC to guarantee consistent execution.
Why is running this job on January 1st at midnight risky?
Midnight on January 1st is one of the most high-traffic, resource-intensive periods for global servers and databases due to year-end processing. Running massive bi-annual jobs at this exact second can lead to database locking and resource contention.
Can I schedule this to run on the last day of June and December instead?
Standard cron does not easily support 'last day of month' logic across different months without complex scripting. Running on the 1st of January and July (`0 0 1 1,7 *`) is the standard, cleaner alternative for bi-annual cadences.
How do I monitor a cron job that runs so infrequently?
Traditional pull-based monitoring is ineffective here. Use push-based heartbeats (like Dead Man's Snitch or Honeybadger) that alert you if they do not receive a ping on January 1st and July 1st within a small buffer window after midnight.
* Explore
Related expressions you might need
Last verified: