Re: cron problem daylight/standard

From: Jim Knutson (knutson%sw.mcc.com@mcc.com)
Date: Wed Apr 10 1991 - 13:38:19 CDT


Actually, no you don't have to remember this too. Below is a script I
just whipped up which will (hopefully) take care of the problem forever
more. Note that I haven't actually used this except to test that it
actually does what it is supposed to.

# 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 weber.sw.mcc.com!knutson on Wed Apr 10 13:20:51 CDT 1991
# Contents: dstcronfix
 
echo x - dstcronfix
sed 's/^@//' > "dstcronfix" <<'@//E*O*F dstcronfix//'
#!/bin/sh
# @(#)dstcronfix 1.1 4/10/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
# Who knows?
#
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 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 fudge to make sure
                        # cron is through processing.
                        sleep `expr $LEADTIME \* 60 + 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=rwx,g=rx,o=rx dstcronfix
 
exit 0



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:06:12 CDT