about summary refs log tree commit diff
path: root/time
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-09-09 12:44:00 +0000
committerUlrich Drepper <drepper@redhat.com>1997-09-09 12:44:00 +0000
commit5b9f9e328d8c1f4c9ea2a5d4b2d54dc5aed6d276 (patch)
tree9dbe3fcadea812f8eaaed4e05af0aaf11cb39b31 /time
parent801c353ac5392a1ff6749a3ea1ef1fe619cbc25d (diff)
downloadglibc-5b9f9e328d8c1f4c9ea2a5d4b2d54dc5aed6d276.tar.gz
glibc-5b9f9e328d8c1f4c9ea2a5d4b2d54dc5aed6d276.tar.xz
glibc-5b9f9e328d8c1f4c9ea2a5d4b2d54dc5aed6d276.zip
Update
Diffstat (limited to 'time')
-rw-r--r--time/README4
-rw-r--r--time/africa81
-rw-r--r--time/europe44
-rw-r--r--time/gmtime.c29
-rw-r--r--time/iso3166.tab4
-rw-r--r--time/localtime.c99
-rw-r--r--time/northamerica7
-rw-r--r--time/southamerica6
-rw-r--r--time/strftime.c1
-rw-r--r--time/tzfile.c26
-rw-r--r--time/tzset.c107
-rw-r--r--time/zone.tab2
12 files changed, 165 insertions, 245 deletions
diff --git a/time/README b/time/README
index 99d14db152..c189555c40 100644
--- a/time/README
+++ b/time/README
@@ -3,7 +3,7 @@ The source files
 	`zdump.c'
 	`tzselect.ksh'
 	`checktab.awk'
-come from the tzcode1997a package by Arthur David Olsen et.al.
+come from the tzcode1997g package by Arthur David Olsen et.al.
 
 The files
 	`africa'
