cron und die Zeitumstellung

bananenBrot

Well-Known Member
Hi,

mal eine Frage.

Nehmen wir mal an, ich habe einen Cron-Job, der jede Nacht um 02:15 Uhr ein Script tues.sh aufruft.
Wird dieses Script am kommenden Sonntag morgen laufen?

Nehmen wir jetzt an, es ist ein Cron-Job, der jede Nacht um 02:15 Uhr und um 03:15 Uhr ausgelöst wird.
Wird tues.sh um 03:15 Uhr 2x aufgerufen? (es wird ja kein 02:15 Uhr geben)

Ich bin echt überfragt...
 
Hi,

mal eine Frage.

Nehmen wir mal an, ich habe einen Cron-Job, der jede Nacht um 02:15 Uhr ein Script tues.sh aufruft.
Wird dieses Script am kommenden Sonntag morgen laufen?

Nehmen wir jetzt an, es ist ein Cron-Job, der jede Nacht um 02:15 Uhr und um 03:15 Uhr ausgelöst wird.
Wird tues.sh um 03:15 Uhr 2x aufgerufen? (es wird ja kein 02:15 Uhr geben)

Ich bin echt überfragt...

Das Sript um 02:15 wird laufen. Hier mal der passende Auszug aus cron(8):

Code:
     -s      Enable special handling of situations when the GMT offset of the
             local timezone changes, such as the switches between the standard
             time and daylight saving time.
     
             The jobs run during the GMT offset changes time as intuitively
             expected.  If a job falls into a time interval that disappears
             (for example, during the switch from standard time) to daylight
             saving time or is duplicated (for example, during the reverse
             switch), then it is handled in one of two ways:

             The first case is for the jobs that run every at hour of a time
             interval overlapping with the disappearing or duplicated inter?
             val.  In other words, if the job had run within one hour before
             the GMT offset change (and cron was not restarted nor the
             crontab(5) changed after that) or would run after the change at
             the next hour.  They work as always, skip the skipped time or run
             in the added time as usual.

             The second case is for the jobs that run less frequently.  They
             are executed exactly once, they are not skipped nor executed
             twice (unless cron is restarted or the user's crontab(5) is
             changed during such a time interval).  If an interval disappears
             due to the GMT offset change, such jobs are executed at the same
             absolute point of time as they would be in the old time zone.
             For example, if exactly one hour disappears, this point would be
             during the next hour at the first minute that is specified for
             them in crontab(5).

Bei mir startet Cron auf per Default mit "-s", ohne dass ich das jemals explizit so gesetzt haette. Brauchst dir also keine Sorgen zu machen.
 
Bezogen auf FreeBSD, aber prinzipiell überall anwendbar: Intern wird die Uhr - wie auf allen unixoiden Systemen - in Sekunden seit "The Epoch" am 1.1.1970 angegeben, ist also linear fortlaufend. Die Realzeit für den Benutzer ergibt sich durch einen Übersetzungmechanismus, mittels in den Kernel geladener Zeitzonendateien. Diese Dateien enthalten Dinge wie Schaltsekunden, Schalttage, fehlende Schalttage und halt auch Sommer- und Winterzeitumstellungen. Jede Nacht wird zwischen 0 Uhr und 6 Uhr in der jeweils ersten und 31ten Minute jeder Stunde adjkerntz(1) ("Adjust Kernel Time Zone") ausgeführt und schaut nach, ob die aktuellen Angaben stimmen. Um 2:01 Uhr wird er also erkennen, dass die falsche Zeitzonendefinition geladen ist, dem Kernel die Neue übergeben und damit die Zeit umstellen. Die Zeitumstellung ist sofort wirksam.
Cron schaut nun also nach wie spät es ist. Sieht, dass es 2 Uhr ist und tut nichts. Schaut wieder nach, es ist 3:01 Uhr und nichts passiert. Der erste Job läuft also nicht, der zweite Job um 3:15 Uhr schon. Steht auch in der crontab(5), was man aber zugegeben leicht übersieht:
Code:
    If you are in one of the 70-odd countries that observe Daylight Savings
     Time, jobs scheduled during the rollback or advance will be affected.  In
     general, it is not a good idea to schedule jobs during this period.

     For US timezones (except parts of IN, AZ, and HI) the time shift occurs
     at 2AM local time.  For others, the output of the zdump(8) program's ver‐
     bose (-v) option can be used to determine the moment of time shift.
