Top
Best
New

Posted by yacin 7 hours ago

Love systemd timers(blog.tjll.net)
227 points | 152 comments
thomashabets2 3 hours ago|
I haven't used systemd timers enough to disagree, but

> Ambiguous $PATH settings make cron script execution difficult to predict.

What makes you say that? You can set the PATH right in the crontab. Is that harder to "predict" than it being set in /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile, /etc/systemd/…, or wherever else?

> You might feel cool knowing the scheduling grammar by heart

I've used Linux since 1994 and I don't know it by heart. But luckily it's pre-printed in the crontab as comments:

    # For more information see the manual pages of crontab(5) and cron(8)
    # 
    # m h  dom mon dow   command
You just put numbers aligned with the titles.

The rest of the complaints, sure. Next time I need a cronjob, I'll try it out.

jerf 2 hours ago||
"You just put numbers aligned with the titles."

That is not a fair summarization of their point because that is not the grammar. There's commas, slashes, asterisks, combinations, and then if you want randomization you need to put it in the command itself because cron can't do it. (Some crons can, but it's not a general capability of cron.) Writing a non-trivial cron spec is not easy.

pkal 1 hour ago|||
I am familiar with the syntax, so I am biased ("*/3" and "12,14,20" makes sense if you are familiar with Unix tools), but it is still more intuitive to me than the systemd unit file syntax and usage. I know that I just have to edit /etc/cron or throw any executable file into /etc/cron.d/monthly and it will work on my system, but I cannot write a systemd timer file from scratch without looking it, and to do that I first have to find the directory where the other examples are located. /etc/systemd doesn't appear to be it.

This is generally my only real complaint about systemd. I don't care if it is too monolitic, written in C or whatever, I just want a straightforward syntax for straightforward operations. I'd like it if systemd could recognize if a .target file is a shell script and just do "the right thing". Perhaps it would make sense for a timer file to recognize cron syntax as well. Or at least allow for a kind of extensibility so that I can have it supported.

If systemd had a little more respect for existing conventions, I am pretty sure it wouldn't be so controversial. After all, system administrators like it because they use it all the time, but a regular, full-timer user like me, who only deals with it when something is broken or have to use it as a means-to-an-end to set something up, then all friction is annoying and bad UX. (And no, using Nix is not the solution)

krunck 41 minutes ago||
Yeah, it would be nice to have a folder like /etc/systemd-jobs/ where I could put them and where there are no files unrelated to job scheduling. There is /etc/systemd/user, but it does get a bit of pollution depending on the system.
ralferoo 1 minute ago||
Not sure if you're talking about cron or systemd, but cron definitely has that in /etc/cron.d where you can have arbitrary crontabs, or /etc/cron.{hourly|daily|weekly|monthly} where you can just place arbitrary scripts if you don't care exactly when they run, just the frequency.
eqvinox 1 hour ago|||
How do you express those things in a systemd timer? E.g. run something 4x per day, */6 in cron.
iam-TJ 1 hour ago|||

  $ systemctl cat public-inbox-watch@.timer
  # /etc/systemd/system/public-inbox-watch@.timer
  [Unit]
  Description=Periodic fetch of public mailing list

  [Timer]
  # twice a day
  OnCalendar=*-*-* 5,17:35
  RandomizedDelaySec=1h
  Persistent=true

  [Install]
  WantedBy=multi-user.target
eqvinox 1 hour ago||
I, er, what? It's... the same as cron? I'm confused now. It's not exactly the same, I guess?
ecnahc515 1 hour ago||||
Something like:

    OnCalendar=00/6
You can test it with:

    systemd-analyze calendar --iterations=6 '0/6:00:00'

The format is `DayOfWeek Year-Month-Day Hour:Minute:Second`

https://www.freedesktop.org/software/systemd/man/latest/syst...

PunchyHamster 54 minutes ago||||
That's simple but consider "run something 4x per day but randomize a delay by hour so all of the 200 servers doing that task won't run it all at once"

In cron, you basically have to either use your configuration management to generate those times, or have a random delay script running before the command

In systemd timers, it's just

    OnCalendar=0/6:00:00
    RandomizedOffsetSec=60m
and the offset generated will be stable for the job on a given machine (i.e. always same on this machine but different on others) so you will get nice uniform distribution of load.

If you add

    Persist=true
the job will also be run once if there was one or more scheduled runs when the machine was down
simoncion 35 minutes ago||
> In cron, you basically have to either use your configuration management to generate those times, or have a random delay script running before the command

Nope. From crontab(5)

  The  RANDOM_DELAY variable allows delaying job startups by random amount
  of minutes with upper limit specified by the variable. The random  scal‐
  ing  factor  is  determined during the cron daemon startup so it remains
  constant for the whole run time of the daemon. 
That's from my cronie install, but it looks like this has been a feature of some crons for at least a decade. (Notice that the post date of [0] is in 2016.) Given that cronie is based on vixie-cron, and I think I was was using vixie-cron in 2002, I bet it's been a thing for at least twenty years.

[0] <https://stackoverflow.com/a/34815984>

simoncion 46 minutes ago|||
Sure, I'll pile on here. To do nontrivial scheduling you'd use the entirely-obvious-and-intuitive syntax described at [0]. For example:

  Mon,Fri *-01/2-01,03 *:30:45
Who'd ever want to go back crontab format for nontrivial scheduling? [1]

[0] <https://www.freedesktop.org/software/systemd/man/latest/syst...>

[1] This question is sarcasm. SystemD is often like this... dead simple things look dead simple, but complex things are -if they're possible at all- at least as complex as they are everywhere else.

p0358 22 minutes ago||
If you know the syntax, it's still actually rather trivial. Still easier to read than advanced cron magic.
simoncion 13 minutes ago||
> Still easier to read than advanced cron magic.

Looking at the other examples on that page, I'm gonna say that it's only arguably easier to read for basic stuff... especially if you're familiar with the syntax. The complex stuff is -at best- just as difficult.

jeroenhd 2 hours ago|||
Having had to work on an application supposedly supporting cron expressions: the numbers are just the basic parts of the language.

When someone inputs something ridiculous like "5,3/4 4-8,11 1 4,5,6,9-11 */2" you get to enjoy the fun of reverse engineering what they meant (it's never what they actually wrote).

And that's before you get to all the extensions supported in some cron environments (but not all).

I find systemd timers a lot more manageable. Things like having control over whether or not long-running jobs are allowed to overlap and the ability to run tasks between start-finish rather than a fixed time window are major improvements for me. At some point my VPS went down because the backup job ran into some kind of symlink loop and cron just kept spawning more and more backup tasks even though none of them finished.

Having to re-write commands and scripts because CRON had its own special PATH was also a pain point, but the same can be true for some types of systemd timers. But: you can execute those timers manually if you want instead of updating the crontab to trigger in 30 seconds and simply waiting.

networked 1 hour ago|||
Complex expressions are one of the things I don't like in cron. On Debian/Ubuntu servers, I bite the bullet with systemd timers. On my workstation, I have a personal job scheduler that feels easier and more fun to tinker with. The scheduler uses Starlark functions instead. For example:

  # Run if at least a day has passed since the last run
  # and it isn't the weekend.
  def should_run(finished, timestamp, dow, **_):
      return dow not in [0, 6] and timestamp - finished >= one_day
This was inspired by GNU mcron. In mcron, jobs can calculate the next time they should run using Guile (https://www.gnu.org/software/mcron/manual/mcron.html#Guile-S...):

  (job
     '(next-minute-from
        (next-hour (range 0 24 2))
        '(15))
     "my-program")
I found mcron's scheduling counterintuitive and decided I wanted a function that returned a boolean. I can recommend this approach so far.
ink_13 1 hour ago|||
> 5,3/4 4-8,11 1 4,5,6,9-11 */2

What's so hard about "At 5 minutes past the hour and every 4 minutes, starting at 3 minutes past the hour, at 04:00 AM through 08:59 AM and 11:00 AM, on day 1 of the month, every 2 days of the week, only in April, May, June, and September through November"?

(I used https://crontab.cronhub.io/ to decode it, to be fair)

jchw 2 hours ago|||
The main nice thing about the environment in systemd is that it is standard and mostly a blank slate, whereas at least for me I was always getting bit by the fact that the environment in Crontab was completely different from say, the environment inherited by supervisord or sysvinit scripts. In systemd the actual unit that gets executed is the same regardless of what triggers it, so there is no gap.

That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell.

I'd have to concur that I agree this is an advantage of systemd.

simoncion 59 minutes ago|||
> That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell.

Odd. This script

  #!/bin/bash
  
  set > /tmp/set.txt
when scheduled like so

  * * * * * $HOME/bin/testCronScript.sh
Produces this file in /tmp/set.txt which has had a handful of values (HOME, UID, etc) lightly redacted prior to posting here -to remove PII or for length- but its keys are entirely untouched:

  BASH=/bin/bash
  BASHOPTS=<redacted because long>
  BASH_ALIASES=()
  BASH_ARGC=()
  BASH_ARGV=()
  BASH_CMDS=()
  BASH_LINENO=([0]="0")
  BASH_LOADABLES_PATH=/usr/local/lib64/bash:/usr/lib64/bash
  BASH_SOURCE=([0]="/home/user/bin/testCronScript.sh")
  BASH_VERSINFO=<redacted bash 5.3.x>
  BASH_VERSION=<redacted bash 5.3.x>
  DIRSTACK=()
  EUID=13370
  GROUPS=()
  HOME=/home/user
  HOSTNAME=hostname
  HOSTTYPE=x86_64
  IFS=$' \t\n'
  LANG=en_US.utf8
  LOGNAME=user
  MACHTYPE=x86_64-pc-linux-gnu
  OPTERR=1
  OPTIND=1
  OSTYPE=linux-gnu
  PATH=/usr/bin:/bin:/usr/sbin:/sbin
  PPID=1337
  PS4='+ '
  PWD=/home/user
  SHELL=/bin/sh
  SHELLOPTS=braceexpand:hashall:interactive-comments
  SHLVL=1
  TERM=dumb
  UID=13370
  USER=user
  _=/home/user/bin/testCronScript.sh
Seems pretty clean to me. Even when I run this via /etc/crontab, rather than as a user cron job:

  * * * * * root /home/user/bin/testCronScript.sh
I get effectively the same results.

Maybe your distro's default cron environment was bad, and you never bothered to check and unset the badness? I'd be surprised if they were unable to make the default environment for Timer Units to be bad.

skydhash 1 hour ago|||
I use cron in OpenBSD and it's a deterministic environment and mostly clean[0]. I like that instead of having other subsystems creep in.

[0]: https://man.openbsd.org/crontab.5#ENVIRONMENT

nailer 1 hour ago|||
> But luckily it's pre-printed in the crontab as comments

That's true, but most people don't know the numbered manual sections, so they get the docs for the cron table command not the cron table config file.

skydhash 1 hour ago||
> That's true, but most people don't know the numbered manual sections, so they get the docs for the cron table command not the cron table config file.

No `man man`? ;)

PunchyHamster 1 hour ago|||
problem with vars is that they apply to any subsequent entry in the file so you need to take that into consideration; the nice thing about timers is that all settings are self contained and not affected by previous entries. The standard /10 and similar cron expressions also have thundering herd problem when on bunch of servers, tho some variants like in Jenkins use variant H/10 (H standing for hash) where the thing is randomly shifted in time to not hit same minute on same server/job

another benefit is having logs in one place for the job; cron's "send a mail when there is any amount of output text" is just annoying behaviour, but also only place to get the job output unless you redirect it somewhere. Also starting from timer vs just doing systemctl start job.service is the same so easier to debug

other than that the few improvements in how to specify run time have been pretty useful.

For example, setting timer as "persistent" will mean any run "lost" to machine powered off will just be ran next time after boot, so you can have job on your PC that is just "run backup at 2AM" and if you turn it off before that you get the backup done first thing in the morning

There is also both random, and fixed (depending on machine UUID) random delay so avoiding thundering herd problem with backups is also pretty convenient.

There is even option to wake a device for the job if necessary tho the problem of shutdown is left to the user. And picking whether to start counting to next timer from previous one or from the job's end.

What I would like also is to have job summary page ("hey this job was done X times but failed Y times") but that's probably better left to external tooling

> You can set the PATH right in the crontab. Is that harder to "predict" than it being set in /etc/bashrc, ~/.bashrc, ~/.profile, ~/.bash_profile, /etc/systemd/…, or wherever else?

There is* a common trap as the cron PATH is usually just /usr/bin:/bin so anything in /usr/local/bin, or in /sbin won't be there.

egorfine 1 hour ago||
> I've used Linux since 1994

Same here.

We are now considered old and therefore irrelevant. The new generation uses timers and couldn't care less about cron that has served us just fine for decades.

I use cron and my general attitude towards LP and systemd is very similar to the attitude of LP and systemd to us.

NikhilVerma 3 hours ago||
I have a Canon printer, I actually can't trust that their print nozzle won't get jammed up after sitting idle for a while. So I had claude setup a systemd script to print a picture of my dog every week, I ensure it has enough CMYK spectrum to stress the printer. Its a nice surprise every monday as I sit on my desk to see a sudden picture pop up from the printer :)
tdeck 3 hours ago||
I wish printers could have a mode like this to print random images from an album, or a calendar, rather than wastefully draining ink into a sponge every few days.

If nothing else, maybe it could be some kid's high school science fair project idea.

sunrunner 3 hours ago||
How about printing a QR code for a randomly generated private key for Satoshi Nakamoto's Bitcoin wallet, then every few days you get a tiny moment of excitement, hope, and then disappointment. It's still wasteful, but it could pay off big time?
tekno45 1 hour ago|||
this is an amazing youtube video idea if you could get a type writer to do it.
sunrunner 35 minutes ago||
Maybe I'm misremembering, but I'm sure there was something on HN a few weeks ago about an electric typewriter that someone had connected to (I'm guessing) a Raspberry Pi? My search-fu is currently failing to find anything particularly recently, at the moment.
NSUserDefaults 3 hours ago|||
Or if you have a printer/scanner combo, you can turn it into a pen pal!
magicalhippo 3 hours ago|||
Dad had an Deskjet 720 or something like that.

It sat unused and powered off for a couple of years after he passed, until I needed a color print.

Didn't do anything but hook it up to power and print. Took about 1/5 of a page until all colors were back in action, after that it printed about 20 pages flawlessly.

ThePowerOfFuet 3 hours ago|||
Laser printers are your friend. The savings on consumables alone will make it pay for itself.
criddell 23 minutes ago|||
Laser printers are great for documents, but not very good for photos.

I have an ink jet printer that I like. I don't print very often (average a couple pages per week) but when I do it's a mix of documents and photos. The ink isn't cheap, but the quality seems good and for the amount I print the expense is minor.

tobyhinloopen 3 hours ago||||
Epson Ecotank. I’ve been using mine for years and I only had to buy new ink once.

And I printed a lot of photos, notes, documents, etc

Blackthorn 3 hours ago||
Those will still get their nozzles clogged if you don't run them.
ssl-3 1 hour ago||
This is the part where I get to point out that Brother inkjets do a little dance ~every day that keeps the heads fresh. They do this on their own as for long as they're powered up.

This allows them to work well even if years go by between prints. It's a very thoughtful design element.

(They don't survive sitting for months and months unpowered on a shelf very well, but... you'll have that.)

hmng 3 hours ago|||
Not to mention more water resistant, when printing things like envelopes.
RicoElectrico 3 hours ago||
I was about to recommend a cheap OKI LED color printer (I think C322dn); alas they withdrew from consumer market :/ The colors are super nice and uniform, even if the maximum resolution is only 600 dpi - and the toner won't dry out, which was my brother's crucial purchase criterion; we had HP inkjet clogged more than once.
gchamonlive 4 hours ago||
Moved from cronie to systemd timers because they are resilient to system startup times. My backup strategy is to create a borg archive entry every day at a fixed time. With cronie the system needs to be running at the scheduled time, but systemd timer tolerates this and runs the service as soons as the system is available.

Btw this is my repo for the backup automation: https://github.com/gchamon/borg-automated-backups

mid-kid 3 hours ago||
Cronie has a mechanism for this, called "anacron", which is called hourly by cron (on my system, /etc/cron.hourly/0anacron), and performs all the /etc/cron.{daily,weekly,monthly} tasks, no matter if the earliest possible schedule was missed (and with a configurable random delay). You can modify /etc/anacrontab to create custom schedules.

To do this at the user level, you can add something like "@hourly anacron -t /path/to/anacrontab -S /path/to/spooldir" to the user's crontab, though I've never tried this.

Many cron implementations have a similar mechanism.

gchamonlive 2 hours ago||
EDITED

This isn't the same as with systemd timer because timer lets you specify when you want to run your service exactly and will fallback to running when the system comes online. With @hourly I lose this control and multiple machines could potentially trigger backups at the same time, hogging the physical hard drives and the network.

layer8 2 hours ago|||
Cron also has @reboot. Not exactly the same, but has been sufficient for me so far.
gchamonlive 1 hour ago||
https://news.ycombinator.com/item?id=48371021
newsoftheday 2 hours ago|||
> fallback to running when the system comes online.

That isn't something I'd want to happen, it sounds like it creates a potential queue of scripts that will flood the system on start, if it works the way you described.

I prefer the deterministic behavior of cron, the script will run when it is specified to run, as you said earlier, as long as the system is running; and as I stated in a separate comment, it will run @reboot if I need it to run then.

> With @hourly I lose this control and multiple machines could potentially trigger backups at the same time

Then don't use @hourly, use staggered times, it's very easy.

gchamonlive 2 hours ago|||
> That isn't something I'd want to happen, it sounds like it creates a potential queue of scripts that will flood the system on start, if it works the way you described.

This isn't what happens. If you leave it offline for days it'll only trigger the service only a single time.

happysadpanda2 1 hour ago|||
I interpreted it more like "I have these 500 different cronjobs all spread out across $unit_of_time. If the system is down for longer than $unit_of_time and then comes back, does all 500 jobs start running instantly (since they missed their previous deadline)?"
gchamonlive 1 hour ago||
Just to be clear, this isn't default systemd timer behaviour, you need to opt in by setting Persistent=true. If you have hundreds of jobs like this you need a proper queue and neither cronie nor systemd is the right tool because at that scale you'd surely need better observability
bisby 1 hour ago|||
If you have 100 different jobs that were supposed to run over the past week, but didn't because offline, when you restart, they they all flood the system on start.

100 jobs all running at different times throughout the week is a very different load than them all falling back and running at the same time on system boot.

gchamonlive 1 hour ago||
I don't, it's a single backup service.
PunchyHamster 46 minutes ago|||
> That isn't something I'd want to happen, it sounds like it creates a potential queue of scripts that will flood the system on start, if it works the way you described.

There are two options to fix it;

Disable persist so no catching up on missing scripts. Set OnBoot=5m so it gets ran 5 minutes after boot, so your script (say backup) is ran on boot first, then every time on schedule

Enable persist but just add sleep in ExecStartPre - very "cron" way but there is just no in-systemd option to enable "catch up" script to be delayed

Sadly no option to "run catch-up timers with delay" at least yet

> Then don't use @hourly, use staggered times, it's very easy.

Not in cron. In systemd it's just RandomizedOffsetSec=30m and it is "stable" - same host with same job will always have same delay so on multiple hosts it is spread nicely. There is also non-stable version

michaelcampbell 1 hour ago|||
> With cronie the system needs to be running at the scheduled time, but systemd timer tolerates this and runs the service as soons as the system is available.

Cronie doesn't have a `@reboot` meta-trigger?

gchamonlive 1 hour ago||
https://news.ycombinator.com/item?id=48371021
newsoftheday 2 hours ago||
I'm sorry, I tried Googling the word "tolates" but I can't find any definition that makes sense?

> runs the service as soons as the system is available.

cron has the @reboot option which I use for a few scripts and works great.

gchamonlive 2 hours ago|||
Typo, I meant tolerates. Fixed it.

Not an option either, because if I reboot two machines and the backup starts in both of them it'll cripple my NAS

regularfry 2 hours ago|||
"tolerates".
kayson 2 hours ago||
I love systemd timers! I've slowly moved all of my ansible-deployed cron jobs to timers (now just an ansible copy!). The integration with journalctl, especially in a newer OS like Debian 13 where syslog is gone, is really nice. It's also really nice to be able to start the service manually for debug. Having a cron job that didn't work was an annoying exercise in copy/pasting or writing an extra shell script. Don't even get me started on the black hole of cron job stdout. I can monitor systemd services like I already do and get a notification on failure.

I've noticed more and more open source projects recommending timers as a deployment method and I think that's great!

egorfine 1 hour ago|
> more and more open source projects recommending timers

I am perfectly happy with projects recommending timers as long as I can ignore them and use cron.

stryan 4 hours ago||
Timers can work with arbitrary units (not just a similarly-named service unit) so they can be surprisingly flexible. I have a timer on my servers that starts a backup.target that fires off a full "restic backup","restic prune", "restic forget" backup cycle each morning with randomized start times and notifications. The actual restic-* units are Podman Quadlets so the whole setup runs agnosticaly of what's on the server, just as long as it has Podman and Systemd installed.

I will admit thought, timers are up there in terms of being the clunkiest systemd unit type to use on a regular basis. I get why they're split up into two files and require different start vs enable syntax's, but man sometimes I just want to create a file that runs a script and be done with it.

9dev 2 hours ago||
I feel like systemd units could need a layer of abstraction above them, so instead of editing the files manually, a tool would do it, some kind of declarative CLI or something. Probably not really a concern in the age of LLMs anymore, but it feels just slightly too tedious every time.
esperent 4 hours ago||
Why do you randomize your backup times?
stryan 3 hours ago||
Should have been more clear: I use RandomizedOffsetSec= to add a random offset to a set start time (usually 4am), to prevent overloading the backup server, not truly random start times.
hombre_fatal 4 hours ago||
NixOS comes with systemd, so I've been using it as a first-class part of managing stuff. It's great, especially coming from macOS' launchd.

Which makes it nice to distribute a tool for NixOS so that it can lean into systemd instead of as some bolted-on afterthought.

Makes me wonder what you'd do if you were distributing a lifecycle-heavy tool for Linux users in general since systemd isn't ubiquitous.

I use a systemd timer to run a monthly scrub for my btrfs pool. Kinda cool how you can do increasingly useful things like skip the next scheduled event if the user initiates a scrub, do or don't accumulate tasks if you have a monthly task but the machine was offline for 6 months -- or fold them into a single task, etc.

Cyph0n 4 hours ago||
+1, NixOS makes working with systemd a breeze. Defining units in Nix beats wrangling INI files.

  systemd.services.sync-recyclarr = {
    serviceConfig.Type = "oneshot";
    path = [ pkgs.podman ];
    script = ''
      podman exec -it recyclarr recyclarr sync radarr
      podman exec -it recyclarr recyclarr sync sonarr
    '';
  };
  systemd.timers.sync-recyclarr = {
    timerConfig = {
      OnCalendar = "daily";
      Persistent = true;
      Unit = "sync-recyclarr.service";
    };
    partOf = [ "sync-recyclarr.service" ];
    requires = [ "podman-recyclarr.service" ];
    wantedBy = [ "timers.target" ];
  };
drunner 4 hours ago||
Have you been defining them directly in your flake.nix file? I too am on nixos but I keep all my configurations in their native format and symlink them with nix, that way I can take and reuse that config on a non nixos system easily.

The problem I have found is that nixos doesn't seem to pickup and run systemd timers and services placed into the ~/.config/systems/user folder and additionally things like WantedBy=default.target have no effect.

So after I restart all my services manually on reboot I agree, systems timers are cool.

Cyph0n 4 hours ago||
I define all units in Nix because:

a) It is way nicer and you get decent validation at build time

b) A LLM can port units over if the need arises; it’s a very light abstraction around systemd syntax

c) I personally don’t see how I would ever move to another distro :)