@@ -25,4 +25,4 @@ The files
 	`zone.tab'
 	`leapseconds'
 	`yearistype'
-come from the tzdata1997a package by Arthur David Olsen et.al.
+come from the tzdata1997h package by Arthur David Olsen et.al.
diff --git a/time/africa b/time/africa
index 2ea89bd5e0..5c9608ceaa 100644
--- a/time/africa
+++ b/time/africa
@@ -1,4 +1,4 @@
-# @(#)africa	7.18
+# @(#)africa	7.19
 
 # This data is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
@@ -27,85 +27,6 @@
 # Derek Howse, Greenwich time and the discovery of the longitude,
 # Oxford University Press (1980).
 #
-# I added so many Zone names that the old, mostly flat name space was unwieldy.
-# So I renamed the Zones to have the form AREA/LOCATION, where
-# AREA is the name of a continent or ocean, and
-# LOCATION is the name of a specific location within that region.
-# For example, the old zone name `Egypt' is now `Africa/Cairo'.
-#
-# Here are the general rules I used for choosing location names,
-# in decreasing order of importance:
-#
-#	Use only valid Posix file names.  Use only Ascii letters, digits, `.',
-#		`-' and `_'.  Do not exceed 14 characters or start with `-'.
-#		E.g. prefer `Brunei' to `Bandar_Seri_Begawan'.
-#	Include at least one location per time zone rule set per country.
-#		One such location is enough.
-#	If all the clocks in a country's region have agreed since 1970,
-#		don't bother to include more than one location
-#		even if subregions' clocks disagreed before 1970.
-#		Otherwise these tables would become annoyingly large.
-#	If a name is ambiguous, use a less ambiguous alternative;
-#		e.g. many cities are named San Jose and Georgetown, so
-#		prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'.
-#	Keep locations compact.  Use cities or small islands, not countries
-#		or regions, so that any future time zone changes do not split
-#		locations into different time zones.  E.g. prefer `Paris'
-#		to `France', since France has had multiple time zones.
-#	Use traditional English spelling, e.g. prefer `Rome' to `Roma', and
-#		prefer `Athens' to the true name (which uses Greek letters).
-#		The Posix file name restrictions encourage this rule.
-#	Use the most populous among locations in a country's time zone,
-#		e.g. prefer `Shanghai' to `Beijing'.  Among locations with
-#		similar populations, pick the best-known location,
-#		e.g. prefer `Rome' to `Milan'.
-#	Use the singular form, e.g. prefer `Canary' to `Canaries'.
-#	Omit common suffixes like `_Islands' and `_City', unless that
-#		would lead to ambiguity.  E.g. prefer `Cayman' to
-#		`Cayman_Islands' and `Guatemala' to `Guatemala_City',
-#		but prefer `Mexico_City' to `Mexico' because the country
-#		of Mexico has several time zones.
-#	Use `_' to represent a space.
-#	Omit `.' from abbreviations in names, e.g. prefer `St_Helena'
-#		to `St._Helena'.
-#
-# For time zone abbreviations like `EST' I used the following rules,
-# in decreasing order of importance:
-#
-#	Use abbreviations that consist of 3 or more upper-case Ascii letters,
-#		except use "___" for locations while uninhabited.
-#		Posix.1 requires at least 3 characters, and the restriction to
-#		upper-case Ascii letters follows most traditions.
-#		Previous editions of this database also used characters like
-#		' ' and '?', but these characters have a special meaning to
-#		the shell and cause commands like
-#			set `date`
-#		to have unexpected effects.  In theory, the character set could
-#		be !%./@A-Z^_a-z{}, but these tables use only upper-case
-#		Ascii letters (and "___").
-#	Use abbreviations that are in common use among English-speakers,
-#		e.g. `EST' for Eastern Standard Time in North America.
-#		We assume that applications translate them to other languages
-#		as part of the normal localization process; for example,
-#		a French application might translate `EST' to `HNE'.
-#	For zones whose times are taken from a city's longitude, use the
-#		traditional xMT notation, e.g. `PMT' for Paris Mean Time.
-#		The only name like this in current use is `GMT'.
-#	If there is no common English abbreviation, abbreviate the English
-#		translation of the usual phrase used by native speakers.
-#		If this is not available or is a phrase mentioning the country
-#		(e.g. ``Cape Verde Time''), then:
-#
-#		When a country has a single or principal time zone region,
-#			append `T' to the country's ISO	code, e.g. `CVT' for
-#			Cape Verde Time.  For summer time append `ST';
-#			for double summer time append `DST'; etc.
-#		When a country has multiple time zones, take the first three
-#			letters of an English place name identifying each zone
-#			and then append `T', `ST', etc. as before;
-#			e.g. `MOSST' for MOScow Summer Time.
-#
-#
 # For Africa I invented the following time zone abbreviations.
 #		LMT	Local Mean Time
 #	-1:00	AAT	Atlantic Africa Time (no longer used)
diff --git a/time/europe b/time/europe
index c011424bdc..2948ba1caf 100644
--- a/time/europe
+++ b/time/europe
@@ -1,4 +1,4 @@
-# @(#)europe	7.45
+# @(#)europe	7.46
 
 # This data is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
@@ -630,18 +630,18 @@
 # came into force on 16 November.  It restates the dates from the EC
 # seventh Summer Time Directive....
 #
-# From Peter Ilieve <peter@aldie.co.uk> (1997-03-28):
-# The [European] Transport Council discussed the proposed Eighth Directive
-# on 11 March and agreed [to] it, so it moves forward to the next stage,
-# from a Commission proposal to a Common Position....  What this means is:
-#
-# - The eighth directive proposal rules have been accepted.
-#   These are the same as the current rules (last Sunday in March and last
-#   Sunday in October).  The rules will run until 2001.
-#
-# - The French have had their request to abandon summer time turned down.
-#   They have been promised some sort of review in 1999 which might change
-#   the rules for 2000 and 2001.
+# From Peter Ilieve <peter@aldie.co.uk> (1997-08-06):
+# I now have a copy of the ... Eighth Directive 97/44/EC of the European
+# Parliament and of the Council of 22 July 1997 on summer-time arrangements.
+# It runs for 4 years, 1998--2001, and confirms the current rules of
+# last Sunday in March to last Sunday in October....
+# The directive does not apply in overseas territories of the Member States.
+# It says the Commission should produce a proposal for 2002 and beyond
+# by 1 Jan 2000 and this should be adopted by 1 Jan 2001.  I doubt that
+# this will happen though....
+# There is no mention of the French desire to abandon the whole idea.
+# France has had a change of government recently so maybe it will
+# be quietly dropped.
 
 # From Peter Ilieve <peter@memex.co.uk> (1994-03-28):
 # The [GB-Eire] end date of 22 October [1995] conflicts with your current rule
