jobscheduler is less time-related than startserviceat.
it can actually have nothing to do with a given time of day,
whereas startserviceat is nothing without a time of day.
with jobscheduler, the os decides when to run your jobs.
with startserviceat, the app decides (but MAY be delayed
by the os).
jobscheduler survives rebooting, startserviceat doesn't.
(of course, you can cause your app to run after reboot, so
that issue is moot.)
jobscheduler makes sure your job - once running - isn't killed.
unclear what kinds of guarantees you have with startserviceat.
with jobscheduler, battery issues are handled by the os. with
startserviceat, you usually have to deal with these yourself (by learning
all the various conditions under which your app can function).
in addition to jobscheduler and startserviceat, there is also the
alarm broadcast receiver, and SetExactAndAllowWhileIdle you
can look into.