Question: I have in my crontab the following

`15 */4 * * * ...`

My original intent was that I would run ... every 4 hours from when the computer boots up. If I power on at 8 am, it would run at 8, 12, 16, 20, ...; if I power on at 9am it would run at 9, 13, 17, 21, ...

My observation is that crontab seems to divide the hour by 4 and if the remainder is 0 it executes.

Is there a way I can achieve the former rather than the latter?

Answer: 
This is something that might more easily be done on current Ubuntu systems using a [systemd timer](https://www.freedesktop.org/software/systemd/man/systemd.timer.html#).

Following the [monotonic timer](https://wiki.archlinux.org/title/Systemd/Timers#Monotonic_timer) example in the [archlinux wiki](https://wiki.archlinux.org/):

1. create a service unit file to run your command (`/usr/local/bin/foo` in this example) as a oneshot service

```
[Unit]
Description=do some stuff on schedule defined by foo.timer

[Service]
Type=oneshot
ExecStart=/usr/local/bin/foo

```
2. create a corresponding timer unit with the desired time specifications (0 seconds after boot, and then 4 hours after the service unit was last activated)

```
[Unit]
Description=Run foo on boot and every 4 hours thereafter

[Timer]
OnBootSec=0
OnUnitActiveSec=4h

[Install]
WantedBy=timers.target

```
3. enable the timer

```
sudo systemctl enable foo.timer

```

After reboot, you should be able to see the new timer along with its last and next activation times:

```
$ systemctl list-timers foo
NEXT                        LEFT          LAST                        PASSED      UNIT      ACTIVATES  
Thu 2023-01-12 19:37:39 EST 3h 58min left Thu 2023-01-12 15:37:39 EST 1min 5s ago foo.timer foo.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.

```
Have you considered the use of at as a scheduler?

At boot time, run a script that schedules an 'at' job four hours hence and passes the time it ran to something the at job can read (e.g. a file somewhere, e.g. within the at job itself, e.g. a parameter passed to the 'at' job, there are many ways you can pass the parameter).

When the 'at' job runs, at some point in the script run it schedules another 'at' job exactly 4 hours after it was launched. This will only suffer schedule creep or not-four-hourness at times your system clock enters or exist DST (twice a year if the timezone it runs in uses daylight saving) or when the system clock gets a time adjustment...