*BSD News Article 13876


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!hp9000.csc.cuhk.hk!saimiri.primate.wisc.edu!zaphod.mps.ohio-state.edu!wupost!emory!europa.eng.gtefsd.com!gatech!usenet.ins.cwru.edu!agate!doc.ic.ac.uk!marble.uknet.ac.uk!mcsun!news.funet.fi!fuug!kiae!relcom!newsserv
From: "Andrew A. Chernov, Black Mage" <ache@astral.msk.su>
Newsgroups: comp.os.386bsd.bugs
Subject: Fix 'date' for update kernel zone offset using zoneinfo rules
Date: Wed, 31 Mar 93 00:44:56 +0400
Distribution: world
Organization: Ha-olahm Yetzirah
Message-ID: <DN85Bkhu60@astral.msk.su>
Sender: news-service@newcom.kiae.su
Reply-To: ache@astral.msk.su
Lines: 125

Problem description:

1. MSDOS and SETUP use BIOS clock value as local (wall) clock.
2. 386bsd use BIOS clock value in the same way only if kernel zone offset
and current zoneinfo zone offset (/etc/localtime) are equal.
3. Kernel compiled with constant zone offset and don't know anything
about right time to change to DST and back.
4. When DST change occurs, kernel zone offset and zoneinfo zone offset
are different, so 386bsd show incorrect time (usually, one hour apart
or back). You can modify this time by hand, but in such situation
you obtain incorrect time in MSDOS or SETUP.

Solution:

I add '-Z' key to "date", which update kernel current zone offset
and corresponding time using current zoneinfo rules. You can simple add
	date -Z -n
before starting anything in your /etc/rc and obtain automagically
timezone changes and correct MSDOS and SETUP clock too.

Problem description:

There is '-t' option in "date" to provide forced kernel timezone offset,
but this option works only with positive values (west of GMT),
because getopt() treat all negative (-180 f.e.) arguments as separate
option and produce error.

Solution:

I add '-T' option to "date" to change kernel timezone offset
east of GMT with positive argument converted to negative.

*** date.c.was	Fri Apr  5 05:19:45 1991
--- /usr/src/bin/date/date.c	Tue Mar 30 22:37:58 1993
***************
*** 63,75 ****
  	struct timezone tz;
  	int ch, rflag;
  	char *format, buf[1024];
  
! 	tz.tz_dsttime = tz.tz_minuteswest = 0;
  	rflag = 0;
! 	while ((ch = getopt(argc, argv, "d:nr:ut:")) != EOF)
  		switch((char)ch) {
  		case 'd':		/* daylight savings time */
  			tz.tz_dsttime = atoi(optarg) ? 1 : 0;
  			break;
  		case 'n':		/* don't set network */
  			nflag = 1;
--- 63,78 ----
  	struct timezone tz;
  	int ch, rflag;
  	char *format, buf[1024];
+ 	int force_dst, force_off;
  
! 	force_dst = force_off = 0;
! 	(void)gettimeofday((struct timeval *)NULL, &tz);
  	rflag = 0;
! 	while ((ch = getopt(argc, argv, "d:nr:ut:T:Z")) != EOF)
  		switch((char)ch) {
  		case 'd':		/* daylight savings time */
  			tz.tz_dsttime = atoi(optarg) ? 1 : 0;
+ 			force_dst = 1;
  			break;
  		case 'n':		/* don't set network */
  			nflag = 1;
***************
*** 81,90 ****
--- 84,116 ----
  		case 'u':		/* do everything in GMT */
  			(void)setenv("TZ", "GMT0", 1);
  			break;
+ 		case 'Z': {             /* update kernel offset */
+ 					/* using zoneinfo rules */
+ 				struct tm *tm;
+ 				struct timeval tv;
+ 
+ 				(void)gettimeofday(&tv, (struct timezone *)NULL);
+ 				tm = localtime(&tv.tv_sec);
+ 				tv.tv_sec += -tm->tm_gmtoff - tz.tz_minuteswest*60;
+ 				if (!force_off)
+ 					tz.tz_minuteswest = -tm->tm_gmtoff/60;
+ 				if (!force_dst && tm->tm_isdst)
+ 					tz.tz_dsttime = 1;
+ 				if (settimeofday(&tv, &tz)) {
+ 					perror("date: settimeofday");
+ 					exit(1);
+ 				}
+ 				force_dst = force_off = 0;
+ 			}
+ 			break;
  		case 't':		/* minutes west of GMT */
+ 		case 'T':               /* minutes east of GMT, pay for getopt */
  					/* error check; don't allow "PST" */
  			if (isdigit(*optarg)) {
  				tz.tz_minuteswest = atoi(optarg);
+ 				if (ch == 'T')
+ 					tz.tz_minuteswest = -tz.tz_minuteswest;
+ 				force_off = 1;
  				break;
  			}
  			/* FALLTHROUGH */
***************
*** 98,104 ****
  	 * If -d or -t, set the timezone or daylight savings time; this
  	 * doesn't belong here, there kernel should not know about either.
  	 */
! 	if ((tz.tz_minuteswest || tz.tz_dsttime) &&
  	    settimeofday((struct timeval *)NULL, &tz)) {
  		perror("date: settimeofday");
  		exit(1);
--- 124,130 ----
  	 * If -d or -t, set the timezone or daylight savings time; this
  	 * doesn't belong here, there kernel should not know about either.
  	 */
! 	if ((force_off || force_dst) &&
  	    settimeofday((struct timeval *)NULL, &tz)) {
  		perror("date: settimeofday");
  		exit(1);
-- 
In-This-Life:    Andrew A. Chernov      | "Hay mas dicha, mas contento
Internet:        ache@astral.msk.su     | "Que adorar una hermosura
FIDOnet:         2:5020/23.34           | "Brujuleada entre los lejos
RELCOM Development Team, Moscow, Russia | "De lo imposible?!" (Calderon)