@@ -667,12 +667,12 @@
 # Also, for lack of other data, we'll follow Shanks for Eire in 1940-1948.
 #
 # Given Peter Ilieve's comments, the following claims by Shanks are incorrect:
-#     * Wales did not switch from GMT to daylight savings time until
+#     * Wales did not switch from GMT to daylight saving time until
 #	1921 Apr 3, when they began to conform with the rest of Great Britain.
 # Actually, Wales was identical after 1880.
 #     * Eire had two transitions on 1916 Oct 1.
 # It actually just had one transition.
-#     * Northern Ireland used single daylight savings time throughout WW II.
+#     * Northern Ireland used single daylight saving time throughout WW II.
 # Actually, it conformed to Britain.
 #     * GB-Eire changed standard time to 1 hour ahead of GMT on 1968-02-18.
 # Actually, that date saw the usual switch to summer time.
@@ -681,7 +681,7 @@
 # The following claims by Shanks are possible though doubtful;
 # we'll ignore them for now.
 #     * Jersey, Guernsey, and the Isle of Man did not switch from GMT
-#	to daylight savings time until 1921 Apr 3, when they began to
+#	to daylight saving time until 1921 Apr 3, when they began to
 #	conform with Great Britain.
 #     * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
 #
@@ -1047,7 +1047,7 @@ Zone	Europe/Sarajevo	1:13:40	-	LMT	1884
 			1:00	-	CET	1941 Apr 18 23:00
 			1:00	C-Eur	CE%sT	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
-			1:00	-	CET	1982 Oct 11
+			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 
 # Bulgaria
@@ -1073,7 +1073,7 @@ Zone	Europe/Zagreb	1:03:52	-	LMT	1884
 			1:00	-	CET	1941 Apr 18 23:00
 			1:00	C-Eur	CE%sT	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
-			1:00	-	CET	1982 Oct 11
+			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 
 # Czech Republic
@@ -1572,7 +1572,7 @@ Zone	Europe/Skopje	1:25:44	-	LMT	1884
 			1:00	-	CET	1941 Apr 18 23:00
 			1:00	C-Eur	CE%sT	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
-			1:00	-	CET	1982 Oct 11
+			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 
 # Malta
@@ -1968,7 +1968,7 @@ Zone Europe/Ljubljana	0:58:04	-	LMT	1884
 			1:00	-	CET	1941 Apr 18 23:00
 			1:00	C-Eur	CE%sT	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
-			1:00	-	CET	1982 Oct 11
+			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 
 # Spain
@@ -2209,9 +2209,9 @@ Zone	Europe/Belgrade	1:22:00	-	LMT	1884
 			1:00	C-Eur	CE%sT	1945 May  8  2:00s
 			1:00	1:00	CEST	1945 Sep 16  2:00s
 # Metod Kozelj <metod.kozelj@rzs-hm.si> reports that the legal date of
-# transition to EU rules was 1982-10-11, for all of Yugoslavia at the time.
+# transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
 # Shanks doesn't give as much detail, so go with Kozelj.
-			1:00	-	CET	1982 Oct 11
+			1:00	-	CET	1982 Nov 27
 			1:00	EU	CE%sT
 
 ###############################################################################
diff --git a/time/gmtime.c b/time/gmtime.c
index f9627e7b62..2b388befb1 100644
--- a/time/gmtime.c
+++ b/time/gmtime.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Convert `time_t' to `struct tm' in UTC.
+   Copyright (C) 1991, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,19 +17,14 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <stddef.h>
 #include <time.h>
 
 /* Defined in localtime.c.  */
 extern struct tm _tmbuf;
 
