Run Every 30 Minutes During Business Hours | CronBase
*/30 9-17 * * 1-5 Every half hour during standard business hours on weekdays, starting at nine in the morning and ending at five in the afternoon.
This cron expression schedules a task to execute every thirty minutes, specifically at the top of the hour and thirty minutes past the hour, between the hours of 9:00 AM and 5:30 PM, Monday through Friday. It is ideal for business-day automated processing.
- Minute
- */30
- Hour
- 9-17
- Day of Month
- *
- Month
- *
- Day of Week
- 1-5
Next 5 Runs
- in 1d 12h
- in 1d 13h
- in 1d 13h
- in 1d 14h
- in 1d 14h
* Tools
Code & Implementations
#!/bin/bash
# Safe script to install the cron job for the current user
CRON_EXPR="*/30 9-17 * * 1-5"
JOB_CMD="/usr/local/bin/sync_crm_data.sh >> /var/log/crm_sync.log 2>&1"
# Ensure we do not duplicate the entry in the crontab
(crontab -l 2>/dev/null | grep -F "$JOB_CMD") && echo "Cron job already installed" && exit 0
(crontab -l 2>/dev/null; echo "$CRON_EXPR $JOB_CMD") | crontab -
echo "Cron job successfully installed: $CRON_EXPR" › Setup notes
Save the script to your server, make it executable using chmod +x, and execute it as the user who should run the cron job.
const cron = require('node-cron');
const { exec } = require('child_process');
// Schedule task to run every 30 minutes during business hours (9 AM - 5 PM, Mon-Fri)
const task = cron.schedule('*/30 9-17 * * 1-5', () => {
console.log(`[${new Date().toISOString()}] Starting business hour sync...`);
exec('/usr/local/bin/sync-job.sh', (error, stdout, stderr) => {
if (error) {
console.error(`Execution error: ${error.message}`);
return;
}
if (stderr) console.warn(`Stderr: ${stderr}`);
console.log(`Stdout: ${stdout}`);
});
}, {
scheduled: true,
timezone: "America/New_York" // Explicitly define timezone to handle DST shifts
});
task.start(); › Setup notes
Install the dependency using npm install node-cron and run the script using node scheduler.js in a process manager like PM2.
from apscheduler.schedulers.blocking import BlockingScheduler
import logging
import subprocess
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("business_hours_scheduler")
def run_sync_task():
logger.info("Starting business hour data synchronization task...")
try:
result = subprocess.run(["/usr/local/bin/sync-job.sh"], capture_output=True, text=True, check=True)
logger.info(f"Task completed successfully. Output: {result.stdout}")
except subprocess.CalledProcessError as e:
logger.error(f"Task failed with exit code {e.returncode}. Error: {e.stderr}")
scheduler = BlockingScheduler(timezone="America/New_York")
# Standard cron fields: minute, hour, day, month, day_of_week
scheduler.add_job(run_sync_task, 'cron', minute='*/30', hour='9-17', day_of_week='mon-fri')
try:
logger.info("Starting scheduler...")
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped cleanly.") › Setup notes
Install APScheduler using pip install apscheduler and run the python file to start the persistent scheduling daemon.
package main
import (
"fmt"
"log"
"os/exec"
"time"
"github.com/robfig/cron/v3"
)
func runTask() {
log.Println("Starting scheduled business-hours synchronization...")
cmd := exec.Command("/usr/local/bin/sync-job.sh")
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error executing job: %v. Output: %s", err, string(output))
return
}
log.Printf("Job completed successfully: %s", string(output))
}
func main() {
// Use New with Location to handle DST and timezone offsets
nyc, err := time.LoadLocation("America/New_York")
if err != nil {
log.Fatalf("Failed to load timezone: %v", err)
}
c := cron.New(cron.WithLocation(nyc))
_, err = c.AddFunc("*/30 9-17 * * 1-5", runTask)
if err != nil {
log.Fatalf("Error scheduling job: %v", err)
}
log.Println("Scheduler initiated for standard weekday business hours.")
c.Start()
// Keep the process alive
select {}
} › Setup notes
Initialize your module, run go get github.com/robfig/cron/v3 to install the cron library, and run using go run main.go.
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.TimeZone;
public class BusinessHoursScheduler {
public static class SyncJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Executing business hours synchronization task...");
try {
Process process = Runtime.getRuntime().exec("/usr/local/bin/sync-job.sh");
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new JobExecutionException("Task failed with exit code: " + exitCode);
}
} catch (Exception e) {
throw new JobExecutionException("Execution failed", e);
}
}
}
public static void main(String[] args) {
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(SyncJob.class)
.withIdentity("syncJob", "group1")
.build();
// Quartz uses 6-7 fields (seconds, minutes, hours, day-of-month, month, day-of-week)
// Standard cron: */30 9-17 * * 1-5 maps to Quartz: 0 0/30 9-17 ? * MON-FRI
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("syncTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/30 9-17 ? * MON-FRI")
.inTimeZone(TimeZone.getTimeZone("America/New_York")))
.build();
scheduler.scheduleJob(job, trigger);
System.out.println("Quartz Scheduler started successfully.");
} catch (SchedulerException se) {
se.printStackTrace();
}
}
} › Setup notes
Add the Quartz scheduler dependency to your Maven pom.xml or Gradle build file, compile, and execute the main class.
apiVersion: batch/v1
kind: CronJob
metadata:
name: business-hours-sync
namespace: default
spec:
schedule: "*/30 9-17 * * 1-5"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: sync-worker
image: registry.example.com/sync-worker:v1.2.0
imagePullPolicy: IfNotPresent
command:
- /usr/local/bin/sync-job.sh
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
restartPolicy: OnFailure › Setup notes
Save the manifest to a YAML file, adjust the container image, and apply it to your cluster using kubectl apply -f cronjob.yaml.
Last verified:
Keep this cron job monitored 24/7
UptimeRobot alerts you the moment a scheduled job stops responding. Free plan monitors up to 50 endpoints — no credit card required.
Platform Equivalents
AWS EventBridge
Standard cron expressions often need conversion for AWS EventBridge schedules.
cron(*/30 9-17 ? * 1-5 *) Systemd Timer
OnCalendarMon..Fri *-*-* 09..17:00/30:00
[Unit]
Description=Timer for cron expression: */30 9-17 * * 1-5
[Timer]
OnCalendar=Mon..Fri *-*-* 09..17:00/30:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
Does this schedule execute exactly at 5:00 PM or does it run until 5:30 PM?
It runs at both 5:00 PM and 5:30 PM. The hour range '9-17' is inclusive of the 17th hour (5 PM), meaning executions occur at 17:00 and 17:30. The next scheduled run after 17:30 will be at 09:00 the following weekday morning.
How do Daylight Saving Time (DST) changes affect this weekday business schedule?
Standard system cron utilities typically run on system time (which is often set to UTC). If your system is set to UTC, the schedule will not shift for DST, causing your business-hour jobs to run an hour early or late relative to local business time. To prevent this, use a timezone-aware scheduler wrapper or set your host timezone to your local region.
What happens if a job execution takes longer than 30 minutes to complete?
With standard cron, a new process will start at the next 30-minute mark regardless of whether the previous instance finished. This can cause overlap, database locking issues, and resource exhaustion. To prevent this, implement locking using tools like flock in Bash, or use the Kubernetes 'concurrencyPolicy: Forbid' option.
Is it possible to exclude national holidays from this weekday business cron schedule?
Standard cron dialects do not have built-in holiday awareness. To handle holidays, your execution script or application code must check a holiday calendar API or database table at startup and exit gracefully if the current date is a designated holiday.
How can I test the schedule locally to verify it triggers correctly on weekends?
You can temporarily modify the day-of-week field from '1-5' to '*' or include the current weekend day (e.g., '1-5,6' for Saturday) in a local testing environment. Alternatively, mock your system time or use simulation tools like croniter in Python to verify execution timestamps.
* Explore
Related expressions you might need
Last verified: