Index: timezone/pgtz.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/timezone/pgtz.c,v
retrieving revision 1.20
diff -c -r1.20 pgtz.c
*** timezone/pgtz.c	30 Jul 2004 17:31:24 -0000	1.20
--- timezone/pgtz.c	30 Jul 2004 20:43:08 -0000
***************
*** 43,52 ****
  static char tzdir[MAXPGPATH];
  static int	done_tzdir = 0;

  static void scan_available_timezones(char *tzdir, char *tzdirsub,
  									 struct tztry *tt,
  									 int *bestscore, char *bestzonename);
!

  /*
   * Return full pathname of timezone data directory
--- 43,54 ----
  static char tzdir[MAXPGPATH];
  static int	done_tzdir = 0;

+ #ifndef WIN32
+
  static void scan_available_timezones(char *tzdir, char *tzdirsub,
  									 struct tztry *tt,
  									 int *bestscore, char *bestzonename);
! #endif

  /*
   * Return full pathname of timezone data directory
***************
*** 64,69 ****
--- 66,73 ----
  	return tzdir;
  }

+ #ifndef WIN32
+
  /*
   * Get GMT offset from a system struct tm
   */
***************
*** 84,115 ****
  }

  /*
-  * Grotty kluge for win32 ... do we really need this?
-  */
- #ifdef WIN32
- #define TZABBREV(tz) win32_get_timezone_abbrev(tz)
-
- static char *
- win32_get_timezone_abbrev(const char *tz)
- {
- 	static char w32tzabbr[TZ_STRLEN_MAX + 1];
- 	int			l = 0;
- 	const char  *c;
-
- 	for (c = tz; *c; c++)
- 	{
- 		if (isupper((unsigned char) *c))
- 			w32tzabbr[l++] = *c;
- 	}
- 	w32tzabbr[l] = '\0';
- 	return w32tzabbr;
- }
-
- #else
- #define TZABBREV(tz) (tz)
- #endif
-
- /*
   * Convenience subroutine to convert y/m/d to time_t (NOT pg_time_t)
   */
  static time_t
--- 88,93 ----
***************
*** 210,216 ****
  				return -1;		/* probably shouldn't happen */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */
! 			if (strcmp(TZABBREV(cbuf), pgtm->tm_zone) != 0)
  			{
  				elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
  					 tzname, i, (long) pgtt,
--- 188,194 ----
  				return -1;		/* probably shouldn't happen */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */
! 			if (strcmp(cbuf, pgtm->tm_zone) != 0)
  			{
  				elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
  					 tzname, i, (long) pgtt,
***************
*** 320,326 ****
  			/* found STD zone */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
! 			strcpy(std_zone_name, TZABBREV(cbuf));
  			std_ofs = get_timezone_offset(tm);
  		}
  		if (tm->tm_isdst > 0 && dst_zone_name[0] == '\0')
--- 298,304 ----
  			/* found STD zone */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
! 			strcpy(std_zone_name, cbuf);
  			std_ofs = get_timezone_offset(tm);
  		}
  		if (tm->tm_isdst > 0 && dst_zone_name[0] == '\0')
***************
*** 328,334 ****
  			/* found DST zone */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
! 			strcpy(dst_zone_name, TZABBREV(cbuf));
  		}
  		/* Done if found both */
  		if (std_zone_name[0] && dst_zone_name[0])
--- 306,312 ----
  			/* found DST zone */
  			memset(cbuf, 0, sizeof(cbuf));
  			strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
! 			strcpy(dst_zone_name, cbuf);
  		}
  		/* Done if found both */
  		if (std_zone_name[0] && dst_zone_name[0])