-/* Return the `struct tm' representation of *T in UTC.	*/
-struct tm *
-gmtime (t)
-     const time_t *t;
-{
-  return __gmtime_r (t, &_tmbuf);
-}
+/* Prototype for the internal function to get information based on TZ.  */
+extern struct tm *__tz_convert __P ((const time_t *t, int use_localtime,
+				     struct tm *tp));
 
 
 /* Return the `struct tm' representation of *T in UTC,
@@ -38,12 +34,15 @@ __gmtime_r (t, tp)
      const time_t *t;
      struct tm *tp;
 {
-  __offtime (t, 0L, tp);
+  return __tz_convert (t, 0, tp);
+}
+weak_alias (__gmtime_r, gmtime_r)
 
-  tp->tm_isdst = 0;
-  tp->tm_gmtoff = 0L;
-  tp->tm_zone = "GMT";
 
-  return tp;
+/* Return the `struct tm' representation of *T in UTC.	*/
+struct tm *
+gmtime (t)
+     const time_t *t;
+{
+  return __tz_convert (t, 0, &_tmbuf);
 }
-weak_alias (__gmtime_r, gmtime_r)
diff --git a/time/iso3166.tab b/time/iso3166.tab
index b5237783c4..6eb4d318db 100644
--- a/time/iso3166.tab
+++ b/time/iso3166.tab
@@ -7,6 +7,9 @@
 # 2.  The usual English name for the country,
 #	chosen so that alphabetic sorting of subsets produces helpful lists.
 #
+# For France in Europe, we follow common practice and use FR,
+# even though FX might be more technically correct.
+#
 # Columns are separated by a single tab.
 # The table is sorted by country code.
 #
@@ -86,6 +89,7 @@ FK	Falkland Islands
 FM	Micronesia
 FO	Faeroe Islands
 FR	France
+FX	France, Metropolitan
 GA	Gabon
 GB	Britain (UK)
 GD	Grenada
diff --git a/time/localtime.c b/time/localtime.c
index ab8fc1ac45..3d8d8fbd10 100644
--- a/time/localtime.c
+++ b/time/localtime.c
@@ -17,106 +17,33 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <errno.h>
 #include <time.h>
-#include <libc-lock.h>
 
 /* The C Standard says that localtime and gmtime return the same pointer.  */
 struct tm _tmbuf;
 
 /* Prototype for the internal function to get information based on TZ.  */
-extern void __tzset_internal __P ((int always));
-extern int __tz_compute __P ((time_t timer, struct tm *tp));
-extern int __tzfile_compute __P ((time_t timer,
-				  long int *leap_correct, int *leap_hit));
+extern struct tm *__tz_convert __P ((const time_t *t, int use_localtime,
+				     struct tm *tp));
 
-extern int __use_tzfile;
 
-/* This lock is defined in tzset.c and locks all the data defined there
-   and in tzfile.c; the internal functions do no locking themselves.
-   This lock is only taken here and in `tzset'.  */
-__libc_lock_define (extern, __tzset_lock)
-
-
-/* Return the `struct tm' representation of *TIMER in the local timezone.  */
-static struct tm *
-localtime_internal (const time_t *timer, struct tm *tp)
-{
-  long int leap_correction;
-  int leap_extra_secs;
-
-  if (timer == NULL)
-    {
-      __set_errno (EINVAL);
-      return NULL;
-    }
-
-  if (__use_tzfile)
-    {
-      if (! __tzfile_compute (*timer, &leap_correction, &leap_extra_secs))
-	tp = NULL;
-    }
-  else
-    {
-      tp = __gmtime_r (timer, tp);
-      if (tp && ! __tz_compute (*timer, tp))
-	tp = NULL;
-      leap_correction = 0L;
-      leap_extra_secs = 0;
-    }
-
-  if (tp)
-    {
-      __offtime (timer, __timezone - leap_correction, tp);
-      tp->tm_sec += leap_extra_secs;
-      tp->tm_isdst = __daylight;
-      tp->tm_gmtoff = __timezone;
-      tp->tm_zone = __tzname[__daylight];
-    }
-
-  return tp;
-}
-
-
-/* POSIX.1 8.3.7.2 says that localtime_r is not required to set
-   tzname.  This is a good idea since this allows at least a bit more
-   parallelism.  */
 