Da gibt es mehrere Auswege. Der einfachste ist auf Vixie zu hören und dort keine Jobs hinzulegen. Eine andere ist "anachron" zu nutzen, was die beiden übersprungenen Jobs dann um 3:02 Uhr nachholen würde. Die Oracle-Methode ist, Standardgremien zu bearbeiten, um Schaltsekunden, Schalttage und Sommer-Winterzeitumstellungen grundsätzlich abzuschaffen.

EDIT: Nun hat unull mich überholt und rausgefunden, dass sich crontab(5) und cron(8) widersprechen. Im Zweifel würde ich eher ihm Glauben, also vergiss das von mir geschriebene am besten...
 
Also wird in dem Fall das script gestartet, wenn das System 03:15 Uhr zeigt.
Sollte für 03:15 Uhr noch ein cron gesetzt worden sein, wird der nicht ausgeführt.

Ist schon ganz schön nervig diese Sommer/Winterzeitgeschichte

Cron schaut nun also nach wie spät es ist. Sieht, dass es 2 Uhr ist und tut nichts. Schaut wieder nach, es ist 3:01 Uhr und nichts passiert. Der erste Job läuft also nicht, der zweite Job um 3:15 Uhr schon.

Aber das hier sagt doch, dass der 02:15 Uhr Job gerade doch läuft.
If an interval disappears
due to the GMT offset change, such jobs are executed at the same
absolute point of time as they would be in the old time zone.
 
EDIT: Nun hat unull mich überholt und rausgefunden, dass sich crontab(5) und cron(8) widersprechen. Im Zweifel würde ich eher ihm Glauben, also vergiss das von mir geschriebene am besten...

Eventuell wurde hier vergessen, den Bug aus crontab(5) zu tilgen? Die Manpage von cron ist von 2008, die von crontab von 2005.

Ich habe mal einen Bug-Report zu diesem Widerspruch ausgefuellt und mir auch mal "/usr/src/usr.sbin/cron/cron.c" dazu angesehen:

Code:
	if (dst_enabled && last_time != 0 
	&& TargetTime > last_time /* exclude stepping back */
	&& tm->tm_gmtoff != lasttm.tm_gmtoff ) {

		diff = tm->tm_gmtoff - lasttm.tm_gmtoff;

		if ( diff > 0 ) { /* ST->DST */
			/* mark jobs for an earlier run */
			difflimit = TargetTime + diff;
			for (u = db->head;  u != NULL;  u = u->next) {
				for (e = u->crontab;  e != NULL;  e = e->next) {
					e->flags &= ~NOT_UNTIL;
					if ( e->lastrun >= TargetTime )
						e->lastrun = 0;
					/* not include the ends of hourly ranges */
					if ( e->lastrun < TargetTime - 3600 )
						e->flags |= RUN_AT;
					else
						e->flags &= ~RUN_AT;
				}
			}
		} else { /* diff < 0 : DST->ST */
			/* mark jobs for skipping */
			difflimit = TargetTime - diff;
			for (u = db->head;  u != NULL;  u = u->next) {
				for (e = u->crontab;  e != NULL;  e = e->next) {
					e->flags |= NOT_UNTIL;
					e->flags &= ~RUN_AT;
				}
			}
		}
	}

Sieht also tatsaechlich so aus, als ob crontab(5) nicht auf dem aktuellen Stand ist.
 
Ich löse das Problem dadurch meine Rechner in UTC laufen zu lassen und nur für Loginshells der User TZ=$timezone zu setzten.
 
das von unull beschriebene verhalten haben wir hier auch. mir fällt spontan aber auch kein cron ein, der das nicht nach dem genannten verhalten behandelt.
 
Zurück
Oben