***************
*** 424,436 ****
  		direntry = readdir(dirdesc);
  		if (!direntry)
  		{
- #ifdef WIN32
- 			/* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4),
- 			 * but not in released version
- 			 */
- 			if (GetLastError() == ERROR_NO_MORE_FILES)
- 				errno = 0;
- #endif
  			if (errno)
  				ereport(LOG,
  						(errcode_for_file_access(),
--- 402,407 ----
***************
*** 478,483 ****
--- 449,585 ----
  	tzdir[tzdir_orig_len] = '\0';
  }

+ #else
+ /*
+  * Win32 native knowledge about timezones appear to be too incomplete
+  * and too different from our TZ library to be of any use. But there is
+  * a limited number of timezones available, so we create a mapping
+  * table instead.
+  */
+ const struct {
+ 	const char *stdname;  /* Windows name of standard timezone */
+ 	const char *dstname;  /* Windows name of daylight timezone */
+ 	const char *pgtzname; /* Name of pgsql timezone to map to */
+ } win32_tzmap[] = {
+ 	/*
+ 	 * This list is built from the contents of the registry at
+ 	 *  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
+ 	 * on a Windows XP Professional SP1
+ 	 * The zones have been matched to pg timezones by looking at the cities listed
+ 	 * in the win32 display name (in the comment here) in most cases.
+ 	 */
+ 	{"Afghanistan Standard Time","Afghanistan Daylight Time","Asia/Kabul"}, /* (GMT+04:30) Kabul */
+ 	{"Alaskan Standard Time","Alaskan Daylight Time","US/Alaska"}, /* (GMT-09:00) Alaska */
+ 	{"Arab Standard Time","Arab Daylight Time","Asia/Kuwait"}, /* (GMT+03:00) Kuwait, Riyadh */
+ 	{"Arabian Standard Time","Arabian Daylight Time","Asia/Muscat"}, /* (GMT+04:00) Abu Dhabi, Muscat */
+ 	{"Arabic Standard Time","Arabic Daylight Time","Asia/Baghdad"}, /* (GMT+03:00) Baghdad */
+ 	{"Atlantic Standard Time","Atlantic Daylight Time","Canada/Atlantic"}, /* (GMT-04:00) Atlantic Time (Canada) */
+ 	{"AUS Central Standard Time","AUS Central Daylight Time","Australia/Darwin"}, /* (GMT+09:30) Darwin */
+ 	{"AUS Eastern Standard Time","AUS Eastern Daylight Time","Australia/Canberra"}, /* (GMT+10:00) Canberra, Melbourne, Sydney */
+ 	{"Azores Standard Time","Azores Daylight Time","Atlantic/Azores"}, /* (GMT-01:00) Azores */
+ 	{"Canada Central Standard Time","Canada Central Daylight Time","Canada/Saskatchewan"}, /* (GMT-06:00) Saskatchewan */
+ 	{"Cape Verde Standard Time","Cape Verde Daylight Time","Atlantic/Cape_Verde"}, /* (GMT-01:00) Cape Verde Is. */
+ 	{"Caucasus Standard Time","Caucasus Daylight Time","Asia/Baku"}, /* (GMT+04:00) Baku, Tbilisi, Yerevan */
+ 	{"Cen. Australia Standard Time","Cen. Australia Daylight Time","Australia/Adelaide"}, /* (GMT+09:30) Adelaide */
+ 	{"Central America Standard Time","Central America Daylight Time","CST6CDT"}, /* (GMT-06:00) Central America */
+ 	{"Central Asia Standard Time","Central Asia Daylight Time","Asia/Dhaka"}, /* (GMT+06:00) Astana, Dhaka */
+ 	{"Central Europe Standard Time","Central Europe Daylight Time","Europe/Belgrade"}, /* (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
+ 	{"Central European Standard Time","Central European Daylight Time","Europe/Sarajevo"}, /* (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */
+ 	{"Central Pacific Standard Time","Central Pacific Daylight Time","Pacific/Noumea"}, /* (GMT+11:00) Magadan, Solomon Is., New Caledonia */
+ 	{"Central Standard Time","Central Daylight Time","US/Central"}, /* (GMT-06:00) Central Time (US & Canada) */
+ 	{"China Standard Time","China Daylight Time","Asia/Hong_Kong"}, /* (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
+ 	{"Dateline Standard Time","Dateline Daylight Time","Etc/GMT+12"}, /* (GMT-12:00) International Date Line West */
+ 	{"E. Africa Standard Time","E. Africa Daylight Time","Africa/Nairobi"}, /* (GMT+03:00) Nairobi */
+ 	{"E. Australia Standard Time","E. Australia Daylight Time","Australia/Brisbane"}, /* (GMT+10:00) Brisbane */
+ 	{"E. Europe Standard Time","E. Europe Daylight Time","Europe/Bucharest"}, /* (GMT+02:00) Bucharest */
+ 	{"E. South America Standard Time","E. South America Daylight Time","America/Araguaina"}, /* (GMT-03:00) Brasilia */
+ 	{"Eastern Standard Time","Eastern Daylight Time","US/Eastern"}, /* (GMT-05:00) Eastern Time (US & Canada) */
+ 	{"Egypt Standard Time","Egypt Daylight Time","Africa/Cairo"}, /* (GMT+02:00) Cairo */
+ 	{"Ekaterinburg Standard Time","Ekaterinburg Daylight Time","Asia/Yekaterinburg"}, /* (GMT+05:00) Ekaterinburg */
+ 	{"Fiji Standard Time","Fiji Daylight Time","Pacific/Fiji"}, /* (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
+ 	{"FLE Standard Time","FLE Daylight Time","Europe/Helsinki"}, /* (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */
+ 	{"GMT Standard Time","GMT Daylight Time","Europe/Dublin"}, /* (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
+ 	{"Greenland Standard Time","Greenland Daylight Time","America/Godthab"}, /* (GMT-03:00) Greenland */
+ 	{"Greenwich Standard Time","Greenwich Daylight Time","Africa/Casablanca"}, /* (GMT) Casablanca, Monrovia */
+ 	{"GTB Standard Time","GTB Daylight Time","Europe/Athens"}, /* (GMT+02:00) Athens, Istanbul, Minsk */
+ 	{"Hawaiian Standard Time","Hawaiian Daylight Time","US/Hawaii"}, /* (GMT-10:00) Hawaii */
+ 	{"India Standard Time","India Daylight Time","Asia/Calcutta"}, /* (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */
+ 	{"Iran Standard Time","Iran Daylight Time","Asia/Tehran"}, /* (GMT+03:30) Tehran */
+ 	{"Jerusalem Standard Time","Jerusalem Daylight Time","Asia/Jerusalem"}, /* (GMT+02:00) Jerusalem */
+ 	{"Korea Standard Time","Korea Daylight Time","Asia/Seoul"}, /* (GMT+09:00) Seoul */
+ 	{"Mexico Standard Time","Mexico Daylight Time","America/Mexico_City"}, /* (GMT-06:00) Guadalajara, Mexico City, Monterrey */
+ 	{"Mexico Standard Time","Mexico Daylight Time","America/La_Paz"}, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan */
+ 	{"Mid-Atlantic Standard Time","Mid-Atlantic Daylight Time","Atlantic/South_Georgia"}, /* (GMT-02:00) Mid-Atlantic */
+ 	{"Mountain Standard Time","Mountain Daylight Time","US/Mountain"}, /* (GMT-07:00) Mountain Time (US & Canada) */
+ 	{"Myanmar Standard Time","Myanmar Daylight Time","Asia/Rangoon"}, /* (GMT+06:30) Rangoon */
+ 	{"N. Central Asia Standard Time","N. Central Asia Daylight Time","Asia/Almaty"}, /* (GMT+06:00) Almaty, Novosibirsk */
+ 	{"Nepal Standard Time","Nepal Daylight Time","Asia/Katmandu"}, /* (GMT+05:45) Kathmandu */
+ 	{"New Zealand Standard Time","New Zealand Daylight Time","Pacific/Auckland"}, /* (GMT+12:00) Auckland, Wellington */
+ 	{"Newfoundland Standard Time","Newfoundland Daylight Time","Canada/Newfoundland"}, /* (GMT-03:30) Newfoundland */
+ 	{"North Asia East Standard Time","North Asia East Daylight Time","Asia/Irkutsk"}, /* (GMT+08:00) Irkutsk, Ulaan Bataar */
+ 	{"North Asia Standard Time","North Asia Daylight Time","Asia/Krasnoyarsk"}, /* (GMT+07:00) Krasnoyarsk */
+ 	{"Pacific SA Standard Time","Pacific SA Daylight Time","America/Santiago"}, /* (GMT-04:00) Santiago */
+ 	{"Pacific Standard Time","Pacific Daylight Time","US/Pacific"}, /* (GMT-08:00) Pacific Time (US & Canada); Tijuana */
+ 	{"Romance Standard Time","Romance Daylight Time","Europe/Brussels"}, /* (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
+ 	{"Russian Standard Time","Russian Daylight Time","Europe/Moscow"}, /* (GMT+03:00) Moscow, St. Petersburg, Volgograd */
+ 	{"SA Eastern Standard Time","SA Eastern Daylight Time","America/Buenos_Aires"}, /* (GMT-03:00) Buenos Aires, Georgetown */
+ 	{"SA Pacific Standard Time","SA Pacific Daylight Time","America/Bogota"}, /* (GMT-05:00) Bogota, Lima, Quito */
+ 	{"SA Western Standard Time","SA Western Daylight Time","America/Caracas"}, /* (GMT-04:00) Caracas, La Paz */
+ 	{"Samoa Standard Time","Samoa Daylight Time","Pacific/Midway"}, /* (GMT-11:00) Midway Island, Samoa */
+ 	{"SE Asia Standard Time","SE Asia Daylight Time","Asia/Bangkok"}, /* (GMT+07:00) Bangkok, Hanoi, Jakarta */
+ 	{"Malay Peninsula Standard Time","Malay Peninsula Daylight Time","Asia/Kuala_Lumpur"}, /* (GMT+08:00) Kuala Lumpur, Singapore */
+ 	{"South Africa Standard Time","South Africa Daylight Time","Africa/Harare"}, /* (GMT+02:00) Harare, Pretoria */
+ 	{"Sri Lanka Standard Time","Sri Lanka Daylight Time","Asia/Colombo"}, /* (GMT+06:00) Sri Jayawardenepura */
+ 	{"Taipei Standard Time","Taipei Daylight Time","Asia/Taipei"}, /* (GMT+08:00) Taipei */
+ 	{"Tasmania Standard Time","Tasmania Daylight Time","Australia/Hobart"}, /* (GMT+10:00) Hobart */
+ 	{"Tokyo Standard Time","Tokyo Daylight Time","Asia/Tokyo"}, /* (GMT+09:00) Osaka, Sapporo, Tokyo */
+ 	{"Tonga Standard Time","Tonga Daylight Time","Pacific/Tongatapu"}, /* (GMT+13:00) Nuku'alofa */
+ 	{"US Eastern Standard Time","US Eastern Daylight Time","US/Eastern"}, /* (GMT-05:00) Indiana (East) */
+ 	{"US Mountain Standard Time","US Mountain Daylight Time","US/Arizona"}, /* (GMT-07:00) Arizona */
+ 	{"Vladivostok Standard Time","Vladivostok Daylight Time","Asia/Vladivostok"}, /* (GMT+10:00) Vladivostok */
+ 	{"W. Australia Standard Time","W. Australia Daylight Time","Australia/Perth"}, /* (GMT+08:00) Perth */
+ /*	{"W. Central Africa Standard Time","W. Central Africa Daylight Time",""}, Could not find a match for this one. Excluded for now. */  /* (GMT+01:00) West Central Africa */
+ 	{"W. Europe Standard Time","W. Europe Daylight Time","CET"}, /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
+ 	{"West Asia Standard Time","West Asia Daylight Time","Asia/Karachi"}, /* (GMT+05:00) Islamabad, Karachi, Tashkent */
+ 	{"West Pacific Standard Time","West Pacific Daylight Time","Pacific/Guam"}, /* (GMT+10:00) Guam, Port Moresby */
+ 	{"Yakutsk Standard Time","Yakutsk Daylight Time","Asia/Yakutsk"}, /* (GMT+09:00) Yakutsk */
+ 	{NULL, NULL, NULL }};
+
+ static char *
+ identify_system_timezone(void)
+ {
+ 	int i;
+ 	char tzname[128];
+ 	time_t t = time(NULL);
+ 	struct tm *tm = localtime(&t);
+
+ 	if (!tm)
+ 	{
+ 		ereport(WARNING,
+ 				(errmsg_internal("Unable to determine current date/time!")));
+ 		return NULL;
+ 	}
+
+ 	ZeroMemory(tzname,sizeof(tzname));
+ 	strftime(tzname, sizeof(tzname)-1, "%Z", tm);
+
+ 	for (i=0; win32_tzmap[i].stdname != NULL; i++)
+ 	{
+ 		if (!strcmp(tzname, win32_tzmap[i].stdname) ||
+ 			!strcmp(tzname, win32_tzmap[i].dstname))
+ 		{
+ 			elog(DEBUG4, "TZ \"%s\" matches win32 timezone \"%s\"", win32_tzmap[i].pgtzname, tzname);
+ 			return (char *)win32_tzmap[i].pgtzname;
+ 		}
+ 	}
+
+ 	ereport(WARNING,
+ 			(errmsg_internal("Unable to locate system timezone in the win32 system timeszone map!")));
+ 
+ 	return NULL;
+ }
+ 
+ #endif /* WIN32 */
  
  /*
   * Check whether timezone is acceptable.