+/* Return the `struct tm' representation of *T in local time,
+   using *TP to store the result.  */
 struct tm *
-localtime (timer)
-     const time_t *timer;
+__localtime_r (t, tp)
+     const time_t *t;
+     struct tm *tp;
 {
-  struct tm *result;
-
-  __libc_lock_lock (__tzset_lock);
-
-  /* Update internal database according to current TZ setting.  */
-  __tzset_internal (1);
-
-  result = localtime_internal (timer, &_tmbuf);
-
-  __libc_lock_unlock (__tzset_lock);
-
-  return result;
+  return __tz_convert (t, 1, tp);
 }
+weak_alias (__localtime_r, localtime_r)
 
 
+/* Return the `struct tm' representation of *T in local time.  */
 struct tm *
-__localtime_r (timer, tp)
-     const time_t *timer;
-     struct tm *tp;
+localtime (t)
+     const time_t *t;
 {
-  struct tm *result;
-
-  __libc_lock_lock (__tzset_lock);
-
-  /* Make sure the database is initialized.  */
-  __tzset_internal (0);
-
-  result = localtime_internal (timer, tp);
-
-  __libc_lock_unlock (__tzset_lock);
-
-  return result;
+  return __tz_convert (t, 1, &_tmbuf);
 }
-weak_alias (__localtime_r, localtime_r)
diff --git a/time/northamerica b/time/northamerica
index b70cb900c0..635c4ef180 100644
--- a/time/northamerica
+++ b/time/northamerica
@@ -1,4 +1,4 @@
-# @(#)northamerica	7.31
+# @(#)northamerica	7.32
 # also includes Central America and the Caribbean
 
 # This data is by no means authoritative; if you think you know better,
@@ -1249,8 +1249,11 @@ Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
 			-4:00	-	AST
 
 # Montserrat
+# From Paul Eggert (1997-08-31):
+# Recent volcanic eruptions have forced evacuation of Plymouth, the capital.
+# Luckily, Olveston, the current de facto capital, has the same longitude.
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
-Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Plymouth
+Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Olveston
 			-4:00	-	AST
 
 # Nicaragua
diff --git a/time/southamerica b/time/southamerica
index 927f71638a..09e0aa6d28 100644
--- a/time/southamerica
+++ b/time/southamerica
@@ -1,4 +1,4 @@
-# @(#)southamerica	7.17
+# @(#)southamerica	7.18
 
 # This data is by no means authoritative; if you think you know better,
 # go ahead and edit the file (and please send any changes to
@@ -533,7 +533,9 @@ Rule	Uruguay	1989	only	-	Mar	12	 0:00	0	-
 Rule	Uruguay	1989	only	-	Oct	29	 0:00	1:00	S
 Rule	Uruguay	1990	1992	-	Mar	Sun>=1	 0:00	0	-
 Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
-Rule	Uruguay	1992	1993	-	Oct	Sun>=15	 0:00	1:00	S
+# Shanks's 4th edition (1995) says no DST was observed in 1990/1 and 1991/2,
+# and that 1992/3's DST was from 10-25 to 03-01.  Go with IATA.
+Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
 Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
diff --git a/time/strftime.c b/time/strftime.c
index 891d301f5c..4ecbc5a519 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -132,7 +132,6 @@ extern char *tzname[];
 #ifdef _LIBC
 # define gmtime_r __gmtime_r
 # define localtime_r __localtime_r
-extern int __tz_compute __P ((time_t timer, const struct tm *tm));
 # define tzname __tzname
 # define tzset __tzset
 #else
diff --git a/time/tzfile.c b/time/tzfile.c
index c90e05749f..9289de63a0 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -43,7 +43,7 @@ struct leap
     long int change;		/* Seconds of correction to apply.  */
   };
 
-extern const char * __tzstring (const char *); /* Defined in tzset.c.  */
+extern char * __tzstring (const char *); /* Defined in tzset.c.  */
 
 static struct ttinfo *find_transition (time_t timer);
 static void compute_tzname_max (size_t);