chuckadams 2 hours ago||
I believe one of the major distro lines (redhat or debian, I forget which) uses systemd-cron, where cron is just a thin wrapper around systemd. You get more power from writing the unit files directly, but if all you ever need is a simple cron job, you have the old interface still available.
MathMonkeyMan 1 hour ago|
Yep, I use this for a @reboot job and a few regular jobs on my home server. I use user crontabs, so I can get around the "unknown shell/path/etc." by prefixing every job with

    /some/shell -l myjob.sh
or sometimes

    . ~/.profile && cd /some/where && ./job >>cron.log 2>&1
t43562 25 minutes ago||
It may be a disastrous comment to make but I think I like cron better! A tool designed for a particular job etc.... :/
supriyo-biswas 22 minutes ago||
I wonder what happened with the heading, it was okay before, and then was mutilated since.
Bender 1 hour ago|
I will use what I am comfortable with and so should others. CronD, SystemD, atD, multiple conditional checks in a shell script, whatever tickles your fancy. There is no wrong answer, just document what you did and add a comment. Comments are permitted in cron. If someone keeps putting complex obfuscated time structures into cron make them decipher their incantation and keep nagging them until they keep it simple, comment their cron entries or until they and their manager resign.

For what it's worth there are usually web apps popping up that can decipher goofy cron time/date incantations. [1] This one has a git repo in the top right, not my repo. Maybe clone it just in case their site goes away some day.

[1] - https://crontab.cronhub.io/

More comments...