[comp.sys.sun] CRON problem after Daylight time change

craig@uunet.uu.net (Craig Donath) (04/17/91)

We are running a small system here with a Sun 4/330 as a server for a half
dozen SPARC1's. Version 4.1.1 of SunOS was installed a month ago. 

This week we noticed that one of our cron jobs has stopped running. It
does not appear to have run since late Saturday sometime. It is a job
intended to load some tables in an INFORMIX database IF the ascii load
files have been sent from another source. The crontab entry is:

    30 0-8,18-23 * * * /usr/local/cron_load.sh

In other words, the script is to run each hour on the half-hour except
during the work day. It has been fine for many months, but on Monday
(April 8) we noticed that none of the files queued on Sunday or Monday had
been picked up.  The job only sends mail if it finds work to do, so we
could only trace it back to Saturday when looking for successful
execution. Cron was running, and in fact, other jobs in the same (root)
crontab were still working OK.

By stopping and restarting cron we were able to correct the problem, but
are curious as to why it occurred. By coincidence, this is the ONLY job
that would have been scheduled between midnight and 5:00 AM Sunday morning
(when the time gained an hour - at 2:00 AM I guess...), and as I mentioned
before, the only one that stopped working. Was the system still waiting
for something to happen at 2:30 AM that it never saw? Did this happen to
anyone else?

The folks at the 800 line gave the usual, "Well, I guess that was probably
it, then..." answer, but that still leaves me feeling kinda hollow. Until
I hear otherwise, I will assume this experience was due to Too Many Years
Of Bad Drugs and write it off as such.

Does anyone really know?
Craig Donath

winfpet@duticai.tudelft.nl (Hans Petri) (05/10/91)

Craig Donath wrote:

> This week we noticed that one of our cron jobs has stopped running. It
> does not appear to have run since late Saturday sometime. 
> Cron was running, and in fact, other jobs in the same (root)
> crontab were still working OK.
> Craig Donath

I've had the same experience. I was curious about what would happen with
cron-jobs during the switch from standard-time to daylight saving time.  I
issued a job that executed the date command every 10 minutes and appended
the output to a file. This is what I saw in the file:

Sun Mar 31 00:50:00 MET 1991
Sun Mar 31 01:00:00 MET 1991
Sun Mar 31 01:10:00 MET 1991
Sun Mar 31 01:20:00 MET 1991
Sun Mar 31 01:30:00 MET 1991
Sun Mar 31 01:40:00 MET 1991
Sun Mar 31 01:50:00 MET 1991
Sun Mar 31 11:55:00 MET DST 1991

The last line is appended to the file after I modified the crontab (added
a line and immediately deleted it again) and saved it again, using crontab
-e.  Execution of the crontab-file stopped at he moment we got into
daylight saving time!

J.M. Petri
E-mail: winfpet@duticai.tudelft.nl

knutson%sw.mcc.com@mcc.com (Jim Knutson) (06/28/91)

I posted this to sun-managers a while back.  It will restart cron appropriately
at each time change.


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by knutson on Wed Jun 12 13:25:51 CDT 1991
# Contents:  dstcronfix

echo x - dstcronfix
sed 's/^@//' > "dstcronfix" <<'@//E*O*F dstcronfix//'
#!/bin/sh
# @(#)dstcronfix	1.3	4/15/91
#
# NAME
#	dstcronfix - restart cron when DST changes
#
# SYNOPSIS
#	dstcronfix
#
# DESCRIPTION
#	dstcronfix determines when the next DST change takes place and
#	then schedules an at job to restart cron after the change has
#	taken place.
#
#	The at job is scheduled to start just before the time change.
#	It then waits until the time change has occured before killing
#	and restarting cron.  It also reschedules itself for the next 
#	DST change.
#
#	The leadtime for scheduling is set in the script and should be
#	set to a value which will allow cron to run it before the DST
#	change occurs.  For SunOS 4.0 and greater, at/cron have a 1
#	minute granularity.  Other systems which execute atrun from
#	cron must set the lead time to account for the granularity in
#	running atrun.
#
# SEE ALSO
#	at(1), cron(8), zdump(8)
#
# AUTHOR
#	Jim Knutson <knutson@mcc.com>
#
# BUGS
#	Restarts cron twice in the fall.
#
TIMEZONE=US/Central
LEADTIME=1			# number of minutes of lead time
TMP=/tmp/.dst$$
PATH=/usr/bin:/usr/ucb:/usr/etc