@@ -411,19 +411,23 @@ find_transition (time_t timer)
 }
 
 int
-__tzfile_compute (time_t timer, long int *leap_correct, int *leap_hit)
+__tzfile_compute (time_t timer, int use_localtime,
+		  long int *leap_correct, int *leap_hit)
 {
-  struct ttinfo *info;
   register size_t i;
 
-  info = find_transition (timer);
-  __daylight = info->isdst;
-  __timezone = info->offset;
-  for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
-       ++i)
-    __tzname[types[i].isdst] = &zone_names[types[i].idx];
-  if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
-    __tzname[info->isdst] = &zone_names[info->idx];
+  if (use_localtime)
+    {
+      struct ttinfo *info = find_transition (timer);
+      __daylight = info->isdst;
+      __timezone = info->offset;
+      for (i = 0;
+	   i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
+	   ++i)
+	__tzname[types[i].isdst] = &zone_names[types[i].idx];
+      if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
+	__tzname[info->isdst] = &zone_names[info->idx];
+    }
 
   *leap_correct = 0L;
   *leap_hit = 0;
diff --git a/time/tzset.c b/time/tzset.c
index 979a33b069..6ec4e15a86 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -17,7 +17,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <ctype.h>
-#include <libc-lock.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -27,15 +28,19 @@
 /* Defined in mktime.c.  */
 extern const unsigned short int __mon_yday[2][13];
 
+/* Defined in localtime.c.  */
+extern struct tm _tmbuf;
+
 #define NOID
 #include "tzfile.h"
 
 extern int __use_tzfile;
 extern void __tzfile_read __P ((const char *file));
+extern int __tzfile_compute __P ((time_t timer, int use_localtime,
+				  long int *leap_correct, int *leap_hit));
 extern void __tzfile_default __P ((const char *std, const char *dst,
 				   long int stdoff, long int dstoff));
-extern const char * __tzstring __P ((const char *string));
-extern int __tz_compute __P ((time_t timer, const struct tm *tm));
+extern char * __tzstring __P ((const char *string));
 
 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
 int __daylight = 0;
@@ -78,6 +83,8 @@ static tz_rule tz_rules[2];
 
 
 static int compute_change __P ((tz_rule *rule, int year));
+static int tz_compute __P ((time_t timer, const struct tm *tm));
+static void tzset_internal __P ((int always));
 
 /* Header for a list of buffers containing time zone strings.  */
 struct tzstring_head
@@ -102,7 +109,7 @@ static size_t tzstring_last_buffer_size = sizeof tzstring_list.data;
 /* Allocate a time zone string with given contents.
    The string will never be moved or deallocated.
    However, its contents may be shared with other such strings.  */
-const char *
+char *
 __tzstring (string)
      const char *string;
 {
@@ -113,7 +120,7 @@ __tzstring (string)
   /* Look through time zone string list for a duplicate of this one.  */
   for (h = &tzstring_list.head;  ;  h = h->next)
     {
-      for (p = (char *) (h + 1);  p[0] | p[1];  p++)
+      for (p = (char *) (h + 1);  p[0] | p[1];  ++p)
 	if (strcmp (p, string) == 0)
 	  return p;
       if (! h->next)
@@ -122,7 +129,7 @@ __tzstring (string)
 
   /* No duplicate was found.  Copy to the end of this buffer if there's room;
      otherwise, append a large-enough new buffer to the list and use it.  */
-  p++;
+  ++p;
   needed = strlen (string) + 2; /* Need 2 trailing '\0's after last string.  */
 
   if ((size_t) ((char *) (h + 1) + tzstring_last_buffer_size - p) < needed)
@@ -137,16 +144,14 @@ __tzstring (string)
       p = (char *) (h + 1);
     }
 
-  strncpy (p, string, needed);
-  return p;
+  return strncpy (p, string, needed);
 }
 
 static char *old_tz = NULL;
 
 /* Interpret the TZ envariable.  */
