diff --git a/NEWS b/NEWS
index 7b0e0b5..f87a363 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,57 @@
News for the tz database
+Unreleased, experimental changes
+
+ Changes affecting future time stamps
+
+ Uruguay will stop observing DST. (Thanks to Steffen Thorsen
+ and Pablo Camargo.)
+
+ Changes affecting past and future time stamps
+
+ Moldova starts and ends DST at 00:00 UTC, not at 01:00 UTC.
+ (Thanks to Roman Tudos.)
+
+ Changes affecting data format and code
+
+ zic's '-y YEARISTYPE' option is no longer documented. The TYPE
+ field of a Rule line should now be '-'; the old values 'even',
+ 'odd', 'uspres', 'nonpres', 'nonuspres' were already undocumented.
+ Although the implementation has not changed, these features do not
+ work in the default installation, they are not used in the data,
+ and they are now considered obsolescent.
+
+ zic now checks that two rules don't take effect at the same time.
+ (Thanks to Jon Skeet and Arthur David Olson.) Constraints on
+ simultaneity are now documented.
+
+ The two characters '%z' in a zone format now stand for the UTC
+ offset, e.g., '-07' for seven hours behind UTC and '+0530' for
+ five hours and thirty minutes ahead. This better supports time
+ zone abbreviations conforming to POSIX.1-2001 and later.
+
+ Changes affecting installed data files
+
+ Comments for America/Halifax and America/Glace_Bay have been improved.
+ (Thanks to Brian Inglis.)
+
+ Data entries have been simplified for Atlantic/Canary, Europe/Simferopol,
+ Europe/Sofia, and Europe/Tallinn. This yields slightly smaller
+ installed data files for Europe/Simferopol and Europe/Tallinn.
+ It does not affect timestamps. (Thanks to Howard Hinnant.)
+
+ Changes affecting code
+
+ zdump and zic no longer warn about valid time zone abbreviations
+ like '-05'.
+
+ Some Visual Studio 2013 warnings have been suppressed.
+ (Thanks to Kees Dekker.)
+
+ Changes affecting documentation
+
+ tz-link.htm mentions Time Zone Database Parser (thanks to Howard Hinnant).
+
Release 2015e - 2015-06-13 10:56:02 -0700
diff --git a/difftime.c b/difftime.c
index 449cdf0..5ee8eec 100644
--- a/difftime.c
+++ b/difftime.c
@@ -8,7 +8,7 @@
#include "private.h" /* for time_t and TYPE_SIGNED */
double ATTRIBUTE_CONST
-difftime(const time_t time1, const time_t time0)
+difftime(time_t time1, time_t time0)
{
/*
** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
diff --git a/europe b/europe
index c64c41b..6449483 100644
--- a/europe
+++ b/europe
@@ -845,7 +845,7 @@ Zone Europe/Sofia 1:33:16 - LMT 1880
1:00 C-Eur CE%sT 1945
1:00 - CET 1945 Apr 2 3:00
2:00 - EET 1979 Mar 31 23:00
- 2:00 Bulg EE%sT 1982 Sep 26 2:00
+ 2:00 Bulg EE%sT 1982 Sep 26 3:00
2:00 C-Eur EE%sT 1991
2:00 E-Eur EE%sT 1997
2:00 EU EE%sT
@@ -1084,7 +1084,7 @@ Zone Europe/Tallinn 1:39:00 - LMT 1880
3:00 Russia MSK/MSD 1989 Mar 26 2:00s
2:00 1:00 EEST 1989 Sep 24 2:00s
2:00 C-Eur EE%sT 1998 Sep 22
- 2:00 EU EE%sT 1999 Nov 1
+ 2:00 EU EE%sT 1999 Oct 31 4:00
2:00 - EET 2002 Feb 21
2:00 EU EE%sT
@@ -1763,6 +1763,18 @@ Zone Europe/Malta 0:58:04 - LMT 1893 Nov 2 0:00s # Valletta
# News from Moldova (in russian):
# http://ru.publika.md/link_317061.html
+# From Roman Tudos (2015-07-02):
+# http://lex.justice.md/index.php?action=view&view=doc&lang=1&id=355077
+# From Paul Eggert (2015-07-01):
+# The abovementioned official link to IGO1445-868/2014 states that
+# 2014-10-26's fallback transition occurred at 03:00 local time. Also,
+# http://www.trm.md/en/social/la-30-martie-vom-trece-la-ora-de-vara
+# says the 2014-03-30 spring-forward transition was at 02:00 local time.
+# Guess that since 1997 Moldova has switched one hour before the EU.
+
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Moldova 1997 max - Mar lastSun 2:00 1:00 S
+Rule Moldova 1997 max - Oct lastSun 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Chisinau 1:55:20 - LMT 1880
@@ -1777,7 +1789,7 @@ Zone Europe/Chisinau 1:55:20 - LMT 1880
2:00 Russia EE%sT 1992
2:00 E-Eur EE%sT 1997
# See Romania commentary for the guessed 1997 transition to EU rules.
- 2:00 EU EE%sT
+ 2:00 Moldova EE%sT
# Monaco
# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
@@ -2364,7 +2376,7 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880
# changed in May.
2:00 E-Eur EE%sT 1994 May
# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
- 3:00 E-Eur MSK/MSD 1996 Mar 31 3:00s
+ 3:00 E-Eur MSK/MSD 1996 Mar 31 0:00s
3:00 1:00 MSD 1996 Oct 27 3:00s
# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
# Assume it happened in March by not changing the clocks.
@@ -2922,7 +2934,7 @@ Zone Africa/Ceuta -0:21:16 - LMT 1901
Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C.
-1:00 - CANT 1946 Sep 30 1:00 # Canaries T
0:00 - WET 1980 Apr 6 0:00s
- 0:00 1:00 WEST 1980 Sep 28 0:00s
+ 0:00 1:00 WEST 1980 Sep 28 1:00u
0:00 EU WE%sT
# IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
# Ignore this for now, as the Canaries are part of the EU.
diff --git a/leap-seconds.list b/leap-seconds.list
old mode 100755
new mode 100644
index 5bac01b..0a0bacb
--- a/leap-seconds.list
+++ b/leap-seconds.list
@@ -199,10 +199,10 @@
# current -- the update time stamp, the data and the name of the file
# will not change.
#
-# Updated through IERS Bulletin C49
-# File expires on: 28 December 2015
+# Updated through IERS Bulletin C50
+# File expires on: 28 June 2016
#
-#@ 3660249600
+#@ 3676060800
#
2272060800 10 # 1 Jan 1972
2287785600 11 # 1 Jul 1972
@@ -246,4 +246,4 @@
# the hash line is also ignored in the
# computation.
#
-#h 45e70fa7 a9df2033 f4a49ab0 ec648273 7b6c22c
+#h 3d037453 3acade76 570bd8f8 be2b8bc9 55ec6fe8
diff --git a/localtime.c b/localtime.c
index 423e13e..cc54ab0 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1464,13 +1464,13 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
}
struct tm *
-localtime(const time_t *const timep)
+localtime(const time_t *timep)
{
return localtime_tzset(timep, &tm, true);
}
struct tm *
-localtime_r(const time_t *const timep, struct tm *tmp)
+localtime_r(const time_t *timep, struct tm *tmp)
{
return localtime_tzset(timep, tmp, false);
}
@@ -1499,7 +1499,7 @@ gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
}
struct tm *
-gmtime(const time_t *const timep)
+gmtime(const time_t *timep)
{
return gmtime_r(timep, &tm);
}
@@ -1509,7 +1509,7 @@ gmtime(const time_t *const timep)
*/
struct tm *
-gmtime_r(const time_t *const timep, struct tm *tmp)
+gmtime_r(const time_t *timep, struct tm *tmp)
{
gmtcheck();
return gmtsub(gmtptr, timep, 0, tmp);
@@ -1518,7 +1518,7 @@ gmtime_r(const time_t *const timep, struct tm *tmp)
#ifdef STD_INSPIRED
struct tm *
-offtime(const time_t *const timep, const long offset)
+offtime(const time_t *timep, long offset)
{
gmtcheck();
return gmtsub(gmtptr, timep, offset, &tm);
@@ -1671,7 +1671,7 @@ timesub(const time_t *const timep, const int_fast32_t offset,
}
char *
-ctime(const time_t *const timep)
+ctime(const time_t *timep)
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
@@ -1684,7 +1684,7 @@ ctime(const time_t *const timep)
}
char *
-ctime_r(const time_t *const timep, char *buf)
+ctime_r(const time_t *timep, char *buf)
{
struct tm mytm;
struct tm *tmp = localtime_r(timep, &mytm);
@@ -2103,7 +2103,7 @@ mktime_z(struct state *sp, struct tm *tmp)
#endif
time_t
-mktime(struct tm *const tmp)
+mktime(struct tm *tmp)
{
time_t t;
int err = lock();
@@ -2120,7 +2120,7 @@ mktime(struct tm *const tmp)
#ifdef STD_INSPIRED
time_t
-timelocal(struct tm *const tmp)
+timelocal(struct tm *tmp)
{
if (tmp != NULL)
tmp->tm_isdst = -1; /* in case it wasn't initialized */
@@ -2128,13 +2128,13 @@ timelocal(struct tm *const tmp)
}
time_t
-timegm(struct tm *const tmp)
+timegm(struct tm *tmp)
{
return timeoff(tmp, 0);
}
time_t
-timeoff(struct tm *const tmp, const long offset)
+timeoff(struct tm *tmp, long offset)
{
if (tmp)
tmp->tm_isdst = 0;
diff --git a/northamerica b/northamerica
index 88423e6..873a0f7 100644
--- a/northamerica
+++ b/northamerica
@@ -1235,10 +1235,19 @@ Zone America/Goose_Bay -4:01:40 - LMT 1884 # Happy Valley-Goose Bay
# west Labrador, Nova Scotia, Prince Edward I
-# From Paul Eggert (2006-03-22):
+# From Brian Inglis (2015-07-20):
+# From the historical weather station records available at:
+# https://weatherspark.com/history/28351/1971/Sydney-Nova-Scotia-Canada
+# Sydney shares the same time history as Glace Bay, so was
+# likely to be the same across the island....
+# Sydney, as the capital and most populous location, or Cape Breton, would
+# have been better names for the zone had we known this in 1996.
+
+# From Paul Eggert (2015-07-20):
# Shanks & Pottenger write that since 1970 most of this region has been like
# Halifax. Many locales did not observe peacetime DST until 1972;
-# Glace Bay, NS is the largest that we know of.
+# the Cape Breton area, represented by Glace Bay, is the largest we know of
+# (Glace Bay was perhaps not the best name choice but no point changing now).
# Shanks & Pottenger also write that Liverpool, NS was the only town
# in Canada to observe DST in 1971 but not 1970; for now we'll assume
# this is a typo.
diff --git a/southamerica b/southamerica
index 6bbc2c8..dcc063f 100644
--- a/southamerica
+++ b/southamerica
@@ -1713,8 +1713,19 @@ Rule Uruguay 2005 only - Oct 9 2:00 1:00 S
Rule Uruguay 2006 only - Mar 12 2:00 0 -
# From Jesper Nørgaard Welen (2006-09-06):
# http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
-Rule Uruguay 2006 max - Oct Sun>=1 2:00 1:00 S
-Rule Uruguay 2007 max - Mar Sun>=8 2:00 0 -
+#
+# From Steffen Thorsen (2015-06-30):
+# ... it looks like they will not be using DST the coming summer:
+# http://www.elobservador.com.uy/gobierno-resolvio-que-no-habra-cambio-horario-verano-n656787
+# http://www.republica.com.uy/este-ano-no-se-modificara-el-huso-horario-en-uruguay/523760/
+# From Paul Eggert (2015-06-30):
+# Apparently restaurateurs complained that DST caused people to go to the beach
+# instead of out to dinner.
+# From Pablo Camargo (2015-07-13):
+# http://archivo.presidencia.gub.uy/sci/decretos/2015/06/cons_min_201.pdf
+# [dated 2015-06-29; repeals Decree 311/006 dated 2006-09-04]
+Rule Uruguay 2006 2014 - Oct Sun>=1 2:00 1:00 S
+Rule Uruguay 2007 2015 - Mar Sun>=8 2:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Montevideo -3:44:44 - LMT 1898 Jun 28
-3:44:44 - MMT 1920 May 1 # Montevideo MT
diff --git a/strftime.c b/strftime.c
index 632f395..c01ce19 100644
--- a/strftime.c
+++ b/strftime.c
@@ -117,8 +117,7 @@ strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
#endif
size_t
-strftime(char * const s, const size_t maxsize, const char *const format,
- const struct tm *const t)
+strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
{
char * p;
int warn;
@@ -149,8 +148,8 @@ strftime(char * const s, const size_t maxsize, const char *const format,
}
static char *
-_fmt(const char *format, const struct tm *const t, char * pt,
- const char *const ptlim, int *warnp)
+_fmt(const char *format, const struct tm *t, char *pt,
+ const char *ptlim, int *warnp)
{
for ( ; *format; ++format) {
if (*format == '%') {
@@ -562,8 +561,7 @@ label:
}
static char *
-_conv(const int n, const char *const format, char *const pt,
- const char *const ptlim)
+_conv(int n, const char *format, char *pt, const char *ptlim)
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
@@ -572,7 +570,7 @@ _conv(const int n, const char *const format, char *const pt,
}
static char *
-_add(const char *str, char *pt, const char *const ptlim)
+_add(const char *str, char *pt, const char *ptlim)
{
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
diff --git a/tz-link.htm b/tz-link.htm
index 242be84..85d71f2 100644
--- a/tz-link.htm
+++ b/tz-link.htm
@@ -8,7 +8,7 @@
-
+
Sources for Time Zone and Daylight Saving Time Data
The tz database
-The public-domain
+The public-domain
time zone database contains code and data
that represent the history of local time
for many representative locations around the globe.
It is updated periodically to reflect changes made by political bodies
-to time zone
+to time zone
boundaries and
-daylight-saving
+daylight-saving
rules.
This database (often called zoneinfo or
tz)
@@ -36,27 +36,27 @@ including
the
GNU
C Library (used in
-GNU/Linux),
+GNU/Linux),
Android,
Firefox
OS,
FreeBSD,
NetBSD,
-OpenBSD,
+OpenBSD,
Cygwin,
DJGPP,
-MINIX,
-MINIX,
+webOS,
AIX,
-BlackBerry 10,
+BlackBerry 10,
iOS,
Microsoft Windows,
-OpenOpenVMS,
Oracle Database,
Oracle Solaris, and
@@ -78,19 +78,19 @@ and other entries represent smaller regions like Starke County,
Indiana, which switched from central to eastern time in 1991
and switched back in 2006.
To use the database on an extended POSIX
implementation set the TZ
environment variable to the location's full name,
e.g., TZ="America/New_York".
Associated with each region is a history of offsets from
-Universal
+Universal
Time (UT), which is Greenwich Mean
+href="https://en.wikipedia.org/wiki/Greenwich_Mean_Time">Greenwich Mean
Time (GMT) with days beginning at midnight;
for time stamps after 1960 this is more precisely Coordinated
+href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">Coordinated
Universal Time (UTC).
The database also records when daylight saving time was in use,
along with alphabetic time zone abbreviations such as EST
@@ -113,7 +113,7 @@ code and
latest data revisions
are also available.
The following shell commands download
+href="https://en.wikipedia.org/wiki/Unix_shell">shell commands download
these files to a GNU/Linux or similar host;
see the downloaded
README file for what to do next.
@@ -158,7 +158,7 @@ Here are some links that may be of interest.
Commentary on the tz database
- The article
-tz database is
+tz database is
an encyclopedic summary.
- How to Read the
tz Database Source Files explains the
tz
@@ -186,11 +186,8 @@ Converter
uses a pulldown menu.
- Complete
timezone information for all countries displays tables of DST rules.
-
- The World Clock –
+
- The World Clock –
Time Zones lets you sort zone names and convert times.
-- Permatime generates and views
-links that refer to a particular point in time and can be displayed in
-multiple time zones.
- Time Difference
calculates the current time difference between locations.
- Weather Now lists the weather too.
@@ -251,7 +248,7 @@ data converted from tz.
Other tz compilers
- Vzic is a C
+href="https://en.wikipedia.org/wiki/C_%28programming_language%29">C
program that compiles
tz source into iCalendar-compatible VTIMEZONE files.
Vzic is freely
@@ -259,9 +256,9 @@ available under the GNU
General Public License (GPL).
-- tziCal – tz
+
- tziCal – tz
database conversion utility is like Vzic, except for the .NET framework
+href="https://msdn.microsoft.com/netframework">.NET framework
and with a BSD-style license.
- DateTime::TimeZone
@@ -273,9 +270,15 @@ available under both the GPL and the Perl Artistic
License. DateTime::TimeZone also contains a script
tests_from_zdump that generates test cases for each clock
transition in the tz database.
-- International Components for
+
- The Time Zone
+Database Parser is a
+C++ parser and
+runtime library. It is freely available under the
+Creative Commons
+Attribution 4.0 International Public License.
+- International Components for
Unicode (ICU) contains C/C++ and Java
+href="https://en.wikipedia.org/wiki/Java_%28programming_language%29">Java
libraries for internationalization that
has a compiler from tz source
and from CLDR data
@@ -299,7 +302,7 @@ are similar to Joda Time, but for the .NET framework instead of
Java. They are freely available under the
Apache License
and a BSD-style license, respectively.
-- JavaScript-based
+
- JavaScript-based
compilers and libraries include:
- Moment Timezone is a
@@ -321,11 +324,11 @@ It is freely available under a BSD-style license.
- TZInfo –
Ruby Timezone Library
compiles
tz source into
-Ruby.
+Ruby.
It is freely available under the MIT license.
- The Chronos Date/Time
Library is
-a Smalltalk class
+a Smalltalk class
library that compiles
tz source into a time
zone repository whose format
is either proprietary or an XML-encoded
@@ -348,7 +351,7 @@ This library is freely available under the
GNU Lesser General Public License
(LGPL),
and is widely used in GNU/Linux systems.
-- GNOME's Glib has
+
- GNOME's Glib has
a
tz binary file reader written in C that
creates a GTimeZone object representing sets
of UT offsets.
@@ -382,7 +385,7 @@ available under a BSD-style license.
Other tz-based time zone software
- FoxClocks
-is an extension for Google
+is an extension for Google
Chrome and for Mozilla
Toolkit applications like GPL.
- Microsoft Windows 8.1
and later has
tz data and CLDR
data (mentioned below) used by
-Windows Runtime
+Windows Runtime
classes such as DateTimeFormatter.
+href="https://msdn.microsoft.com/en-us/library/windows/apps/windows.globalization.datetimeformatting.datetimeformatter.aspx">DateTimeFormatter.
Exploring
Windows Time Zones with System.TimeZoneInfo describes
the older, proprietary method of Microsoft Windows 2000 and later,
which stores time zone data in the
-Windows Registry. The
+Windows Registry. The
Zone →
Tzid table or Astro Computing Services.
These atlases are extensive but unreliable, as Shanks appears to have
guessed many UT offsets and transitions. The atlases cite no
sources and do not indicate which entries are guesswork.
-- HP-UX has a database in
+
- HP-UX has a database in
its own
tztab(4) format.
- Microsoft Windows has proprietary data mentioned above.
-- World Time Server
+
- World Time Server
is another time zone database.
- World Time Zones
contains data from the Time Service Department of the
@@ -479,13 +482,14 @@ recent editions.
The pictorial quality is good,
but the maps do not indicate summer time,
and parts of the data are a few years out of date.
-- Current time around the world
+
- Current time around the world
and standard time zones map of the world
has several fancy time zone maps; it covers Russia particularly well.
The maps' pictorial quality is not quite as good as the
CIA's
but the maps are more up to date.
-- How
+
- How
much is time wrong around the world? maps the difference between
mean solar and standard time, highlighting areas such as western China
where the two differ greatly. It's a bit out of date, unfortunately.
@@ -494,7 +498,7 @@ where the two differ greatly. It's a bit out of date, unfortunately.
of
sets of tz regions.
- The latlong package
maps geographical coordinates to a
tz region.
@@ -517,7 +521,7 @@ world time zone boundaries distributed under the
href="http://spatialnews.geocomm.com/features/timezones/">International
Time Zones and Time Zone Data.
- A ship within the territorial
+href="https://en.wikipedia.org/wiki/Territorial_waters">territorial
waters of any nation uses that nation's time. In international
waters, time zone boundaries are meridians 15° apart, except that
UTC−12 and UTC+12 are each 7.5°
@@ -619,6 +623,10 @@ with perhaps the best-documented history of clock adjustments.
The National Physical Laboratory also maintains an Archive
of Summer time dates.
+
- United States
+- The Department of Transportation's Recent
+Time Zone Proceedings lists changes to time zone boundaries.
Precision timekeeping
@@ -640,7 +648,7 @@ href="http://tools.ietf.org/html/rfc4833">Timezone
Options for DHCP
(Internet RFC 4833)
specifies a DHCP
+href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP
option for a server to configure
a client's time zone and daylight saving settings automatically.
- A Few Facts
@@ -661,7 +669,7 @@ title="International Astronomical Union">IAU's SOFA
collection contains C and Fortran
+href="https://en.wikipedia.org/wiki/Fortran">Fortran
code for converting among time scales like
TAI,
TDB, TDT and
@@ -773,13 +781,9 @@ any future changes to the rules. One should never set
local time is nine hours ahead of UTC and the time zone
is called "GMT".
-Related indexes
+See also
diff --git a/zdump.c b/zdump.c
index adb806c..64ff6ce 100644
--- a/zdump.c
+++ b/zdump.c
@@ -269,6 +269,9 @@ static void show(timezone_t, char *, time_t, bool);
static const char *tformat(void);
static time_t yeartot(intmax_t) ATTRIBUTE_PURE;
+/* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
/* Is A an alphabetic character in the C locale? */
static bool
is_alpha(char a)
@@ -485,25 +488,16 @@ abbrok(const char *const abbrp, const char *const zone)
if (warned)
return;
cp = abbrp;
- wp = NULL;
- while (is_alpha(*cp))
+ while (is_alpha(*cp) || is_digit(*cp) || *cp == '-' || *cp == '+')
++cp;
- if (cp - abbrp == 0)
- wp = _("lacks alphabetic at start");
- else if (cp - abbrp < 3)
- wp = _("has fewer than 3 alphabetics");
+ if (cp - abbrp < 3)
+ wp = _("has fewer than 3 characters");
else if (cp - abbrp > 6)
- wp = _("has more than 6 alphabetics");
- if (wp == NULL && (*cp == '+' || *cp == '-')) {
- ++cp;
- if ('0' <= *cp && *cp <= '9')
- if (*cp++ == '1' && '0' <= *cp && *cp <= '4')
- cp++;
- if (*cp != '\0')
- wp = _("differs from POSIX standard");
- }
- if (wp == NULL)
- return;
+ wp = _("has more than 6 characters");
+ else if (*cp)
+ wp = _("has characters other than ASCII alphanumerics, '-' or '+'");
+ else
+ return;
fflush(stdout);
fprintf(stderr,
_("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"),
diff --git a/zic.8 b/zic.8
index b8aaa42..94b6753 100644
--- a/zic.8
+++ b/zic.8
@@ -119,13 +119,6 @@ or that starts with
Limit time values stored in output files to values that are the same
whether they're taken to be signed or unsigned.
You can use this option to generate SVVS-compatible files.
-.TP
-.BI "\*-y " command
-Use the given
-.I command
-rather than
-.B yearistype
-when checking year types (see below).
.PP
Input files should be text files, that is, they should be a series of
zero or more lines, each ending in a newline byte and containing at
@@ -203,27 +196,11 @@ may be used to repeat the value of the
field.
.TP
.B TYPE
-Gives the type of year in which the rule applies.
-If
-.B TYPE
-is
+should be
.q \*-
-then the rule applies in all years between
-.B FROM
-and
-.B TO
-inclusive.
-If
-.B TYPE
-is something else, then
+and is present for compatibility with older versions of
.I zic
-executes the command
-.ti +.5i
-\fByearistype\fP \fIyear\fP \fItype\fP
-.br
-to check the type of a year:
-an exit status of zero is taken to mean that the year is of the given type;
-an exit status of one is taken to mean that the year is not of the given type.
+in which it could contain year types.
.TP
.B IN
Names the month in which the rule takes effect.
@@ -299,6 +276,12 @@ field
and
.B s
suffixes are not used).
+Only the sum of standard time and this amount matters; for example,
+.I zic
+does not distinguish a 10:30 standard time plus an 0:30
+.B SAVE
+from a 10:00 standard time plus a 1:00
+.BR SAVE .
.TP
.B LETTER/S
Gives the
@@ -357,6 +340,8 @@ alternately, an amount of time to add to local standard time.
If this field is
.B \*-
then standard time always applies in the time zone.
+When an amount of time is given, only the sum of standard time and
+this amount matters.
.TP
.B FORMAT
The format for time zone abbreviations in this time zone.
@@ -365,9 +350,24 @@ The pair of characters
is used to show where the
.q "variable part"
of the time zone abbreviation goes.
+Alternately, a format can use the pair of characters
+.B %z
+to stand for the UTC offset in the form
+.RI \(+- hh ,
+.RI \(+- hhmm ,
+or
+.RI \(+- hhmmss ,
+using the shortest form that does not lose information, where
+.IR hh ,
+.IR mm ,
+and
+.I ss
+are the hours, minutes, and seconds east (+) or west (\(mi) of UTC.
Alternately,
a slash (/)
separates standard and daylight abbreviations.
+To conform to POSIX, a time zone abbreviation should contain only
+alphanumeric ASCII characters, "+" and "\*-".
.TP
.B UNTILYEAR [MONTH [DAY [TIME]]]
The time at which the UT offset or the rule(s) change for a location.
@@ -394,6 +394,11 @@ Continuation lines may contain
information, just as zone lines do, indicating that the next line is a further
continuation.
.PP
+If a zone changes at the same instant that a rule would otherwise take
+effect in the earlier zone or continuation line, the rule is ignored.
+In a single zone it is an error if two rules take effect at the same
+instant, or if two zone changes take effect at the same instant.
+.PP
A link line has the form
.sp
.nf
diff --git a/zic.c b/zic.c
index f51fc48..3c4ae93 100644
--- a/zic.c
+++ b/zic.c
@@ -76,6 +76,7 @@ struct zone {
zic_t z_gmtoff;
const char * z_rule;
const char * z_format;
+ char z_format_specifier;
zic_t z_stdoff;
@@ -130,6 +131,9 @@ static void rulesub(struct rule * rp,
static zic_t tadd(zic_t t1, zic_t t2);
static bool yearistype(int year, const char * type);
+/* Bound on length of what %z can expand to. */
+enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
+
static int charcnt;
static bool errors;
static bool warnings;
@@ -139,7 +143,7 @@ static bool leapseen;
static zic_t leapminyear;
static zic_t leapmaxyear;
static int linenum;
-static int max_abbrvar_len;
+static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
static int max_format_len;
static zic_t max_year;
static zic_t min_year;
@@ -493,7 +497,7 @@ usage(FILE *stream, int status)
fprintf(stream,
_("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
"\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
- "\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\n"
+ "\t[ -L leapseconds ] [ filename ... ]\n\n"
"Report bugs to %s.\n"),
progname, progname, REPORT_BUGS_TO);
if (status == EXIT_SUCCESS)
@@ -955,7 +959,7 @@ associate(void)
** Note, though, that if there's no rule,
** a '%s' in the format is a bad thing.
*/
- if (strchr(zp->z_format, '%') != 0)
+ if (zp->z_format_specifier == 's')
error("%s", _("%s in ruleless zone"));
}
}
@@ -1170,6 +1174,7 @@ static bool
inzsub(char **fields, int nfields, bool iscont)
{
register char * cp;
+ char * cp1;
static struct zone z;
register int i_gmtoff, i_rule, i_format;
register int i_untilyear, i_untilmonth;
@@ -1201,13 +1206,21 @@ inzsub(char **fields, int nfields, bool iscont)
z.z_linenum = linenum;
z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
if ((cp = strchr(fields[i_format], '%')) != 0) {
- if (*++cp != 's' || strchr(cp, '%') != 0) {
+ if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
+ || strchr(fields[i_format], '/')) {
error(_("invalid abbreviation format"));
return false;
}
}
z.z_rule = ecpyalloc(fields[i_rule]);
- z.z_format = ecpyalloc(fields[i_format]);
+ z.z_format = cp1 = ecpyalloc(fields[i_format]);
+ z.z_format_specifier = cp ? *cp : '\0';
+ if (z.z_format_specifier == 'z') {
+ if (noise)
+ warning(_("format '%s' not handled by pre-2015 versions of zic"),
+ z.z_format);
+ cp1[cp - fields[i_format]] = 's';
+ }
if (max_format_len < strlen(z.z_format))
max_format_len = strlen(z.z_format);
hasuntil = nfields > i_untilyear;
@@ -1890,19 +1903,59 @@ writezone(const char *const name, const char *const string, char version)
free(fullname);
}
+static char const *
+abbroffset(char *buf, zic_t offset)
+{
+ char sign = '+';
+ int seconds, minutes;
+
+ if (offset < 0) {
+ offset = -offset;
+ sign = '-';
+ }
+
+ seconds = offset % SECSPERMIN;
+ offset /= SECSPERMIN;
+ minutes = offset % MINSPERHOUR;
+ offset /= MINSPERHOUR;
+ if (100 <= offset) {
+ error(_("%%z UTC offset magnitude exceeds 99:59:59"));
+ return "%z";
+ } else {
+ char *p = buf;
+ *p++ = sign;
+ *p++ = '0' + offset / 10;
+ *p++ = '0' + offset % 10;
+ if (minutes | seconds) {
+ *p++ = '0' + minutes / 10;
+ *p++ = '0' + minutes % 10;
+ if (seconds) {
+ *p++ = '0' + seconds / 10;
+ *p++ = '0' + seconds % 10;
+ }
+ }
+ *p = '\0';
+ return buf;
+ }
+}
+
static size_t
-doabbr(char *const abbr, const char *const format, const char *const letters,
+doabbr(char *abbr, struct zone const *zp, char const *letters,
bool isdst, bool doquotes)
{
register char * cp;
register char * slashp;
register size_t len;
+ char const *format = zp->z_format;
slashp = strchr(format, '/');
if (slashp == NULL) {
- if (letters == NULL)
- strcpy(abbr, format);
- else sprintf(abbr, format, letters);
+ char letterbuf[PERCENT_Z_LEN_BOUND + 1];
+ if (zp->z_format_specifier == 'z')
+ letters = abbroffset(letterbuf, -zp->z_gmtoff);
+ else if (!letters)
+ letters = "%s";
+ sprintf(abbr, format, letters);
} else if (isdst) {
strcpy(abbr, slashp + 1);
} else {
@@ -2127,7 +2180,7 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
return -1;
abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
- len = doabbr(result, zp->z_format, abbrvar, false, true);
+ len = doabbr(result, zp, abbrvar, false, true);
offsetlen = stringoffset(result + len, -zp->z_gmtoff);
if (! offsetlen) {
result[0] = '\0';
@@ -2136,7 +2189,7 @@ stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
len += offsetlen;
if (dstrp == NULL)
return compat;
- len += doabbr(result + len, zp->z_format, dstrp->r_abbrvar, true, true);
+ len += doabbr(result + len, zp, dstrp->r_abbrvar, true, true);
if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
offsetlen = stringoffset(result + len,
-(zp->z_gmtoff + dstrp->r_stdoff));
@@ -2307,8 +2360,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
startoff = zp->z_gmtoff;
if (zp->z_nrules == 0) {
stdoff = zp->z_stdoff;
- doabbr(startbuf, zp->z_format,
- NULL, stdoff != 0, false);
+ doabbr(startbuf, zp, NULL, stdoff != 0, false);
type = addtype(oadd(zp->z_gmtoff, stdoff),
startbuf, stdoff != 0, startttisstd,
startttisgmt);
@@ -2375,6 +2427,16 @@ outzone(const struct zone * const zpfirst, const int zonecount)
if (k < 0 || jtime < ktime) {
k = j;
ktime = jtime;
+ } else if (jtime == ktime) {
+ char const *dup_rules_msg =
+ _("two rules for same instant");
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ warning("%s", dup_rules_msg);
+ rp = &zp->z_rules[k];
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ error("%s", dup_rules_msg);
}
}
if (k < 0)
@@ -2390,7 +2452,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
if (ktime < starttime) {
startoff = oadd(zp->z_gmtoff,
stdoff);
- doabbr(startbuf, zp->z_format,
+ doabbr(startbuf, zp,
rp->r_abbrvar,
rp->r_stdoff != 0,
false);
@@ -2400,7 +2462,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
startoff == oadd(zp->z_gmtoff,
stdoff)) {
doabbr(startbuf,
- zp->z_format,
+ zp,
rp->r_abbrvar,
rp->r_stdoff !=
false,
@@ -2409,7 +2471,7 @@ outzone(const struct zone * const zpfirst, const int zonecount)
}
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
- doabbr(ab, zp->z_format, rp->r_abbrvar,
+ doabbr(ab, zp, rp->r_abbrvar,
rp->r_stdoff != 0, false);
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
type = addtype(offset, ab, rp->r_stdoff != 0,
@@ -2893,27 +2955,15 @@ newabbr(const char *const string)
register const char * cp;
const char * mp;
- /*
- ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
- ** optionally followed by a + or - and a number from 1 to 14.
- */
cp = string;
mp = NULL;
- while (is_alpha(*cp))
+ while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
+ || *cp == '-' || *cp == '+')
++cp;
- if (cp - string == 0)
-mp = _("time zone abbreviation lacks alphabetic at start");
if (noise && cp - string < 3)
-mp = _("time zone abbreviation has fewer than 3 alphabetics");
+ mp = _("time zone abbreviation has fewer than 3 characters");
if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
-mp = _("time zone abbreviation has too many alphabetics");
- if (mp == NULL && (*cp == '+' || *cp == '-')) {
- ++cp;
- if (is_digit(*cp))
- if (*cp++ == '1' &&
- *cp >= '0' && *cp <= '4')
- ++cp;
- }
+ mp = _("time zone abbreviation has too many characters");
if (*cp != '\0')
mp = _("time zone abbreviation differs from POSIX standard");
if (mp != NULL)
diff --git a/zone.tab b/zone.tab
index f418e7f..381f245 100644
--- a/zone.tab
+++ b/zone.tab
@@ -106,8 +106,8 @@ BW -2439+02555 Africa/Gaborone
BY +5354+02734 Europe/Minsk
BZ +1730-08812 America/Belize
CA +4734-05243 America/St_Johns Newfoundland Time, including SE Labrador
-CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (most places), PEI
-CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971
+CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (peninsula), PEI
+CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia (Cape Breton)
CA +4606-06447 America/Moncton Atlantic Time - New Brunswick
CA +5320-06025 America/Goose_Bay Atlantic Time - Labrador - most locations
CA +5125-05707 America/Blanc-Sablon Atlantic Standard Time - Quebec - Lower North Shore
diff --git a/zone1970.tab b/zone1970.tab
index 2689c00..c9d31d9 100644
--- a/zone1970.tab
+++ b/zone1970.tab
@@ -103,8 +103,8 @@ BT +2728+08939 Asia/Thimphu
BY +5354+02734 Europe/Minsk
BZ +1730-08812 America/Belize
CA +4734-05243 America/St_Johns Newfoundland Time, including SE Labrador
-CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (most places), PEI
-CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971
+CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (peninsula), PEI
+CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia (Cape Breton)
CA +4606-06447 America/Moncton Atlantic Time - New Brunswick
CA +5320-06025 America/Goose_Bay Atlantic Time - Labrador - most locations
CA +5125-05707 America/Blanc-Sablon Atlantic Standard Time - Quebec - Lower North Shore