# Cron Job Helper — Tips & Tricks

> Cron pitfalls: day-of-month and day-of-week as OR logic, the server time zone, suppressing output, MAILTO, absolute paths and locking against overlap.

Source: https://www.jpkc.com/db/en/tools/cron/tips/

Back to the overview: [Cron Job Helper](https://www.jpkc.com/db/en/tools/cron/) · Open the live tool: [www.jpkc.com/tools/cron/](https://www.jpkc.com/tools/cron/)

The [Manual](https://www.jpkc.com/db/en/tools/cron/manual/) explains every tab; the [Examples](https://www.jpkc.com/db/en/tools/cron/examples/) show concrete expressions. This page is about what tends to go wrong when writing cron — the traps you only notice on the third missed run.

## The infamous OR logic between day-of-month and day-of-week

The single most important cron trap: when you restrict **both** the *Day of Month* field **and** the *Day of Week* field (neither is `*`), classic Unix cron combines them with **OR**, not AND. The job then runs on every day that satisfies **either** condition.

Example:

```
0 0 13 * 5
```

This does **not** run "only on a Friday the 13th" but on **every 13th of the month AND additionally every Friday**. If you want "Friday the 13th", standard cron cannot express it in a single line.

Practical takeaway: always restrict **only one** of the two day fields and leave the other on `*`. The builder's plain-text preview phrases such cases as "on day-of-month X and weekday Y" — but for the actual meaning, trust the real cron OR rule, because that is how the daemon behaves on the server.

## Cron runs in the server's time zone — not yours

Cron uses the **server's time zone** (often UTC), not your local one. A `0 3 * * *` is "3 AM server time". Two things follow:

- On the system you can set the crontab's time zone with `CRON_TZ=Europe/Berlin` at the **top** of the file (as the tool's *General Best Practices* block recommends). In containers, set `TZ=Europe/Berlin` as an environment variable instead — otherwise the container runs in UTC.
- The **Next Scheduled Runs** in the builder compute in your **browser's** time zone. That preview is a convenient estimate, but not necessarily identical to what the server does. Plan in server time when the hour matters.

## Suppressing output: MAILTO vs. /dev/null

By default, cron emails any output (stdout **and** stderr) of a job to the local system user. A chatty script floods the inbox. There are two levers, which the *Reference* tab clearly separates:

- `MAILTO=""` at the top of the crontab disables emails **globally** for the whole file.
- `> /dev/null 2>&1` after the command suppresses output **per job** — and also prevents a process from blocking on a full mail queue.

For web cron jobs, **combining both** is the most robust. Note: `> /dev/null 2>&1` also redirects stderr (`2>`) — `> /dev/null` alone would still email error messages.

## Use absolute paths

Cron starts with a **minimal environment**: `$PATH` is usually just `/usr/bin:/bin`, and your interactive profile (`.bashrc`, `nvm`, `rbenv` …) is not loaded. A command that works in your shell can fail silently under cron because the binary is not found. So: use **absolute paths** to the interpreter and script (`/usr/bin/php /var/www/html/artisan …`) instead of just `php …`. If a script needs particular environment variables, set them explicitly at the top of the crontab.

## Specify the user (in system-wide crontabs)

In `/etc/crontab` and files under `/etc/cron.d/`, the username comes **before the command** — e.g. `www-data`. This is a common trap: the **personal** crontab (`crontab -e`) has **no** such field (the job runs as that user), while the system-wide files require it. The tool's CMS recipes show the system-wide form with `www-data`.

## Prevent overlapping runs (flock)

If a job takes longer than its interval (e.g. a `*/5` import that sometimes runs 7 minutes), cron starts the next run anyway — two instances race and can clash. Guard against it with `flock`:

```
*/5 * * * *  flock -n /tmp/mycron.lock php /var/www/html/artisan schedule:run >> /dev/null 2>&1
```

`flock -n` only starts the job if the lock file is free, and skips it otherwise. The tool mentions this trick in its *General Best Practices* block.

## Web cron vs. system cron — when to use which

The **Web Cron** tab builds jobs that call a URL via `curl`/`wget` — the schedule still runs in the system cron, only the **command** is an HTTP request. When is that worth it?

- **Web cron** is the right choice on **shared hosting**, where you lack shell access or control over CLI tools, and for CMS endpoints triggered over HTTP anyway (`wp-cron.php`, Drupal's `/cron/KEY`).
- **System cron with CLI** (WP-CLI, Drush, `artisan`, `console`) is faster, more robust and bypasses the web server timeout. Where you have shell access it is the better choice — the *CMS & Frameworks* tab recommends the CLI path throughout.

When you protect a web cron endpoint, remember the **Web Cron Tips** from the tool: always use `-s` (silent) with curl, redirect output to a log file, secure the URL with a token/IP restriction/basic auth, set a timeout, and use **HTTPS** exclusively so credentials are not sent in plain text.

## Quartz characters do not work in Unix cron

The *Reference* table lists `?`, `L`, `W` and `#` and marks them explicitly as **Quartz**. These belong to the Java Quartz scheduler (and a few cron derivatives), **not** to plain Unix `cron`. A `0 0 L * *` ("last day of the month") or `5#3` ("3rd Friday") is not understood by vixie/cronie cron. Use them only if your target scheduler speaks Quartz syntax; for a classic `crontab`, stick to `* , - /`.

## Containers: log to stdout

In Docker/Podman, write cron output to **`/proc/1/fd/1`** (or `stdout`) so it appears in `docker logs` — otherwise it vanishes. And mind the time zone: without `TZ`, the container runs in UTC. Both are in the tool's **Container Cron Tips**.

## Combine with other JPKCom tools

- **[Docker tools](https://www.jpkc.com/db/en/tools/docker/)** — when you turn the container patterns from the *Docker / DDEV* tab into a real setup.
- **[Time & timestamp tools](https://www.jpkc.com/db/en/tools/time/)** — to clarify the server time zone and Unix timestamps before committing to a clock time.

---

More context: the [overview](https://www.jpkc.com/db/en/tools/cron/) for the big picture, the [Manual](https://www.jpkc.com/db/en/tools/cron/manual/) for every tab, and the [Examples](https://www.jpkc.com/db/en/tools/cron/examples/) for concrete expressions. Try it all directly in the [tool](https://www.jpkc.com/tools/cron/).

