Browse Source

added table for time-zone determination

eck 34 years ago
parent
commit
8519a01099
1 changed files with 109 additions and 7 deletions
  1. 109 7
      lang/cem/libcc.ansi/time/misc.c

+ 109 - 7
lang/cem/libcc.ansi/time/misc.c

@@ -44,7 +44,7 @@ void _ftime(struct timeb *bp);
  * right value from the system. TZ is the only help.
  */
 static char ntstr[TZ_LEN + 1] = "GMT";	/* string for normal time */
-static char dststr[TZ_LEN + 1] = "GMT";	/* string for daylight saving */
+static char dststr[TZ_LEN + 1] = "GDT";	/* string for daylight saving */
 
 long	_timezone = 0;
 long	_dst_off = 60 * 60;
@@ -84,6 +84,96 @@ const int _ytab[2][12] = {
 		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 	};
 
+#if	!defined(_POSIX_SOURCE) && !defined(__USG)
+#define	USE_TABLE	1
+#endif
+
+#if	USE_TABLE
+static int usetable = 1;
+
+typedef struct table {
+	const char *tz_name;
+	const int daylight;
+	const long zoneoffset;
+} TABLE;
+
+#define HOUR(x)	((x) * 60*60)
+
+static TABLE TimezoneTable[] = {
+	{"GMT", 0,	HOUR(0) },	/* Greenwich Mean */
+	{"BST", 60*60,	HOUR(0) },	/* British Summer */
+	{"WAT", 0,	HOUR(1) },	/* West Africa */
+	{"AT", 0,	HOUR(2) },	/* Azores */
+	{"BST", 0,	HOUR(3) },	/* Brazil Standard */
+	{"NFT", 0,	HOUR(3.5) },	/* Newfoundland */
+	{"NDT", 60*60,	HOUR(3.5) },	/* Newfoundland Daylight */
+	{"AST", 0,	HOUR(4) },	/* Atlantic Standard */
+	{"ADT", 60*60,	HOUR(4) },	/* Atlantic Daylight */
+	{"EST", 0,	HOUR(5) },	/* Eastern Standard */
+	{"EDT", 60*60,	HOUR(5) },	/* Eastern Daylight */
+	{"CST", 0,	HOUR(6) },	/* Central Standard */
+	{"CDT", 60*60,	HOUR(6) },	/* Central Daylight */
+	{"MST", 0,	HOUR(7) },	/* Mountain Standard */
+	{"MDT", 60*60,	HOUR(7) },	/* Mountain Daylight */
+	{"PST", 0,	HOUR(8) },	/* Pacific Standard */
+	{"PDT", 60*60,	HOUR(8) },	/* Pacific Daylight */
+	{"YST", 0,	HOUR(9) },	/* Yukon Standard */
+	{"YDT", 60*60,	HOUR(9) },	/* Yukon Daylight */
+	{"HST", 0,	HOUR(10) },	/* Hawaii Standard */
+	{"HDT", 60*60,	HOUR(10) },	/* Hawaii Daylight */
+	{"NT", 0,	HOUR(11) },	/* Nome */
+	{"IDLW", 0,	HOUR(12) },	/* International Date Line West */
+	{"MET", 0,	-HOUR(1) },	/* Middle European */
+	{"MDT", 60*60,	-HOUR(1) },	/* Middle European Summer */
+	{"EET", 0,	-HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
+	{"BT", 0,	-HOUR(3) },	/* Baghdad, USSR Zone 2 */
+	{"IT", 0,	-HOUR(3.5) },	/* Iran */
+	{"ZP4", 0,	-HOUR(4) },	/* USSR Zone 3 */
+	{"ZP5", 0,	-HOUR(5) },	/* USSR Zone 4 */
+	{"IST", 0,	-HOUR(5.5) },	/* Indian Standard */
+	{"ZP6", 0,	-HOUR(6) },	/* USSR Zone 5 */
+	{"NST", 0,	-HOUR(6.5) },	/* North Sumatra */
+	{"SST", 0,	-HOUR(7) },	/* South Sumatra, USSR Zone 6 */
+	{"WAST", 0,	-HOUR(7) },	/* West Australian Standard */
+	{"WADT", 60*60,	-HOUR(7) },	/* West Australian Daylight */
+	{"JT", 0,	-HOUR(7.5) },	/* Java (3pm in Cronusland!) */
+	{"CCT", 0,	-HOUR(8) },	/* China Coast, USSR Zone 7 */
+	{"JST", 0,	-HOUR(9) },	/* Japan Standard, USSR Zone 8 */
+	{"CAST", 0,	-HOUR(9.5) },	/* Central Australian Standard */
+	{"CADT", 60*60,	-HOUR(9.5) },	/* Central Australian Daylight */
+	{"EAST", 0,	-HOUR(10) },	/* Eastern Australian Standard */
+	{"EADT", 60*60,	-HOUR(10) },	/* Eastern Australian Daylight */
+	{"NZT", 0,	-HOUR(12) },	/* New Zealand */
+	{"NZDT", 60*60,	-HOUR(12) },	/* New Zealand Daylight */
+	{  NULL, 0, 0  }
+};
+
+/*
+ * The function ZoneFromTable() searches the table for the current
+ * timezone.  It saves the last one found in ntstr or dststr, depending on
+ * wheter the name is for daylight-saving-time or not.
+ * Both ntstr and dststr are TZ_LEN + 1 chars.
+ */
+static void
+ZoneFromTable(long timezone)
+{
+	register TABLE *tptr = TimezoneTable;
+
+	while (tptr->tz_name != NULL) {
+		if (tptr->zoneoffset == timezone) {
+			if (tptr->daylight == 0) {
+				strncpy(ntstr,tptr->tz_name, TZ_LEN);
+				ntstr[TZ_LEN] = '\0';
+			} else {
+				strncpy(dststr,tptr->tz_name, TZ_LEN);
+				dststr[TZ_LEN] = '\0';
+			}
+		}
+		tptr++;
+	}
+}
+#endif	/* USE_TABLE */
+
 static const char *
 parseZoneName(register char *buf, register const char *p)
 {
@@ -233,6 +323,9 @@ parseTZ(const char *p)
 
 	if (!p) return;
 
+#if	USE_TABLE
+	usetable = 0;
+#endif
 	if (*p == ':') {
 		/*
 		 * According to POSIX, this is implementation defined.
@@ -294,7 +387,7 @@ _tzset(void)
 
 	_gettimeofday(&tv, &tz);
 	_daylight = tz.tz_dsttime;
-	_timezone = tz.tz_minuteswest * 60;
+	_timezone = tz.tz_minuteswest * 60L;
 
 #elif	!defined(_POSIX_SOURCE) && !defined(__USG)
 
@@ -357,11 +450,16 @@ date_of(register struct dsttype *dst, struct tm *timep)
 	return day;
 }
 
+/*
+ * The default dst transitions are those for Western Europe (except Great
+ * Britain). 
+ */
 unsigned
 _dstget(register struct tm *timep)
 {
 	int begindst, enddst;
 	register struct dsttype *dsts = &dststart, *dste = &dstend;
+	int do_dst = 0;
 
 	if (_daylight == -1)
 		_tzset();
@@ -379,13 +477,14 @@ _dstget(register struct tm *timep)
 	/* assume begindst != enddst (otherwise it would be no use) */
 	if (begindst < enddst) {		/* northern hemisphere */
 		if (timep->tm_yday > begindst && timep->tm_yday < enddst)
-			return _dst_off;
+			do_dst = 1;
 	} else {				/* southern hemisphere */
 		if (timep->tm_yday > begindst || timep->tm_yday < enddst)
-			return _dst_off;
+			do_dst = 1;
 	}
 
-	if (timep->tm_yday == begindst || timep->tm_yday == enddst) {
+	if (!do_dst
+	    && (timep->tm_yday == begindst || timep->tm_yday == enddst)) {
 		long dsttranssec;	/* transition when day is this old */
 		long cursec;
 
@@ -397,9 +496,12 @@ _dstget(register struct tm *timep)
 
 		if ((timep->tm_yday == begindst && cursec >= dsttranssec)
 		    || (timep->tm_yday == enddst && cursec < dsttranssec))
-			return _dst_off;
+			do_dst = 1;
 	}
+#if USE_TABLE
+	if (usetable) ZoneFromTable(_timezone);
+#endif
+	if (do_dst) return _dst_off;
 	timep->tm_isdst = 0;
-
 	return 0;
 }