-void __tzset_internal __P ((int always));
-void
-__tzset_internal (always)
+static void
+tzset_internal (always)
      int always;
 {
   static int is_initialized = 0;
@@ -338,12 +343,9 @@ __tzset_internal (always)
     {
       register tz_rule *tzr = &tz_rules[whichrule];
 
-      if (*tz == ',')
-	{
-	  ++tz;
-	  if (*tz == '\0')
-	    return;
-	}
+      /* Ignore comma to support string following the incorrect
+	 specification in early POSIX.1 printings.  */
+      tz += *tz == ',';
 
       /* Get the date of the change.  */
       if (*tz == 'J' || isdigit (*tz))
@@ -436,7 +438,7 @@ __tzname_max ()
 {
   __libc_lock_lock (tzset_lock);
 
-  __tzset_internal (0);
+  tzset_internal (0);
 
   __libc_lock_unlock (tzset_lock);
 
@@ -531,13 +533,11 @@ compute_change (rule, year)
 /* Figure out the correct timezone for *TIMER and TM (which must be the same)
    and set `__tzname', `__timezone', and `__daylight' accordingly.
    Return nonzero on success, zero on failure.  */
-int
-__tz_compute (timer, tm)
+static int
+tz_compute (timer, tm)
      time_t timer;
      const struct tm *tm;
 {
-  __tzset_internal (0);
-
   if (! compute_change (&tz_rules[0], 1900 + tm->tm_year) ||
       ! compute_change (&tz_rules[1], 1900 + tm->tm_year))
     return 0;
@@ -568,7 +568,7 @@ __tzset (void)
 {
   __libc_lock_lock (tzset_lock);
 
-  __tzset_internal (1);
+  tzset_internal (1);
 
   if (!__use_tzfile)
     {
@@ -580,3 +580,64 @@ __tzset (void)
   __libc_lock_unlock (tzset_lock);
 }
 weak_alias (__tzset, tzset)
+
+/* Return the `struct tm' representation of *TIMER in the local timezone.
+   Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
+struct tm *
+__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
+{
+  long int leap_correction;
+  int leap_extra_secs;
+
+  if (timer == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  __libc_lock_lock (tzset_lock);
+
+  /* Update internal database according to current TZ setting.
+     POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
+     This is a good idea since this allows at least a bit more parallelism.
+     By analogy we apply the same rule to gmtime_r.  */
+  tzset_internal (tp == &_tmbuf);
+
+  if (__use_tzfile)
+    {
+      if (! __tzfile_compute (*timer, use_localtime,
+			      &leap_correction, &leap_extra_secs))
+	tp = NULL;
+    }
+  else
+    {
+      __offtime (timer, 0, tp);
+      if (! tz_compute (*timer, tp))
+	tp = NULL;
+      leap_correction = 0L;
+      leap_extra_secs = 0;
+    }
+
+  if (tp)
+    {
+      if (use_localtime)
+	{
+	  tp->tm_isdst = __daylight;
+	  tp->tm_zone = __tzname[__daylight];
+	  tp->tm_gmtoff = __timezone;
+	}
+      else
+	{
+	  tp->tm_isdst = 0;
+	  tp->tm_zone = "GMT";
+	  tp->tm_gmtoff = 0L;
+	}
+
+      __offtime (timer, tp->tm_gmtoff - leap_correction, tp);
+      tp->tm_sec += leap_extra_secs;
+    }
+
+  __libc_lock_unlock (tzset_lock);
+
+  return tp;
+}
diff --git a/time/zone.tab b/time/zone.tab
index 48b32373cc..df4c157788 100644
--- a/time/zone.tab
+++ b/time/zone.tab
@@ -231,7 +231,7 @@ MO	+2214+11335	Asia/Macao
 MP	+1512+14545	Pacific/Saipan
 MQ	+1436-06105	America/Martinique
 MR	+1806-01557	Africa/Nouakchott
-MS	+1642-06213	America/Montserrat
+MS	+1644-06213	America/Montserrat
 MT	+3554+01431	Europe/Malta
 MU	-2010+05730	Indian/Mauritius
 MV	+0410+07330	Indian/Maldives