# return month number for a given month name
monthnum() {
	case "$1" in
	Jan) echo 01;;
	Feb) echo 02;;
	Mar) echo 03;;
	Apr) echo 04;;
	May) echo 05;;
	Jun) echo 06;;
	Jul) echo 07;;
	Aug) echo 08;;
	Sep) echo 09;;
	Oct) echo 10;;
	Nov) echo 11;;
	Dec) echo 12;;
	esac
}

# compare two dates of the form "MMM YY HH:MM:SS YYYY" and
# return <0 if date1 < date2, 0 if date1 = date2, >0 if date1 > date2
datecmp() {
	eval `echo "$1" | sed 's/:/ /g' | awk '{printf "mon1=%s day1=%s hr1=%s min1=%s sec1=%s yr1=%s\n",$1,$2,$3,$4,$5,$6}'`
	eval `echo "$2" | sed 's/:/ /g' | awk '{printf "mon2=%s day2=%s hr2=%s min2=%s sec2=%s yr2=%s\n",$1,$2,$3,$4,$5,$6}'`
	diff=`expr $yr1 - $yr2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	mm1=`monthnum $mon1`
	mm2=`monthnum $mon2`
	diff=`expr $mm1 - $mm2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $day1 - $day2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $hr1 - $hr2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $min1 - $min2`
	if [ $diff -ne 0 ]; then
		echo $diff
		return
	fi
	diff=`expr $sec1 - $sec2`
	echo $diff
	return
}

# translate a date of the form "MMM DD HH:MM:SS YYYY" into a
# form suitable for use with the at command.
atdate () {
	eval `echo $* | sed 's/:/ /g' | awk '{printf "mon=%s day=%s hr=%s min=%s sec=%s yr=%s\n",$1,$2,$3,$4,$5,$6}'`
	min=`expr $min - $LEADTIME`
	if [ $min -lt 0 ]; then
		echo "`basename $0`: too much lead time"
	fi
	echo "$hr:$min $mon $day"
}

# get seconds from a date of the form "MMM DD HH:MM:SS YYYY"
seconds() {
	expr "$*" : '.*:..:\(..\) .*'
}

# get DST change data
trap "rm -f $TMP; exit 1" 2 3
zdump -v $TIMEZONE >$TMP

# save the current date for comparison
set `head -1 $TMP`
NOW="$3 $4 $5 $6"
THISYEAR=$6

# look at the DST change data and find the next change
sed -e '1d' -e 's/isdst=//' -e 's/.*= ... //' $TMP | \
while read timeinfo; do
	set $timeinfo

	# speed things up by ignoring old years
	if [ $THISYEAR -gt $4 ]; then
		continue
	fi

	DATE="$1 $2 $3 $4"
	# if this DST change is in the future
	if [ `datecmp "$NOW" "$DATE"` -lt 0 ]; then
		# schedule at job to fix cron and start the cycle all over again
		at `atdate $DATE` <<!
			# sleep for the leadtime we specified to make sure
			# the DST change has occured.  Add seconds before change
			# and a fudge to make sure cron is through processing.
			sleep `expr $LEADTIME \* 60 + \`seconds $DATE\` + 10`
			echo Restarting cron due to DST change
			pid=\`ps ax | grep -w cron | grep -v grep | awk '{print \$1}'\`
			kill \$pid
			cron
			# Start the cycle over again
			echo Scheduling next cron restart
			$0
!
		break
	fi
done


# remove tmp file
rm -f $TMP
@//E*O*F dstcronfix//
chmod u=r,g=r,o=r dstcronfix

exit 0