Fri Sep 20 19:06:54 2013 UTC ()
Welcome to tzcode 2013e:

  Changes affecting API

    The 'zic' command now outputs a dummy transition when far-future
    data can't be summarized using a TZ string, and uses a 402-year
    window rather than a 400-year window.  For the current data, this
    affects only the Asia/Tehran file.  It does not affect any of the
    time stamps that this file represents, so zdump outputs the same
    information as before.  (Thanks to Andrew Main (Zefram).)

    The 'date' command has a new '-r' option, which lets you specify
    the integer time to display, a la FreeBSD.

    The 'tzselect' command has two new options '-c' and '-n', which lets you
    select a zone based on latitude and longitude.

    The 'zic' command's '-v' option now warns about constructs that
    require the new version-3 binary file format.  (Thanks to Arthur
    David Olson for the suggestion.)

    Support for floating-point time_t has been removed.
    It was always dicey, and POSIX no longer requires it.
    (Thanks to Eric Blake for suggesting to the POSIX committee to
    remove it, and thanks to Alan Barrett, Clive D.W. Feather, Andy
    Heninger, Arthur David Olson, and Alois Treindl, for reporting
    bugs and elucidating some of the corners of the old floating-point
    implementation.)

    The signatures of 'offtime', 'timeoff', and 'gtime' have been
    changed back to the old practice of using 'long' to represent UT
    offsets.  This had been inadvertently and mistakenly changed to
    'int_fast32_t'.  (Thanks to Christos Zoulos.)

    The code avoids undefined behavior on integer overflow in some
    more places, including gmtime, localtime, mktime and zdump.

  Changes affecting the zdump utility

    zdump now outputs "UT" when referring to Universal Time, not "UTC".
    "UTC" does not make sense for time stamps that predate the introduction
    of UTC, whereas "UT", a more-generic term, does.  (Thanks to Steve Allen
    for clarifying UT vs UTC.)

  Data changes affecting behavior of tzselect and similar programs

    Country code BQ is now called the more-common name "Caribbean Netherlands"
    rather than the more-official "Bonaire, St Eustatius & Saba".

    Remove from zone.tab the names America/Montreal, America/Shiprock,
    and Antarctica/South_Pole, as they are equivalent to existing
    same-country-code zones for post-1970 time stamps.  The data for
    these names are unchanged, so the names continue to work as before.

  Changes affecting code internals

    zic -c now runs way faster on 64-bit hosts when given large numbers.

    zic now uses vfprintf to avoid allocating and freeing some memory.

    tzselect now computes the list of continents from the data,
    rather than have it hard-coded.

    Minor changes pacify GCC 4.7.3 and GCC 4.8.1.

  Changes affecting the build procedure

    The 'leapseconds' file is now generated automatically from a
    new file 'leap-seconds.list', which is a copy of
    <ftp://time.nist.gov/pub/leap-seconds.list>.
    A new source file 'leapseconds.awk' implements this.
    The goal is simplification of the future maintenance of 'leapseconds'.

    When building the 'posix' or 'right' subdirectories, if the
    subdirectory would be a copy of the default subdirectory, it is
    now made a symbolic link if that is supported.  This saves about
    2 MB of file system space.

    The links America/Shiprock and Antarctica/South_Pole have been
    moved to the 'backward' file.  This affects only nondefault builds
    that omit 'backward'.

  Changes affecting documentation and commentary

    Changes to the 'tzfile' man page

      It now mentions that the binary file format may be extended in
      future versions by appending data.

      It now refers to the 'zdump' and 'zic' man pages.

    Changes to the 'zic' man page

      It lists conditions that elicit a warning with '-v'.

      It says that the behavior is unspecified when duplicate names
      are given, or if the source of one link is the target of another.

      Its examples are updated to match the latest data.

      The definition of white space has been clarified slightly.
      (Thanks to Michael Deckers.)

    Changes to the 'Theory' file

      There is a new section about the accuracy of the tz database,
      describing the many ways that errors can creep in, and
      explaining why so many of the pre-1970 time stamps are wrong or
      misleading (thanks to Steve Allen, Lester Caine, and Garrett
      Wollman for discussions that contributed to this).

      The 'Theory' file describes LMT better (this follows a
      suggestion by Guy Harris).

      It refers to the 2013 edition of POSIX rather than the 2004 edition.

      It's mentioned that excluding 'backward' should not affect the
      other data, and it suggests at least one zone.tab name per
      inhabited country (thanks to Stephen Colebourne).

      Some longstanding restrictions on names are documented, e.g.,
      'America/New_York' precludes 'America/New_York/Bronx'.

      It gives more reasons for the 1970 cutoff.

      It now mentions which time_t variants are supported, such as
      signed integer time_t.  (Thanks to Paul Goyette for reporting
      typos in an experimental version of this change.)

      (Thanks to Philip Newton for correcting typos in these changes.)

    Documentation and commentary is more careful to distinguish UT in
    general from UTC in particular.  (Thanks to Steve Allen.)

    Add a better source for the Zurich 1894 transition.
    (Thanks to Pierre-Yves Berger.)

    Update shapefile citations in tz-link.htm.  (Thanks to Guy Harris.)


(christos)
diff -r1.14 -r1.15 src/lib/libc/time/Makefile
diff -r1.14 -r1.15 src/lib/libc/time/difftime.c
diff -r1.13 -r1.14 src/lib/libc/time/Theory
diff -r1.5 -r1.6 src/lib/libc/time/checktab.awk
diff -r1.47 -r1.48 src/lib/libc/time/ctime.3
diff -r1.77 -r1.78 src/lib/libc/time/localtime.c
diff -r1.29 -r1.30 src/lib/libc/time/private.h
diff -r1.29 -r1.30 src/lib/libc/time/strftime.3
diff -r1.28 -r1.29 src/lib/libc/time/strftime.c
diff -r1.11 -r1.12 src/lib/libc/time/tz-link.htm
diff -r1.11 -r1.12 src/lib/libc/time/tzfile.h
diff -r1.19 -r1.20 src/lib/libc/time/tzfile.5
diff -r1.4 -r1.5 src/lib/libc/time/tzselect.8
diff -r1.8 -r1.9 src/lib/libc/time/tzselect.ksh
diff -r1.25 -r1.26 src/lib/libc/time/tzset.3
diff -r1.1 -r1.2 src/lib/libc/time/version.h
diff -r1.10 -r1.11 src/lib/libc/time/zdump.8
diff -r1.30 -r1.31 src/lib/libc/time/zdump.c
diff -r1.20 -r1.21 src/lib/libc/time/zic.8
diff -r1.42 -r1.43 src/lib/libc/time/zic.c

cvs diff -r1.14 -r1.15 src/lib/libc/time/Makefile (expand / switch to unified diff)

--- src/lib/libc/time/Makefile 2013/07/17 20:13:04 1.14
+++ src/lib/libc/time/Makefile 2013/09/20 19:06:54 1.15
@@ -1,67 +1,68 @@ @@ -1,67 +1,68 @@
1# <pre> 1# <pre>
2# This file is in the public domain, so clarified as of 2# This file is in the public domain, so clarified as of
3# 2009-05-17 by Arthur David Olson. 3# 2009-05-17 by Arthur David Olson.
4 4
5# Package name for the code distribution. 5# Package name for the code distribution.
6PACKAGE= tzcode 6PACKAGE= tzcode
7 7
8# Version numbers of the code and data distributions. 8# Version numbers of the code and data distributions.
9VERSION= 2013d 9VERSION= 2013e
10 10
11# Email address for bug reports. 11# Email address for bug reports.
12BUGEMAIL= tz@iana.org 12BUGEMAIL= tz@iana.org
13 13
14# Change the line below for your time zone (after finding the zone you want in 14# Change the line below for your time zone (after finding the zone you want in
15# the time zone files, or adding it to a time zone file). 15# the time zone files, or adding it to a time zone file).
16# Alternately, if you discover you've got the wrong time zone, you can just 16# Alternately, if you discover you've got the wrong time zone, you can just
17# zic -l rightzone 17# zic -l rightzone
18# to correct things. 18# to correct things.
19# Use the command 19# Use the command
20# make zonenames 20# make zonenames
21# to get a list of the values you can use for LOCALTIME. 21# to get a list of the values you can use for LOCALTIME.
22 22
23LOCALTIME= GMT 23LOCALTIME= GMT
24 24
25# If you want something other than Eastern United States time as a template 25# If you want something other than Eastern United States time as a template
26# for handling POSIX-style time zone environment variables, 26# for handling POSIX-style time zone environment variables,
27# change the line below (after finding the zone you want in the 27# change the line below (after finding the zone you want in the
28# time zone files, or adding it to a time zone file). 28# time zone files, or adding it to a time zone file).
29# (When a POSIX-style environment variable is handled, the rules in the 29# (When a POSIX-style environment variable is handled, the rules in the
30# template file are used to determine "spring forward" and "fall back" days and 30# template file are used to determine "spring forward" and "fall back" days and
31# times; the environment variable itself specifies UTC offsets of standard and 31# times; the environment variable itself specifies UT offsets of standard and
32# summer time.) 32# summer time.)
33# Alternately, if you discover you've got the wrong time zone, you can just 33# Alternately, if you discover you've got the wrong time zone, you can just
34# zic -p rightzone 34# zic -p rightzone
35# to correct things. 35# to correct things.
36# Use the command 36# Use the command
37# make zonenames 37# make zonenames
38# to get a list of the values you can use for POSIXRULES. 38# to get a list of the values you can use for POSIXRULES.
39# If you want POSIX compatibility, use "America/New_York". 39# If you want POSIX compatibility, use "America/New_York".
40 40
41POSIXRULES= America/New_York 41POSIXRULES= America/New_York
42 42
43# Also see TZDEFRULESTRING below, which takes effect only 43# Also see TZDEFRULESTRING below, which takes effect only
44# if the time zone files cannot be accessed. 44# if the time zone files cannot be accessed.
45 45
46# Everything gets put in subdirectories of. . . 46# Everything gets put in subdirectories of. . .
47 47
48TOPDIR= /usr/local 48TOPDIR= /usr/local
49 49
50# "Compiled" time zone information is placed in the "TZDIR" directory 50# "Compiled" time zone information is placed in the "TZDIR" directory
51# (and subdirectories). 51# (and subdirectories).
52# Use an absolute path name for TZDIR unless you're just testing the software. 52# Use an absolute path name for TZDIR unless you're just testing the software.
53 53
54TZDIR= $(TOPDIR)/etc/zoneinfo 54TZDIR_BASENAME= zoneinfo
 55TZDIR= $(TOPDIR)/etc/$(TZDIR_BASENAME)
55 56
56# Types to try, as an alternative to time_t. int64_t should be first. 57# Types to try, as an alternative to time_t. int64_t should be first.
57TIME_T_ALTERNATIVES= int64_t int32_t uint32_t uint64_t 58TIME_T_ALTERNATIVES= int64_t int32_t uint32_t uint64_t
58 59
59# The "tzselect", "zic", and "zdump" commands get installed in. . . 60# The "tzselect", "zic", and "zdump" commands get installed in. . .
60 61
61ETCDIR= $(TOPDIR)/etc 62ETCDIR= $(TOPDIR)/etc
62 63
63# If you "make INSTALL", the "date" command gets installed in. . . 64# If you "make INSTALL", the "date" command gets installed in. . .
64 65
65BINDIR= $(TOPDIR)/bin 66BINDIR= $(TOPDIR)/bin
66 67
67# Manual pages go in subdirectories of. . . 68# Manual pages go in subdirectories of. . .
@@ -110,27 +111,26 @@ LDLIBS= @@ -110,27 +111,26 @@ LDLIBS=
110# -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4) 111# -DHAVE_SETTIMEOFDAY=1 if settimeofday has just 1 arg (SVR4)
111# -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD) 112# -DHAVE_SETTIMEOFDAY=2 if settimeofday uses 2nd arg (4.3BSD)
112# -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD) 113# -DHAVE_SETTIMEOFDAY=3 if settimeofday ignores 2nd arg (4.4BSD)
113# -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h" 114# -DHAVE_STDINT_H=1 if you have a pre-C99 compiler with "stdint.h"
114# -DHAVE_SYMLINK=0 if your system lacks the symlink function 115# -DHAVE_SYMLINK=0 if your system lacks the symlink function
115# -DHAVE_SYS_STAT_H=0 if your compiler lacks a "sys/stat.h" 116# -DHAVE_SYS_STAT_H=0 if your compiler lacks a "sys/stat.h"
116# -DHAVE_SYS_WAIT_H=0 if your compiler lacks a "sys/wait.h" 117# -DHAVE_SYS_WAIT_H=0 if your compiler lacks a "sys/wait.h"
117# -DHAVE_UNISTD_H=0 if your compiler lacks a "unistd.h" (Microsoft C++ 7?) 118# -DHAVE_UNISTD_H=0 if your compiler lacks a "unistd.h" (Microsoft C++ 7?)
118# -DHAVE_UTMPX_H=1 if your compiler has a "utmpx.h" 119# -DHAVE_UTMPX_H=1 if your compiler has a "utmpx.h"
119# -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale" 120# -DLOCALE_HOME=\"path\" if locales are in "path", not "/usr/lib/locale"
120# -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1 121# -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
121# if you do not want run time warnings about formats that may cause 122# if you do not want run time warnings about formats that may cause
122# year 2000 grief 123# year 2000 grief
123# -DTIME_T_FLOATING=1 if your time_t (or time_tz) is floating point 
124# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t 124# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
125# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz" 125# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
126# -TTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory; 126# -TTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
127# the default is system-supplied, typically "/usr/lib/locale" 127# the default is system-supplied, typically "/usr/lib/locale"
128# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified 128# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
129# -DNO_ERROR_IN_DST_GAP=1 129# -DNO_ERROR_IN_DST_GAP=1
130# if you want mktime() not to return an error in the DST gap. 130# if you want mktime() not to return an error in the DST gap.
131# -DZIC_MAX_ABBR_LEN_WO_WARN=3 131# -DZIC_MAX_ABBR_LEN_WO_WARN=3
132# (or some other number) to set the maximum time zone abbreviation length 132# (or some other number) to set the maximum time zone abbreviation length
133# that zic will accept without a warning (the default is 6) 133# that zic will accept without a warning (the default is 6)
134# $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking 134# $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking
135GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \ 135GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \
136 -Wall -Wextra \ 136 -Wall -Wextra \
@@ -178,27 +178,27 @@ GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-co @@ -178,27 +178,27 @@ GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-co
178# If you want functions that were inspired by early versions of X3J11's work, 178# If you want functions that were inspired by early versions of X3J11's work,
179# add 179# add
180# -DSTD_INSPIRED 180# -DSTD_INSPIRED
181# to the end of the "CFLAGS=" line. This arranges for the functions 181# to the end of the "CFLAGS=" line. This arranges for the functions
182# "tzsetwall", "offtime", "timelocal", "timegm", "timeoff", 182# "tzsetwall", "offtime", "timelocal", "timegm", "timeoff",
183# "posix2time", and "time2posix" to be added to the time conversion library. 183# "posix2time", and "time2posix" to be added to the time conversion library.
184# "tzsetwall" is like "tzset" except that it arranges for local wall clock 184# "tzsetwall" is like "tzset" except that it arranges for local wall clock
185# time (rather than the time specified in the TZ environment variable) 185# time (rather than the time specified in the TZ environment variable)
186# to be used. 186# to be used.
187# "offtime" is like "gmtime" except that it accepts a second (long) argument 187# "offtime" is like "gmtime" except that it accepts a second (long) argument
188# that gives an offset to add to the time_t when converting it. 188# that gives an offset to add to the time_t when converting it.
189# "timelocal" is equivalent to "mktime". 189# "timelocal" is equivalent to "mktime".
190# "timegm" is like "timelocal" except that it turns a struct tm into 190# "timegm" is like "timelocal" except that it turns a struct tm into
191# a time_t using UTC (rather than local time as "timelocal" does). 191# a time_t using UT (rather than local time as "timelocal" does).
192# "timeoff" is like "timegm" except that it accepts a second (long) argument 192# "timeoff" is like "timegm" except that it accepts a second (long) argument
193# that gives an offset to use when converting to a time_t. 193# that gives an offset to use when converting to a time_t.
194# "posix2time" and "time2posix" are described in an included manual page. 194# "posix2time" and "time2posix" are described in an included manual page.
195# X3J11's work does not describe any of these functions. 195# X3J11's work does not describe any of these functions.
196# Sun has provided "tzsetwall", "timelocal", and "timegm" in SunOS 4.0. 196# Sun has provided "tzsetwall", "timelocal", and "timegm" in SunOS 4.0.
197# These functions may well disappear in future releases of the time 197# These functions may well disappear in future releases of the time
198# conversion package. 198# conversion package.
199# 199#
200# If you'll never want to handle solar-time-based time zones, add 200# If you'll never want to handle solar-time-based time zones, add
201# -DNOSOLAR 201# -DNOSOLAR
202# to the end of the "CFLAGS=" line 202# to the end of the "CFLAGS=" line
203# (and comment out the "SDATA=" line below). 203# (and comment out the "SDATA=" line below).
204# This reduces (slightly) the run-time data-space requirements of 204# This reduces (slightly) the run-time data-space requirements of
@@ -232,26 +232,28 @@ GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-co @@ -232,26 +232,28 @@ GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-co
232# before the first Monday in January when a "%V" format is used and January 1 232# before the first Monday in January when a "%V" format is used and January 1
233# falls on a Friday, Saturday, or Sunday. 233# falls on a Friday, Saturday, or Sunday.
234 234
235CFLAGS= 235CFLAGS=
236 236
237# Linker flags. Default to $(LFLAGS) for backwards compatibility 237# Linker flags. Default to $(LFLAGS) for backwards compatibility
238# to tzcode2012h and earlier. 238# to tzcode2012h and earlier.
239 239
240LDFLAGS= $(LFLAGS) 240LDFLAGS= $(LFLAGS)
241 241
242zic= ./zic 242zic= ./zic
243ZIC= $(zic) $(ZFLAGS) 243ZIC= $(zic) $(ZFLAGS)
244 244
 245ZFLAGS=
 246
245# The name of a Posix-compliant `awk' on your system. 247# The name of a Posix-compliant `awk' on your system.
246AWK= awk 248AWK= awk
247 249
248# The full path name of a Posix-compliant shell that supports the Korn shell's 250# The full path name of a Posix-compliant shell that supports the Korn shell's
249# 'select' statement, as an extension. These days, Bash is the most popular. 251# 'select' statement, as an extension. These days, Bash is the most popular.
250KSHELL= /bin/bash 252KSHELL= /bin/bash
251 253
252# The path where SGML DTDs are kept. 254# The path where SGML DTDs are kept.
253# The default is appropriate for Ubuntu 12.10. 255# The default is appropriate for Ubuntu 12.10.
254SGML_TOPDIR= /usr 256SGML_TOPDIR= /usr
255SGML_DTDDIR= $(SGML_TOPDIR)/share/xml/w3c-sgml-lib/schema/dtd 257SGML_DTDDIR= $(SGML_TOPDIR)/share/xml/w3c-sgml-lib/schema/dtd
256SGML_SEARCH_PATH= $(SGML_DTDDIR)/REC-html401-19991224 258SGML_SEARCH_PATH= $(SGML_DTDDIR)/REC-html401-19991224
257 259
@@ -309,111 +311,128 @@ NONLIBSRCS= zic.c zdump.c scheck.c iallo @@ -309,111 +311,128 @@ NONLIBSRCS= zic.c zdump.c scheck.c iallo
309NEWUCBSRCS= date.c strftime.c 311NEWUCBSRCS= date.c strftime.c
310SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) tzselect.ksh 312SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) tzselect.ksh
311MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \ 313MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \
312 tzfile.5 tzselect.8 zic.8 zdump.8 314 tzfile.5 tzselect.8 zic.8 zdump.8
313COMMON= Makefile 315COMMON= Makefile
314DOCS= README Theory $(MANS) date.1 316DOCS= README Theory $(MANS) date.1
315PRIMARY_YDATA= africa antarctica asia australasia \ 317PRIMARY_YDATA= africa antarctica asia australasia \
316 europe northamerica southamerica 318 europe northamerica southamerica
317YDATA= $(PRIMARY_YDATA) pacificnew etcetera backward 319YDATA= $(PRIMARY_YDATA) pacificnew etcetera backward
318NDATA= systemv factory 320NDATA= systemv factory
319SDATA= solar87 solar88 solar89 321SDATA= solar87 solar88 solar89
320TDATA= $(YDATA) $(NDATA) $(SDATA) 322TDATA= $(YDATA) $(NDATA) $(SDATA)
321TABDATA= iso3166.tab zone.tab 323TABDATA= iso3166.tab zone.tab
322DATA= $(YDATA) $(NDATA) $(SDATA) $(TABDATA) leapseconds yearistype.sh 324DATA= $(YDATA) $(NDATA) $(SDATA) $(TABDATA) \
 325 leap-seconds.list yearistype.sh
323WEB_PAGES= tz-art.htm tz-link.htm 326WEB_PAGES= tz-art.htm tz-link.htm
 327AWK_SCRIPTS= checktab.awk leapseconds.awk
324MISC= usno1988 usno1989 usno1989a usno1995 usno1997 usno1998 \ 328MISC= usno1988 usno1989 usno1989a usno1995 usno1997 usno1998 \
325 $(WEB_PAGES) checktab.awk workman.sh \ 329 $(WEB_PAGES) $(AWK_SCRIPTS) workman.sh \
326 zoneinfo2tdf.pl 330 zoneinfo2tdf.pl
327ENCHILADA= $(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC) 331ENCHILADA= $(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC)
328 332
329# And for the benefit of csh users on systems that assume the user 333# And for the benefit of csh users on systems that assume the user
330# shell should be used to handle commands in Makefiles. . . 334# shell should be used to handle commands in Makefiles. . .
331 335
332SHELL= /bin/sh 336SHELL= /bin/sh
333 337
334all: tzselect zic zdump $(LIBOBJS) 338all: tzselect zic zdump $(LIBOBJS) $(TABDATA)
335 339
336ALL: all date 340ALL: all date
337 341
338install: all $(DATA) $(REDO) $(TZLIB) $(MANS) $(TABDATA) 342install: all $(DATA) $(REDO) $(DESTDIR)$(TZLIB) $(MANS)
339 $(ZIC) -y $(YEARISTYPE) \ 343 $(ZIC) -y $(YEARISTYPE) \
340 -d $(TZDIR) -l $(LOCALTIME) -p $(POSIXRULES) 344 -d $(DESTDIR)$(TZDIR) -l $(LOCALTIME) -p $(POSIXRULES)
341 -rm -f $(TZDIR)/iso3166.tab $(TZDIR)/zone.tab 345 -rm -f $(DESTDIR)$(TZDIR)/iso3166.tab \
342 cp iso3166.tab zone.tab $(TZDIR)/. 346 $(DESTDIR)$(TZDIR)/zone.tab
343 -mkdir $(TOPDIR) $(ETCDIR) 347 cp iso3166.tab zone.tab $(DESTDIR)$(TZDIR)/.
344 cp tzselect zic zdump $(ETCDIR)/. 348 -mkdir $(DESTDIR)$(TOPDIR) $(DESTDIR)$(ETCDIR)
345 -mkdir $(TOPDIR) $(MANDIR) \ 349 cp tzselect zic zdump $(DESTDIR)$(ETCDIR)/.
346 $(MANDIR)/man3 $(MANDIR)/man5 $(MANDIR)/man8 350 -mkdir $(DESTDIR)$(TOPDIR) $(DESTDIR)$(MANDIR) \
347 -rm -f $(MANDIR)/man3/newctime.3 \ 351 $(DESTDIR)$(MANDIR)/man3 $(DESTDIR)$(MANDIR)/man5 \
348 $(MANDIR)/man3/newtzset.3 \ 352 $(DESTDIR)$(MANDIR)/man8
349 $(MANDIR)/man5/tzfile.5 \ 353 -rm -f $(DESTDIR)$(MANDIR)/man3/newctime.3 \
350 $(MANDIR)/man8/tzselect.8 \ 354 $(DESTDIR)$(MANDIR)/man3/newtzset.3 \
351 $(MANDIR)/man8/zdump.8 \ 355 $(DESTDIR)$(MANDIR)/man5/tzfile.5 \
352 $(MANDIR)/man8/zic.8 356 $(DESTDIR)$(MANDIR)/man8/tzselect.8 \
353 cp newctime.3 newtzset.3 $(MANDIR)/man3/. 357 $(DESTDIR)$(MANDIR)/man8/zdump.8 \
354 cp tzfile.5 $(MANDIR)/man5/. 358 $(DESTDIR)$(MANDIR)/man8/zic.8
355 cp tzselect.8 zdump.8 zic.8 $(MANDIR)/man8/. 359 cp newctime.3 newtzset.3 $(DESTDIR)$(MANDIR)/man3/.
 360 cp tzfile.5 $(DESTDIR)$(MANDIR)/man5/.
 361 cp tzselect.8 zdump.8 zic.8 $(DESTDIR)$(MANDIR)/man8/.
356 362
357INSTALL: ALL install date.1 363INSTALL: ALL install date.1
358 -mkdir $(TOPDIR) $(BINDIR) 364 -mkdir $(DESTDIR)$(TOPDIR) $(DESTDIR)$(BINDIR)
359 cp date $(BINDIR)/. 365 cp date $(DESTDIR)$(BINDIR)/.
360 -mkdir $(TOPDIR) $(MANDIR) $(MANDIR)/man1 366 -mkdir $(DESTDIR)$(TOPDIR) $(DESTDIR)$(MANDIR) \
361 -rm -f $(MANDIR)/man1/date.1 367 $(DESTDIR)$(MANDIR)/man1
362 cp date.1 $(MANDIR)/man1/. 368 -rm -f $(DESTDIR)$(MANDIR)/man1/date.1
 369 cp date.1 $(DESTDIR)$(MANDIR)/man1/.
363 370
364version.h: 371version.h:
365 (echo 'static char const PKGVERSION[]="($(PACKAGE)) ";' && \ 372 (echo 'static char const PKGVERSION[]="($(PACKAGE)) ";' && \
366 echo 'static char const TZVERSION[]="$(VERSION)";' && \ 373 echo 'static char const TZVERSION[]="$(VERSION)";' && \
367 echo 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";') >$@ 374 echo 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";') >$@
368 375
369zdump: $(TZDOBJS) 376zdump: $(TZDOBJS)
370 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS) 377 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS)
371 378
372zic: $(TZCOBJS) yearistype 379zic: $(TZCOBJS) yearistype
373 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS) 380 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS)
374 381
375yearistype: yearistype.sh 382yearistype: yearistype.sh
376 cp yearistype.sh yearistype 383 cp yearistype.sh yearistype
377 chmod +x yearistype 384 chmod +x yearistype
378 385
 386leapseconds: leapseconds.awk leap-seconds.list
 387 $(AWK) -f leapseconds.awk leap-seconds.list >$@
 388
379posix_only: zic $(TDATA) 389posix_only: zic $(TDATA)
380 $(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L /dev/null $(TDATA) 390 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR) \
 391 -L /dev/null $(TDATA)
381 392
382right_only: zic leapseconds $(TDATA) 393right_only: zic leapseconds $(TDATA)
383 $(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L leapseconds $(TDATA) 394 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR) \
 395 -L leapseconds $(TDATA)
384 396
385# In earlier versions of this makefile, the other two directories were 397# In earlier versions of this makefile, the other two directories were
386# subdirectories of $(TZDIR). However, this led to configuration errors. 398# subdirectories of $(TZDIR). However, this led to configuration errors.
387# For example, with posix_right under the earlier scheme, 399# For example, with posix_right under the earlier scheme,
388# TZ='right/Australia/Adelaide' got you localtime with leap seconds, 400# TZ='right/Australia/Adelaide' got you localtime with leap seconds,
389# but gmtime without leap seconds, which led to problems with applications 401# but gmtime without leap seconds, which led to problems with applications
390# like sendmail that subtract gmtime from localtime. 402# like sendmail that subtract gmtime from localtime.
391# Therefore, the other two directories are now siblings of $(TZDIR). 403# Therefore, the other two directories are now siblings of $(TZDIR).
392# You must replace all of $(TZDIR) to switch from not using leap seconds 404# You must replace all of $(TZDIR) to switch from not using leap seconds
393# to using them, or vice versa. 405# to using them, or vice versa.
394other_two: zic leapseconds $(TDATA) 406right_posix: right_only leapseconds
395 $(ZIC) -y $(YEARISTYPE) -d $(TZDIR)-posix -L /dev/null $(TDATA) 407 rm -fr $(DESTDIR)$(TZDIR)-leaps
396 $(ZIC) -y $(YEARISTYPE) \ 408 ln -s $(TZDIR_BASENAME) $(DESTDIR)$(TZDIR)-leaps || \
397 -d $(TZDIR)-leaps -L leapseconds $(TDATA) 409 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR)-leaps \
398 410 -L leapseconds $(TDATA)
399posix_right: posix_only other_two 411 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR)-posix \
400 412 -L /dev/null $(TDATA)
401right_posix: right_only other_two 413
 414posix_right: posix_only leapseconds
 415 rm -fr $(DESTDIR)$(TZDIR)-posix
 416 ln -s $(TZDIR_BASENAME) $(DESTDIR)$(TZDIR)-posix || \
 417 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR)-posix \
 418 -L /dev/null $(TDATA)
 419 $(ZIC) -y $(YEARISTYPE) -d $(DESTDIR)$(TZDIR)-leaps \
 420 -L leapseconds $(TDATA)
402 421
403zones: $(REDO) 422zones: $(REDO)
404 423
405$(TZLIB): $(LIBOBJS) 424$(DESTDIR)$(TZLIB): $(LIBOBJS)
406 -mkdir $(TOPDIR) $(LIBDIR) 425 -mkdir -p $(DESTDIR)$(TOPDIR) $(DESTDIR)$(LIBDIR)
407 ar ru $@ $(LIBOBJS) 426 ar ru $@ $(LIBOBJS)
408 if [ -x /usr/ucb/ranlib ] || [ -x /usr/bin/ranlib ]; \ 427 if [ -x /usr/ucb/ranlib ] || [ -x /usr/bin/ranlib ]; \
409 then ranlib $@ ; fi 428 then ranlib $@ ; fi
410 429
411date: $(DATEOBJS) 430date: $(DATEOBJS)
412 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS) 431 $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS)
413 432
414tzselect: tzselect.ksh 433tzselect: tzselect.ksh
415 sed \ 434 sed \
416 -e 's|#!/bin/bash|#!$(KSHELL)|g' \ 435 -e 's|#!/bin/bash|#!$(KSHELL)|g' \
417 -e 's|AWK=[^}]*|AWK=$(AWK)|g' \ 436 -e 's|AWK=[^}]*|AWK=$(AWK)|g' \
418 -e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \ 437 -e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \
419 -e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \ 438 -e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \
@@ -425,27 +444,27 @@ tzselect: tzselect.ksh @@ -425,27 +444,27 @@ tzselect: tzselect.ksh
425check: check_character_set check_tables check_web 444check: check_character_set check_tables check_web
426 445
427check_character_set: $(ENCHILADA) 446check_character_set: $(ENCHILADA)
428 sharp='#'; ! grep -n $(INVALID_CHAR) $(ENCHILADA) 447 sharp='#'; ! grep -n $(INVALID_CHAR) $(ENCHILADA)
429 448
430check_tables: checktab.awk $(PRIMARY_YDATA) 449check_tables: checktab.awk $(PRIMARY_YDATA)
431 $(AWK) -f checktab.awk $(PRIMARY_YDATA) 450 $(AWK) -f checktab.awk $(PRIMARY_YDATA)
432 451
433check_web: $(WEB_PAGES) 452check_web: $(WEB_PAGES)
434 $(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) $(WEB_PAGES) 453 $(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) $(WEB_PAGES)
435 454
436clean_misc: 455clean_misc:
437 rm -f core *.o *.out \ 456 rm -f core *.o *.out \
438 date tzselect version.h zdump zic yearistype 457 date leapseconds tzselect version.h zdump zic yearistype
439clean: clean_misc 458clean: clean_misc
440 rm -f -r tzpublic 459 rm -f -r tzpublic
441 460
442maintainer-clean: clean 461maintainer-clean: clean
443 @echo 'This command is intended for maintainers to use; it' 462 @echo 'This command is intended for maintainers to use; it'
444 @echo 'deletes files that may need special tools to rebuild.' 463 @echo 'deletes files that may need special tools to rebuild.'
445 rm -f *.[1-8].txt *.asc *.tar.gz 464 rm -f *.[1-8].txt *.asc *.tar.gz
446 465
447names: 466names:
448 @echo $(ENCHILADA) 467 @echo $(ENCHILADA)
449 468
450public: check check_public check_time_t_alternatives \ 469public: check check_public check_time_t_alternatives \
451 set-timestamps tarballs signatures 470 set-timestamps tarballs signatures
@@ -525,27 +544,27 @@ tzdata$(VERSION).tar.gz: $(COMMON) $(DAT @@ -525,27 +544,27 @@ tzdata$(VERSION).tar.gz: $(COMMON) $(DAT
525 tar $(TARFLAGS) -cf - $(COMMON) $(DATA) | \ 544 tar $(TARFLAGS) -cf - $(COMMON) $(DATA) | \
526 gzip $(GZIPFLAGS) > $@ 545 gzip $(GZIPFLAGS) > $@
527 546
528signatures: tzcode$(VERSION).tar.gz.asc tzdata$(VERSION).tar.gz.asc 547signatures: tzcode$(VERSION).tar.gz.asc tzdata$(VERSION).tar.gz.asc
529 548
530tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz 549tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz
531 gpg --armor --detach-sign $? 550 gpg --armor --detach-sign $?
532 551
533tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz 552tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz
534 gpg --armor --detach-sign $? 553 gpg --armor --detach-sign $?
535 554
536typecheck: 555typecheck:
537 make clean 556 make clean
538 for i in "long long" unsigned double; \ 557 for i in "long long" unsigned; \
539 do \ 558 do \
540 make CFLAGS="-DTYPECHECK -D__time_t_defined -D_TIME_T \"-Dtime_t=$$i\"" ; \ 559 make CFLAGS="-DTYPECHECK -D__time_t_defined -D_TIME_T \"-Dtime_t=$$i\"" ; \
541 ./zdump -v Europe/Rome ; \ 560 ./zdump -v Europe/Rome ; \
542 make clean ; \ 561 make clean ; \
543 done 562 done
544 563
545zonenames: $(TDATA) 564zonenames: $(TDATA)
546 @$(AWK) '/^Zone/ { print $$2 } /^Link/ { print $$3 }' $(TDATA) 565 @$(AWK) '/^Zone/ { print $$2 } /^Link/ { print $$3 }' $(TDATA)
547 566
548asctime.o: private.h tzfile.h 567asctime.o: private.h tzfile.h
549date.o: private.h 568date.o: private.h
550difftime.o: private.h 569difftime.o: private.h
551ialloc.o: private.h 570ialloc.o: private.h

cvs diff -r1.14 -r1.15 src/lib/libc/time/difftime.c (expand / switch to unified diff)

--- src/lib/libc/time/difftime.c 2013/07/17 20:13:04 1.14
+++ src/lib/libc/time/difftime.c 2013/09/20 19:06:54 1.15
@@ -1,63 +1,54 @@ @@ -1,63 +1,54 @@
1/* $NetBSD: difftime.c,v 1.14 2013/07/17 20:13:04 christos Exp $ */ 1/* $NetBSD: difftime.c,v 1.15 2013/09/20 19:06:54 christos Exp $ */
2 2
3/* 3/*
4** This file is in the public domain, so clarified as of 4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson. 5** 1996-06-05 by Arthur David Olson.
6*/ 6*/
7 7
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#if defined(LIBC_SCCS) && !defined(lint) 9#if defined(LIBC_SCCS) && !defined(lint)
10#if 0 10#if 0
11static char elsieid[] = "@(#)difftime.c 8.1"; 11static char elsieid[] = "@(#)difftime.c 8.1";
12#else 12#else
13__RCSID("$NetBSD: difftime.c,v 1.14 2013/07/17 20:13:04 christos Exp $"); 13__RCSID("$NetBSD: difftime.c,v 1.15 2013/09/20 19:06:54 christos Exp $");
14#endif 14#endif
15#endif /* LIBC_SCCS and not lint */ 15#endif /* LIBC_SCCS and not lint */
16 16
17/*LINTLIBRARY*/ 17/*LINTLIBRARY*/
18 18
19#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ 19#include "private.h" /* for time_t and TYPE_SIGNED */
20 20
21double ATTRIBUTE_CONST 21double ATTRIBUTE_CONST
22difftime(const time_t time1, const time_t time0) 22difftime(const time_t time1, const time_t time0)
23{ 23{
24 /* 24 /*
25 ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract 25 ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
26 ** (assuming that the larger type has more precision). 26 ** (assuming that the larger type has more precision).
27 */ 27 */
28 /*CONSTCOND*/ 28 /*CONSTCOND*/
29 if (sizeof (double) > sizeof (time_t)) 29 if (sizeof (double) > sizeof (time_t))
30 return (double) time1 - (double) time0; 30 return (double) time1 - (double) time0;
31 /*LINTED const not */ 31 /*LINTED const not */
32 if (!TYPE_INTEGRAL(time_t)) { 
33 /* 
34 ** time_t is floating. 
35 */ 
36 return time1 - time0; 
37 } 
38 /*LINTED const not */ 
39 if (!TYPE_SIGNED(time_t)) { 32 if (!TYPE_SIGNED(time_t)) {
40 /* 33 /*
41 ** time_t is integral and unsigned. 
42 ** The difference of two unsigned values can't overflow 34 ** The difference of two unsigned values can't overflow
43 ** if the minuend is greater than or equal to the subtrahend. 35 ** if the minuend is greater than or equal to the subtrahend.
44 */ 36 */
45 if (time1 >= time0) 37 if (time1 >= time0)
46 return time1 - time0; 38 return time1 - time0;
47 else return -(double) (time0 - time1); 39 else return -(double) (time0 - time1);
48 } 40 }
49 /* 41 /*
50 ** time_t is integral and signed. 
51 ** Handle cases where both time1 and time0 have the same sign 42 ** Handle cases where both time1 and time0 have the same sign
52 ** (meaning that their difference cannot overflow). 43 ** (meaning that their difference cannot overflow).
53 */ 44 */
54 if ((time1 < 0) == (time0 < 0)) 45 if ((time1 < 0) == (time0 < 0))
55 return time1 - time0; 46 return time1 - time0;
56 /* 47 /*
57 ** time1 and time0 have opposite signs. 48 ** time1 and time0 have opposite signs.
58 ** Punt if uintmax_t is too narrow. 49 ** Punt if uintmax_t is too narrow.
59 ** This suffers from double rounding; attempt to lessen that 50 ** This suffers from double rounding; attempt to lessen that
60 ** by using long double temporaries. 51 ** by using long double temporaries.
61 */ 52 */
62 /* CONSTCOND */ 53 /* CONSTCOND */
63 if (sizeof (uintmax_t) < sizeof (time_t)) 54 if (sizeof (uintmax_t) < sizeof (time_t))

cvs diff -r1.13 -r1.14 src/lib/libc/time/Theory (expand / switch to unified diff)

--- src/lib/libc/time/Theory 2013/07/17 20:13:04 1.13
+++ src/lib/libc/time/Theory 2013/09/20 19:06:54 1.14
@@ -2,79 +2,80 @@ This file is in the public domain, so cl @@ -2,79 +2,80 @@ This file is in the public domain, so cl
22009-05-17 by Arthur David Olson. 22009-05-17 by Arthur David Olson.
3 3
4----- Outline ----- 4----- Outline -----
5 5
6 Time and date functions 6 Time and date functions
7 Scope of the tz database 7 Scope of the tz database
8 Names of time zone rule files 8 Names of time zone rule files
9 Time zone abbreviations 9 Time zone abbreviations
10 Calendrical issues 10 Calendrical issues
11 Time and time zones on Mars 11 Time and time zones on Mars
12 12
13----- Time and date functions ----- 13----- Time and date functions -----
14 14
15These time and date functions are upwards compatible with POSIX, 15These time and date functions are upwards compatible with those of POSIX,
16an international standard for UNIX-like systems. 16an international standard for UNIX-like systems.
17As of this writing, the current edition of POSIX is: 17As of this writing, the current edition of POSIX is:
18 18
19 Standard for Information technology 19 The Open Group Base Specifications Issue 7
20 -- Portable Operating System Interface (POSIX (R)) 20 IEEE Std 1003.1, 2013 Edition
21 -- System Interfaces 21 <http://pubs.opengroup.org/onlinepubs/9699919799/>
22 IEEE Std 1003.1, 2004 Edition 
23 <http://www.opengroup.org/online-pubs?DOC=7999959899> 
24 <http://www.opengroup.org/pubs/catalog/t041.htm> 
25 22
26POSIX has the following properties and limitations. 23POSIX has the following properties and limitations.
27 24
28* In POSIX, time display in a process is controlled by the 25* In POSIX, time display in a process is controlled by the
29 environment variable TZ. Unfortunately, the POSIX TZ string takes 26 environment variable TZ. Unfortunately, the POSIX TZ string takes
30 a form that is hard to describe and is error-prone in practice. 27 a form that is hard to describe and is error-prone in practice.
31 Also, POSIX TZ strings can't deal with other (for example, Israeli) 28 Also, POSIX TZ strings can't deal with other (for example, Israeli)
32 daylight saving time rules, or situations where more than two 29 daylight saving time rules, or situations where more than two
33 time zone abbreviations are used in an area. 30 time zone abbreviations are used in an area.
34 31
35 The POSIX TZ string takes the following form: 32 The POSIX TZ string takes the following form:
36 33
37 stdoffset[dst[offset],date[/time],date[/time]] 34 stdoffset[dst[offset][,date[/time],date[/time]]]
38 35
39 where: 36 where:
40 37
41 std and dst 38 std and dst
42 are 3 or more characters specifying the standard 39 are 3 or more characters specifying the standard
43 and daylight saving time (DST) zone names. 40 and daylight saving time (DST) zone names.
44 Starting with POSIX.1-2001, std and dst may also be 41 Starting with POSIX.1-2001, std and dst may also be
45 in a quoted form like "<UTC+10>"; this allows 42 in a quoted form like "<UTC+10>"; this allows
46 "+" and "-" in the names. 43 "+" and "-" in the names.
47 offset 44 offset
48 is of the form `[-]hh:[mm[:ss]]' and specifies the 45 is of the form '[+-]hh:[mm[:ss]]' and specifies the
49 offset west of UTC. The default DST offset is one hour 46 offset west of UT. 'hh' may be a single digit; 0<=hh<=24.
50 ahead of standard time. 47 The default DST offset is one hour ahead of standard time.
51 date[/time],date[/time] 48 date[/time],date[/time]
52 specifies the beginning and end of DST. If this is absent, 49 specifies the beginning and end of DST. If this is absent,
53 the system supplies its own rules for DST, and these can 50 the system supplies its own rules for DST, and these can
54 differ from year to year; typically US DST rules are used. 51 differ from year to year; typically US DST rules are used.
55 time 52 time
56 takes the form `hh:[mm[:ss]]' and defaults to 02:00. 53 takes the form 'hh:[mm[:ss]]' and defaults to 02:00.
 54 This is the same format as the offset, except that a
 55 leading '+' or '-' is not allowed.
57 date 56 date
58 takes one of the following forms: 57 takes one of the following forms:
59 Jn (1<=n<=365) 58 Jn (1<=n<=365)
60 origin-1 day number not counting February 29 59 origin-1 day number not counting February 29
61 n (0<=n<=365) 60 n (0<=n<=365)
62 origin-0 day number counting February 29 if present 61 origin-0 day number counting February 29 if present
63 Mm.n.d (0[Sunday]<=d<=6[Saturday], 1<=n<=5, 1<=m<=12) 62 Mm.n.d (0[Sunday]<=d<=6[Saturday], 1<=n<=5, 1<=m<=12)
64 for the dth day of week n of month m of the year, 63 for the dth day of week n of month m of the year,
65 where week 1 is the first week in which day d appears, 64 where week 1 is the first week in which day d appears,
66 and `5' stands for the last week in which day d appears 65 and '5' stands for the last week in which day d appears
67 (which may be either the 4th or 5th week). 66 (which may be either the 4th or 5th week).
 67 Typically, this is the only useful form;
 68 the n and Jn forms are rarely used.
68 69
69 Here is an example POSIX TZ string, for US Pacific time using rules 70 Here is an example POSIX TZ string, for US Pacific time using rules
70 appropriate from 1987 through 2006: 71 appropriate from 1987 through 2006:
71 72
72 TZ='PST8PDT,M4.1.0/02:00,M10.5.0/02:00' 73 TZ='PST8PDT,M4.1.0/02:00,M10.5.0/02:00'
73 74
74 This POSIX TZ string is hard to remember, and mishandles time stamps 75 This POSIX TZ string is hard to remember, and mishandles time stamps
75 before 1987 and after 2006. With this package you can use this 76 before 1987 and after 2006. With this package you can use this
76 instead: 77 instead:
77 78
78 TZ='America/Los_Angeles' 79 TZ='America/Los_Angeles'
79 80
80* POSIX does not define the exact meaning of TZ values like "EST5EDT". 81* POSIX does not define the exact meaning of TZ values like "EST5EDT".
@@ -85,26 +86,39 @@ POSIX has the following properties and l @@ -85,26 +86,39 @@ POSIX has the following properties and l
85 do time conversion must be recompiled to ensure proper results. 86 do time conversion must be recompiled to ensure proper results.
86 87
87* In POSIX, there's no tamper-proof way for a process to learn the 88* In POSIX, there's no tamper-proof way for a process to learn the
88 system's best idea of local wall clock. (This is important for 89 system's best idea of local wall clock. (This is important for
89 applications that an administrator wants used only at certain times-- 90 applications that an administrator wants used only at certain times--
90 without regard to whether the user has fiddled the "TZ" environment 91 without regard to whether the user has fiddled the "TZ" environment
91 variable. While an administrator can "do everything in UTC" to get 92 variable. While an administrator can "do everything in UTC" to get
92 around the problem, doing so is inconvenient and precludes handling 93 around the problem, doing so is inconvenient and precludes handling
93 daylight saving time shifts--as might be required to limit phone 94 daylight saving time shifts--as might be required to limit phone
94 calls to off-peak hours.) 95 calls to off-peak hours.)
95 96
96* POSIX requires that systems ignore leap seconds. 97* POSIX requires that systems ignore leap seconds.
97 98
 99* The tz code attempts attempts to support all the time_t implementations
 100 allowed by POSIX. The time_t type represents a nonnegative count of
 101 seconds since 1970-01-01 00:00:00 UTC, ignoring leap seconds.
 102 In practice, time_t is usually a signed 64- or 32-bit integer; 32-bit
 103 signed time_t values stop working after 2038-01-19 03:14:07 UTC, so
 104 new implementations these days typically use a signed 64-bit integer.
 105 Unsigned 32-bit integers are used on one or two platforms,
 106 and 36-bit integers are also used occasionally.
 107 Although earlier POSIX versions allowed time_t to be a
 108 floating-point type, this was not supported by any practical
 109 systems, and POSIX.1-2013 and the tz code both require time_t
 110 to be an integer type.
 111
98These are the extensions that have been made to the POSIX functions: 112These are the extensions that have been made to the POSIX functions:
99 113
100* The "TZ" environment variable is used in generating the name of a file 114* The "TZ" environment variable is used in generating the name of a file
101 from which time zone information is read (or is interpreted a la 115 from which time zone information is read (or is interpreted a la
102 POSIX); "TZ" is no longer constrained to be a three-letter time zone 116 POSIX); "TZ" is no longer constrained to be a three-letter time zone
103 name followed by a number of hours and an optional three-letter 117 name followed by a number of hours and an optional three-letter
104 daylight time zone name. The daylight saving time rules to be used 118 daylight time zone name. The daylight saving time rules to be used
105 for a particular time zone are encoded in the time zone file; 119 for a particular time zone are encoded in the time zone file;
106 the format of the file allows U.S., Australian, and other rules to be 120 the format of the file allows U.S., Australian, and other rules to be
107 encoded, and allows for situations where more than two time zone 121 encoded, and allows for situations where more than two time zone
108 abbreviations are used. 122 abbreviations are used.
109 123
110 It was recognized that allowing the "TZ" environment variable to 124 It was recognized that allowing the "TZ" environment variable to
@@ -136,96 +150,223 @@ These are the extensions that have been  @@ -136,96 +150,223 @@ These are the extensions that have been
136 source code tells how to get compatibly wrong results). 150 source code tells how to get compatibly wrong results).
137 151
138* A function "tzsetwall" has been added to arrange for the system's 152* A function "tzsetwall" has been added to arrange for the system's
139 best approximation to local wall clock time to be delivered by 153 best approximation to local wall clock time to be delivered by
140 subsequent calls to "localtime." Source code for portable 154 subsequent calls to "localtime." Source code for portable
141 applications that "must" run on local wall clock time should call 155 applications that "must" run on local wall clock time should call
142 "tzsetwall();" if such code is moved to "old" systems that don't 156 "tzsetwall();" if such code is moved to "old" systems that don't
143 provide tzsetwall, you won't be able to generate an executable program. 157 provide tzsetwall, you won't be able to generate an executable program.
144 (These time zone functions also arrange for local wall clock time to be 158 (These time zone functions also arrange for local wall clock time to be
145 used if tzset is called--directly or indirectly--and there's no "TZ" 159 used if tzset is called--directly or indirectly--and there's no "TZ"
146 environment variable; portable applications should not, however, rely 160 environment variable; portable applications should not, however, rely
147 on this behavior since it's not the way SVR2 systems behave.) 161 on this behavior since it's not the way SVR2 systems behave.)
148 162
 163* Negative time_t values are supported, on systems where time_t is signed.
 164
149* These functions can account for leap seconds, thanks to Bradley White. 165* These functions can account for leap seconds, thanks to Bradley White.
150 166
151Points of interest to folks with other systems: 167Points of interest to folks with other systems:
152 168
153* This package is already part of many POSIX-compliant hosts, 169* This package is already part of many POSIX-compliant hosts,
154 including BSD, HP, Linux, Network Appliance, SCO, SGI, and Sun. 170 including BSD, HP, Linux, Network Appliance, SCO, SGI, and Sun.
155 On such hosts, the primary use of this package 171 On such hosts, the primary use of this package
156 is to update obsolete time zone rule tables. 172 is to update obsolete time zone rule tables.
157 To do this, you may need to compile the time zone compiler 173 To do this, you may need to compile the time zone compiler
158 `zic' supplied with this package instead of using the system `zic', 174 'zic' supplied with this package instead of using the system 'zic',
159 since the format of zic's input changed slightly in late 1994, 175 since the format of zic's input changed slightly in late 1994,
160 and many vendors still do not support the new input format. 176 and many vendors still do not support the new input format.
161 177
162* The UNIX Version 7 "timezone" function is not present in this package; 178* The UNIX Version 7 "timezone" function is not present in this package;
163 it's impossible to reliably map timezone's arguments (a "minutes west 179 it's impossible to reliably map timezone's arguments (a "minutes west
164 of GMT" value and a "daylight saving time in effect" flag) to a 180 of GMT" value and a "daylight saving time in effect" flag) to a
165 time zone abbreviation, and we refuse to guess. 181 time zone abbreviation, and we refuse to guess.
166 Programs that in the past used the timezone function may now examine 182 Programs that in the past used the timezone function may now examine
167 tzname[localtime(&clock)->tm_isdst] to learn the correct time 183 tzname[localtime(&clock)->tm_isdst] to learn the correct time
168 zone abbreviation to use. Alternatively, use 184 zone abbreviation to use. Alternatively, use
169 localtime(&clock)->tm_zone if this has been enabled. 185 localtime(&clock)->tm_zone if this has been enabled.
170 186
171* The 4.2BSD gettimeofday function is not used in this package. 187* The 4.2BSD gettimeofday function is not used in this package.
172 This formerly let users obtain the current UTC offset and DST flag, 188 This formerly let users obtain the current UTC offset and DST flag,
173 but this functionality was removed in later versions of BSD. 189 but this functionality was removed in later versions of BSD.
174 190
175* In SVR2, time conversion fails for near-minimum or near-maximum 191* In SVR2, time conversion fails for near-minimum or near-maximum
176 time_t values when doing conversions for places that don't use UTC. 192 time_t values when doing conversions for places that don't use UT.
177 This package takes care to do these conversions correctly. 193 This package takes care to do these conversions correctly.
178 194
179The functions that are conditionally compiled if STD_INSPIRED is defined 195The functions that are conditionally compiled if STD_INSPIRED is defined
180should, at this point, be looked on primarily as food for thought. They are 196should, at this point, be looked on primarily as food for thought. They are
181not in any sense "standard compatible"--some are not, in fact, specified in 197not in any sense "standard compatible"--some are not, in fact, specified in
182*any* standard. They do, however, represent responses of various authors to 198*any* standard. They do, however, represent responses of various authors to
183standardization proposals. 199standardization proposals.
184 200
185Other time conversion proposals, in particular the one developed by folks at 201Other time conversion proposals, in particular the one developed by folks at
186Hewlett Packard, offer a wider selection of functions that provide capabilities 202Hewlett Packard, offer a wider selection of functions that provide capabilities
187beyond those provided here. The absence of such functions from this package 203beyond those provided here. The absence of such functions from this package
188is not meant to discourage the development, standardization, or use of such 204is not meant to discourage the development, standardization, or use of such
189functions. Rather, their absence reflects the decision to make this package 205functions. Rather, their absence reflects the decision to make this package
190contain valid extensions to POSIX, to ensure its broad acceptability. If 206contain valid extensions to POSIX, to ensure its broad acceptability. If
191more powerful time conversion functions can be standardized, so much the 207more powerful time conversion functions can be standardized, so much the
192better. 208better.
193 209
194 210
195----- Scope of the tz database ----- 211----- Scope of the tz database -----
196 212
197The tz database attempts to record the history and predicted future of 213The tz database attempts to record the history and predicted future of
198all computer-based clocks that track civil time. To represent this 214all computer-based clocks that track civil time. To represent this
199data, the world is partitioned into regions whose clocks all agree 215data, the world is partitioned into regions whose clocks all agree
200about time stamps that occur after the somewhat-arbitrary cutoff point 216about time stamps that occur after the somewhat-arbitrary cutoff point
201of the POSIX Epoch (1970-01-01 00:00:00 UTC). For each such region, 217of the POSIX Epoch (1970-01-01 00:00:00 UTC). For each such region,
202the database records all known clock transitions, and labels the region 218the database records all known clock transitions, and labels the region
203with a notable location. 219with a notable location. Although 1970 is a somewhat-arbitrary
 220cutoff, there are significant challenges to moving the cutoff earlier
 221even by a decade or two, due to the wide variety of local practices
 222before computer timekeeping became prevalent.
204 223
205Clock transitions before 1970 are recorded for each such location, 224Clock transitions before 1970 are recorded for each such location,
206because most POSIX-compatible systems support negative time stamps and 225because most POSIX-compatible systems support negative time stamps and
207could misbehave if data were omitted for pre-1970 transitions. 226could misbehave if data were omitted for pre-1970 transitions.
208However, the database is not designed for and does not suffice for 227However, the database is not designed for and does not suffice for
209applications requiring accurate handling of all past times everywhere, 228applications requiring accurate handling of all past times everywhere,
210as it would take far too much effort and guesswork to record all 229as it would take far too much effort and guesswork to record all
211details of pre-1970 civil timekeeping. 230details of pre-1970 civil timekeeping.
212 231
213As noted in the README file, the tz database is not authoritative 232
214(particularly not for pre-1970 time stamps), and it surely has errors. 233----- Accuracy of the tz database -----
 234
 235The tz database is not authoritative, and it surely has errors.
215Corrections are welcome and encouraged. Users requiring authoritative 236Corrections are welcome and encouraged. Users requiring authoritative
216data should consult national standards bodies and the references cited 237data should consult national standards bodies and the references cited
217in the database's comments. 238in the database's comments.
218 239
 240Errors in the tz database arise from many sources:
 241
 242 * The tz database predicts future time stamps, and current predictions
 243 will be incorrect after future governments change the rules.
 244 For example, if today someone schedules a meeting for 13:00 next
 245 October 1, Casablanca time, and tomorrow Morocco changes its
 246 daylight saving rules, software can mess up after the rule change
 247 if it blithely relies on conversions made before the change.
 248
 249 * The pre-1970 data in this database cover only a tiny sliver of how
 250 clocks actually behaved; the vast majority of the necessary
 251 information was lost or never recorded. Thousands more zones would
 252 be needed if the tz database's scope were extended to cover even
 253 just the known or guessed history of standard time; for example,
 254 the current single entry for France would need to split into dozens
 255 of entries, perhaps hundreds.
 256
 257 * Most of the pre-1970 data comes from unreliable sources, often
 258 astrology books that lack citations and whose compilers evidently
 259 invented entries when the true facts were unknown, without
 260 reporting which entries were known and which were invented.
 261 These books often contradict each other or give implausible entries,
 262 and on the rare occasions when their old data are checked they are
 263 typically found to be incorrect.
 264
 265 * For the UK the tz database relies on years of first-class work done by
 266 Joseph Myers and others; see <http://www.polyomino.org.uk/british-time/>.
 267 Other countries are not done nearly as well.
 268
 269 * Sometimes, different people in the same city would maintain clocks
 270 that differed significantly. Railway time was used by railroad
 271 companies (which did not always agree with each other),
 272 church-clock time was used for birth certificates, etc.
 273 Often this was merely common practice, but sometimes it was set by law.
 274 For example, from 1891 to 1911 the UT offset in France was legally
 275 0:09:21 outside train stations and 0:04:21 inside.
 276
 277 * Although a named location in the tz database stands for the
 278 containing region, its pre-1970 data entries are often accurate for
 279 only a small subset of that region. For example, Europe/London
 280 stands for the United Kingdom, but its pre-1847 times are valid
 281 only for locations that have London's exact meridian, and its 1847
 282 transition to GMT is known to be valid only for the L&NW and the
 283 Caledonian railways.
 284
 285 * The tz database does not record the earliest time for which a
 286 zone's data is thereafter valid for every location in the region.
 287 For example, Europe/London is valid for all locations in its
 288 region after GMT was made the standard time, but the date of
 289 standardization (1880-08-02) is not in the tz database, other than
 290 in commentary. For many zones the earliest time of validity is
 291 unknown.
 292
 293 * The tz database does not record a region's boundaries, and in many
 294 cases the boundaries are not known. For example, the zone
 295 America/Kentucky/Louisville represents a region around the city of
 296 Louisville, the boundaries of which are unclear.
 297
 298 * Changes that are modeled as instantaneous transitions in the tz
 299 database were often spread out over hours, days, or even decades.
 300
 301 * Even if the time is specified by law, locations sometimes
 302 deliberately flout the law.
 303
 304 * Early timekeeping practices, even assuming perfect clocks, were
 305 often not specified to the accuracy that the tz database requires.
 306
 307 * Sometimes historical timekeeping was specified more precisely
 308 than what the tz database can handle. For example, from 1909 to
 309 1937 Netherlands clocks were legally UT+00:19:32.13, but the tz
 310 database cannot represent the fractional second.
 311
 312 * Even when all the timestamp transitions recorded by the tz database
 313 are correct, the tz rules that generate them may not faithfully
 314 reflect the historical rules. For example, from 1922 until World
 315 War II the UK moved clocks forward the day following the third
 316 Saturday in April unless that was Easter, in which case it moved
 317 clocks forward the previous Sunday. Because the tz database has no
 318 way to specify Easter, these exceptional years are entered as
 319 separate tz Rule lines, even though the legal rules did not change.
 320
 321 * The tz database models pre-standard time using the Gregorian
 322 calendar and local mean time (LMT), but many people used other
 323 calendars and other timescales. For example, the Roman Empire used
 324 the Julian calendar, and had 12 varying-length daytime hours with a
 325 non-hour-based system at night.
 326
 327 * Early clocks were less reliable, and the data do not represent this
 328 unreliability.
 329
 330 * As for leap seconds, civil time was not based on atomic time before
 331 1972, and we don't know the history of earth's rotation accurately
 332 enough to map SI seconds to historical solar time to more than
 333 about one-hour accuracy. See: Morrison LV, Stephenson FR.
 334 Historical values of the Earth's clock error Delta T and the
 335 calculation of eclipses. J Hist Astron. 2004;35:327-36
 336 <http://adsabs.harvard.edu/full/2004JHA....35..327M>;
 337 Historical values of the Earth's clock error. J Hist Astron. 2005;36:339
 338 <http://adsabs.harvard.edu/full/2005JHA....36..339M>.
 339
 340 * The relationship between POSIX time (that is, UTC but ignoring leap
 341 seconds) and UTC is not agreed upon after 1972. Although the POSIX
 342 clock officially stops during an inserted leap second, at least one
 343 proposed standard has it jumping back a second instead; and in
 344 practice POSIX clocks more typically either progress glacially during
 345 a leap second, or are slightly slowed while near a leap second.
 346
 347 * The tz database does not represent how uncertain its information is.
 348 Ideally it would contain information about when the data are
 349 incomplete or dicey. Partial temporal knowledge is a field of
 350 active research, though, and it's not clear how to apply it here.
 351
 352In short, many, perhaps most, of the tz database's pre-1970 and future
 353time stamps are either wrong or misleading. Any attempt to pass the
 354tz database off as the definition of time should be unacceptable to
 355anybody who cares about the facts. In particular, the tz database's
 356LMT offsets should not be considered meaningful, and should not prompt
 357creation of zones merely because two locations differ in LMT or
 358transitioned to standard time at different dates.
 359
219 360
220----- Names of time zone rule files ----- 361----- Names of time zone rule files -----
221 362
222The time zone rule file naming conventions attempt to strike a balance 363The time zone rule file naming conventions attempt to strike a balance
223among the following goals: 364among the following goals:
224 365
225 * Uniquely identify every national region where clocks have all 366 * Uniquely identify every national region where clocks have all
226 agreed since 1970. This is essential for the intended use: static 367 agreed since 1970. This is essential for the intended use: static
227 clocks keeping local civil time. 368 clocks keeping local civil time.
228 369
229 * Indicate to humans as to where that region is. This simplifies use. 370 * Indicate to humans as to where that region is. This simplifies use.
230 371
231 * Be robust in the presence of political changes. This reduces the 372 * Be robust in the presence of political changes. This reduces the
@@ -241,177 +382,193 @@ among the following goals: @@ -241,177 +382,193 @@ among the following goals:
241 * Use a consistent naming convention over the entire world. 382 * Use a consistent naming convention over the entire world.
242 This simplifies both use and maintenance. 383 This simplifies both use and maintenance.
243 384
244This naming convention is not intended for use by inexperienced users 385This naming convention is not intended for use by inexperienced users
245to select TZ values by themselves (though they can of course examine 386to select TZ values by themselves (though they can of course examine
246and reuse existing settings). Distributors should provide 387and reuse existing settings). Distributors should provide
247documentation and/or a simple selection interface that explains the 388documentation and/or a simple selection interface that explains the
248names; see the 'tzselect' program supplied with this distribution for 389names; see the 'tzselect' program supplied with this distribution for
249one example. 390one example.
250 391
251Names normally have the form AREA/LOCATION, where AREA is the name 392Names normally have the form AREA/LOCATION, where AREA is the name
252of a continent or ocean, and LOCATION is the name of a specific 393of a continent or ocean, and LOCATION is the name of a specific
253location within that region. North and South America share the same 394location within that region. North and South America share the same
254area, `America'. Typical names are `Africa/Cairo', `America/New_York', 395area, 'America'. Typical names are 'Africa/Cairo', 'America/New_York',
255and `Pacific/Honolulu'. 396and 'Pacific/Honolulu'.
256 397
257Here are the general rules used for choosing location names, 398Here are the general rules used for choosing location names,
258in decreasing order of importance: 399in decreasing order of importance:
259 400
260 Use only valid POSIX file name components (i.e., the parts of 401 Use only valid POSIX file name components (i.e., the parts of
261 names other than `/'). Within a file name component, 402 names other than '/'). Do not use the file name
262 use only ASCII letters, `.', `-' and `_'. Do not use 403 components '.' and '..'. Within a file name component,
 404 use only ASCII letters, '.', '-' and '_'. Do not use
263 digits, as that might create an ambiguity with POSIX 405 digits, as that might create an ambiguity with POSIX
264 TZ strings. A file name component must not exceed 14 406 TZ strings. A file name component must not exceed 14
265 characters or start with `-'. E.g., prefer `Brunei' 407 characters or start with '-'. E.g., prefer 'Brunei'
266 to `Bandar_Seri_Begawan'. 408 to 'Bandar_Seri_Begawan'.
 409 A name must not be empty, or contain '//', or start or end with '/'.
267 Do not use names that differ only in case. Although the reference 410 Do not use names that differ only in case. Although the reference
268 implementation is case-sensitive, some other implementations 411 implementation is case-sensitive, some other implementations
269 are not, and they would mishandle names differing only in case. 412 are not, and they would mishandle names differing only in case.
 413 If one name A is an initial prefix of another name AB (ignoring case),
 414 then B must not start with '/', as a regular file cannot have
 415 the same name as a directory in POSIX. For example,
 416 'America/New_York' precludes 'America/New_York/Bronx'.
270 Uninhabited regions like the North Pole and Bouvet Island 417 Uninhabited regions like the North Pole and Bouvet Island
271 do not need locations, since local time is not defined there. 418 do not need locations, since local time is not defined there.
 419 There should typically be at least one name for each ISO 3166-1
 420 officially assigned two-letter code for an inhabited country
 421 or territory.
272 If all the clocks in a region have agreed since 1970, 422 If all the clocks in a region have agreed since 1970,
273 don't bother to include more than one location 423 don't bother to include more than one location
274 even if subregions' clocks disagreed before 1970. 424 even if subregions' clocks disagreed before 1970.
275 Otherwise these tables would become annoyingly large. 425 Otherwise these tables would become annoyingly large.
276 If a name is ambiguous, use a less ambiguous alternative; 426 If a name is ambiguous, use a less ambiguous alternative;
277 e.g. many cities are named San Jose and Georgetown, so 427 e.g. many cities are named San Jose and Georgetown, so
278 prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'. 428 prefer 'Costa_Rica' to 'San_Jose' and 'Guyana' to 'Georgetown'.
279 Keep locations compact. Use cities or small islands, not countries 429 Keep locations compact. Use cities or small islands, not countries
280 or regions, so that any future time zone changes do not split 430 or regions, so that any future time zone changes do not split
281 locations into different time zones. E.g. prefer `Paris' 431 locations into different time zones. E.g. prefer 'Paris'
282 to `France', since France has had multiple time zones. 432 to 'France', since France has had multiple time zones.
283 Use mainstream English spelling, e.g. prefer `Rome' to `Roma', and 433 Use mainstream English spelling, e.g. prefer 'Rome' to 'Roma', and
284 prefer `Athens' to the true name (which uses Greek letters). 434 prefer 'Athens' to the true name (which uses Greek letters).
285 The POSIX file name restrictions encourage this rule. 435 The POSIX file name restrictions encourage this rule.
286 Use the most populous among locations in a zone, 436 Use the most populous among locations in a zone,
287 e.g. prefer `Shanghai' to `Beijing'. Among locations with 437 e.g. prefer 'Shanghai' to 'Beijing'. Among locations with
288 similar populations, pick the best-known location, 438 similar populations, pick the best-known location,
289 e.g. prefer `Rome' to `Milan'. 439 e.g. prefer 'Rome' to 'Milan'.
290 Use the singular form, e.g. prefer `Canary' to `Canaries'. 440 Use the singular form, e.g. prefer 'Canary' to 'Canaries'.
291 Omit common suffixes like `_Islands' and `_City', unless that 441 Omit common suffixes like '_Islands' and '_City', unless that
292 would lead to ambiguity. E.g. prefer `Cayman' to 442 would lead to ambiguity. E.g. prefer 'Cayman' to
293 `Cayman_Islands' and `Guatemala' to `Guatemala_City', 443 'Cayman_Islands' and 'Guatemala' to 'Guatemala_City',
294 but prefer `Mexico_City' to `Mexico' because the country 444 but prefer 'Mexico_City' to 'Mexico' because the country
295 of Mexico has several time zones. 445 of Mexico has several time zones.
296 Use `_' to represent a space. 446 Use '_' to represent a space.
297 Omit `.' from abbreviations in names, e.g. prefer `St_Helena' 447 Omit '.' from abbreviations in names, e.g. prefer 'St_Helena'
298 to `St._Helena'. 448 to 'St._Helena'.
299 Do not change established names if they only marginally 449 Do not change established names if they only marginally
300 violate the above rules. For example, don't change 450 violate the above rules. For example, don't change
301 the existing name `Rome' to `Milan' merely because 451 the existing name 'Rome' to 'Milan' merely because
302 Milan's population has grown to be somewhat greater 452 Milan's population has grown to be somewhat greater
303 than Rome's. 453 than Rome's.
304 If a name is changed, put its old spelling in the `backward' file. 454 If a name is changed, put its old spelling in the 'backward' file.
305 This means old spellings will continue to work. 455 This means old spellings will continue to work.
306 456
307The file `zone.tab' lists the geographical locations used to name 457The file 'zone.tab' lists geographical locations used to name time
308time zone rule files. It is intended to be an exhaustive list 458zone rule files. It is intended to be an exhaustive list of names
309of names for geographic regions as described above. 459for geographic regions as described above; this is a subset of the
 460names in the data. Although a 'zone.tab' location's longitude
 461corresponds to its LMT offset with one hour for every 15 degrees east
 462longitude, this relationship is not exact.
310 463
311Older versions of this package used a different naming scheme, 464Older versions of this package used a different naming scheme,
312and these older names are still supported. 465and these older names are still supported.
313See the file `backward' for most of these older names 466See the file 'backward' for most of these older names
314(e.g. `US/Eastern' instead of `America/New_York'). 467(e.g. 'US/Eastern' instead of 'America/New_York');
 468excluding 'backward' should not affect the other data.
315The other old-fashioned names still supported are 469The other old-fashioned names still supported are
316`WET', `CET', `MET', and `EET' (see the file `europe'). 470'WET', 'CET', 'MET', and 'EET' (see the file 'europe').
317 471
318 472
319----- Time zone abbreviations ----- 473----- Time zone abbreviations -----
320 474
321When this package is installed, it generates time zone abbreviations 475When this package is installed, it generates time zone abbreviations
322like `EST' to be compatible with human tradition and POSIX. 476like 'EST' to be compatible with human tradition and POSIX.
323Here are the general rules used for choosing time zone abbreviations, 477Here are the general rules used for choosing time zone abbreviations,
324in decreasing order of importance: 478in decreasing order of importance:
325 479
326 Use abbreviations that consist of three or more ASCII letters. 480 Use abbreviations that consist of three or more ASCII letters.
327 Previous editions of this database also used characters like 481 Previous editions of this database also used characters like
328 ' ' and '?', but these characters have a special meaning to 482 ' ' and '?', but these characters have a special meaning to
329 the shell and cause commands like 483 the shell and cause commands like
330 set `date` 484 set `date`
331 to have unexpected effects. 485 to have unexpected effects.
332 Previous editions of this rule required upper-case letters, 486 Previous editions of this rule required upper-case letters,
333 but the Congressman who introduced Chamorro Standard Time 487 but the Congressman who introduced Chamorro Standard Time
334 preferred "ChST", so the rule has been relaxed. 488 preferred "ChST", so the rule has been relaxed.
335 489
336 This rule guarantees that all abbreviations could have 490 This rule guarantees that all abbreviations could have
337 been specified by a POSIX TZ string. POSIX 491 been specified by a POSIX TZ string. POSIX
338 requires at least three characters for an 492 requires at least three characters for an
339 abbreviation. POSIX through 2000 says that an abbreviation 493 abbreviation. POSIX through 2000 says that an abbreviation
340 cannot start with ':', and cannot contain ',', '-', 494 cannot start with ':', and cannot contain ',', '-',
341 '+', NUL, or a digit. POSIX from 2001 on changes this 495 '+', NUL, or a digit. POSIX from 2001 on changes this
342 rule to say that an abbreviation can contain only '-', '+', 496 rule to say that an abbreviation can contain only '-', '+',
343 and alphanumeric characters from the portable character set 497 and alphanumeric characters from the portable character set
344 in the current locale. To be portable to both sets of 498 in the current locale. To be portable to both sets of
345 rules, an abbreviation must therefore use only ASCII 499 rules, an abbreviation must therefore use only ASCII
346 letters. 500 letters.
347 501
348 Use abbreviations that are in common use among English-speakers, 502 Use abbreviations that are in common use among English-speakers,
349 e.g. `EST' for Eastern Standard Time in North America. 503 e.g. 'EST' for Eastern Standard Time in North America.
350 We assume that applications translate them to other languages 504 We assume that applications translate them to other languages
351 as part of the normal localization process; for example, 505 as part of the normal localization process; for example,
352 a French application might translate `EST' to `HNE'. 506 a French application might translate 'EST' to 'HNE'.
353 507
354 For zones whose times are taken from a city's longitude, use the 508 For zones whose times are taken from a city's longitude, use the
355 traditional xMT notation, e.g. `PMT' for Paris Mean Time. 509 traditional xMT notation, e.g. 'PMT' for Paris Mean Time.
356 The only name like this in current use is `GMT'. 510 The only name like this in current use is 'GMT'.
357 511
358 If there is no common English abbreviation, abbreviate the English 512 If there is no common English abbreviation, abbreviate the English
359 translation of the usual phrase used by native speakers. 513 translation of the usual phrase used by native speakers.
360 If this is not available or is a phrase mentioning the country 514 If this is not available or is a phrase mentioning the country
361 (e.g. ``Cape Verde Time''), then: 515 (e.g. "Cape Verde Time"), then:
362 516
363 When a country is identified with a single or principal zone, 517 When a country is identified with a single or principal zone,
364 append `T' to the country's ISO code, e.g. `CVT' for 518 append 'T' to the country's ISO code, e.g. 'CVT' for
365 Cape Verde Time. For summer time append `ST'; 519 Cape Verde Time. For summer time append 'ST';
366 for double summer time append `DST'; etc. 520 for double summer time append 'DST'; etc.
367 Otherwise, take the first three letters of an English place 521 Otherwise, take the first three letters of an English place
368 name identifying each zone and append 'T', 'ST', etc. 522 name identifying each zone and append 'T', 'ST', etc.
369 as before; e.g. 'VLAST' for VLAdivostok Summer Time. 523 as before; e.g. 'VLAST' for VLAdivostok Summer Time.
370 524
371 Use UTC (with time zone abbreviation "zzz") for locations while 525 Use 'LMT' for local mean time of locations before the introduction
372 uninhabited. The "zzz" mnemonic is that these locations are, 526 of standard time; see "Scope of the tz database".
 527
 528 Use UT (with time zone abbreviation 'zzz') for locations while
 529 uninhabited. The 'zzz' mnemonic is that these locations are,
373 in some sense, asleep. 530 in some sense, asleep.
374 531
375Application writers should note that these abbreviations are ambiguous 532Application writers should note that these abbreviations are ambiguous
376in practice: e.g. `EST' has a different meaning in Australia than 533in practice: e.g. 'EST' has a different meaning in Australia than
377it does in the United States. In new applications, it's often better 534it does in the United States. In new applications, it's often better
378to use numeric UTC offsets like `-0500' instead of time zone 535to use numeric UT offsets like '-0500' instead of time zone
379abbreviations like `EST'; this avoids the ambiguity. 536abbreviations like 'EST'; this avoids the ambiguity.
380 537
381 538
382----- Calendrical issues ----- 539----- Calendrical issues -----
383 540
384Calendrical issues are a bit out of scope for a time zone database, 541Calendrical issues are a bit out of scope for a time zone database,
385but they indicate the sort of problems that we would run into if we 542but they indicate the sort of problems that we would run into if we
386extended the time zone database further into the past. An excellent 543extended the time zone database further into the past. An excellent
387resource in this area is Nachum Dershowitz and Edward M. Reingold, 544resource in this area is Nachum Dershowitz and Edward M. Reingold,
388<a href="http://emr.cs.iit.edu/home/reingold/calendar-book/third-edition/"> 545<a href="http://emr.cs.iit.edu/home/reingold/calendar-book/third-edition/">
389Calendrical Calculations: Third Edition 546Calendrical Calculations: Third Edition
390</a>, Cambridge University Press (2008). Other information and 547</a>, Cambridge University Press (2008). Other information and
391sources are given below. They sometimes disagree. 548sources are given below. They sometimes disagree.
392 549
393 550
394France 551France
395 552
396Gregorian calendar adopted 1582-12-20. 553Gregorian calendar adopted 1582-12-20.
397French Revolutionary calendar used 1793-11-24 through 1805-12-31, 554French Revolutionary calendar used 1793-11-24 through 1805-12-31,
398and (in Paris only) 1871-05-06 through 1871-05-23. 555and (in Paris only) 1871-05-06 through 1871-05-23.
399 556
400 557
401Russia 558Russia
402 559
403From Chris Carrier (1996-12-02): 560From Chris Carrier (1996-12-02):
404On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar'' 561On 1929-10-01 the Soviet Union instituted an "Eternal Calendar"
405with 30-day months plus 5 holidays, with a 5-day week. 562with 30-day months plus 5 holidays, with a 5-day week.
406On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the 563On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
407Gregorian calendar while retaining the 6-day week; on 1940-06-27 it 564Gregorian calendar while retaining the 6-day week; on 1940-06-27 it
408reverted to the 7-day week. With the 6-day week the usual days 565reverted to the 7-day week. With the 6-day week the usual days
409off were the 6th, 12th, 18th, 24th and 30th of the month. 566off were the 6th, 12th, 18th, 24th and 30th of the month.
410(Source: Evitiar Zerubavel, _The Seven Day Circle_) 567(Source: Evitiar Zerubavel, _The Seven Day Circle_)
411 568
412 569
413Mark Brader reported a similar story in "The Book of Calendars", edited 570Mark Brader reported a similar story in "The Book of Calendars", edited
414by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But: 571by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But:
415 572
416From: Petteri Sulonen (via Usenet) 573From: Petteri Sulonen (via Usenet)
417Date: 14 Jan 1999 00:00:00 GMT 574Date: 14 Jan 1999 00:00:00 GMT

cvs diff -r1.5 -r1.6 src/lib/libc/time/checktab.awk (expand / switch to unified diff)

--- src/lib/libc/time/checktab.awk 2012/08/09 12:38:25 1.5
+++ src/lib/libc/time/checktab.awk 2013/09/20 19:06:54 1.6
@@ -1,26 +1,29 @@ @@ -1,26 +1,29 @@
1# $NetBSD: checktab.awk,v 1.5 2012/08/09 12:38:25 christos Exp $ 1# $NetBSD: checktab.awk,v 1.6 2013/09/20 19:06:54 christos Exp $
2 2
3# Check tz tables for consistency. 3# Check tz tables for consistency.
4 4
5# Contributed by Paul Eggert. 5# Contributed by Paul Eggert.
6 6
7BEGIN { 7BEGIN {
8 FS = "\t" 8 FS = "\t"
9 9
10 if (!iso_table) iso_table = "iso3166.tab" 10 if (!iso_table) iso_table = "iso3166.tab"
11 if (!zone_table) zone_table = "zone.tab" 11 if (!zone_table) zone_table = "zone.tab"
12 if (!want_warnings) want_warnings = -1 12 if (!want_warnings) want_warnings = -1
13 13
 14 # A special (and we hope temporary) case.
 15 tztab["America/Montreal"] = 1
 16
14 while (getline <iso_table) { 17 while (getline <iso_table) {
15 iso_NR++ 18 iso_NR++
16 if ($0 ~ /^#/) continue 19 if ($0 ~ /^#/) continue
17 if (NF != 2) { 20 if (NF != 2) {
18 printf "%s:%d: wrong number of columns\n", \ 21 printf "%s:%d: wrong number of columns\n", \
19 iso_table, iso_NR >>"/dev/stderr" 22 iso_table, iso_NR >>"/dev/stderr"
20 status = 1 23 status = 1
21 } 24 }
22 cc = $1 25 cc = $1
23 name = $2 26 name = $2
24 if (cc !~ /^[A-Z][A-Z]$/) { 27 if (cc !~ /^[A-Z][A-Z]$/) {
25 printf "%s:%d: invalid country code `%s'\n", \ 28 printf "%s:%d: invalid country code `%s'\n", \
26 iso_table, iso_NR, cc >>"/dev/stderr" 29 iso_table, iso_NR, cc >>"/dev/stderr"
@@ -61,83 +64,83 @@ BEGIN { @@ -61,83 +64,83 @@ BEGIN {
61 zone_table, zone_NR >>"/dev/stderr" 64 zone_table, zone_NR >>"/dev/stderr"
62 status = 1 65 status = 1
63 } 66 }
64 cc = $1 67 cc = $1
65 coordinates = $2 68 coordinates = $2
66 tz = $3 69 tz = $3
67 comments = $4 70 comments = $4
68 if (cc < cc0) { 71 if (cc < cc0) {
69 printf "%s:%d: country code `%s' is out of order\n", \ 72 printf "%s:%d: country code `%s' is out of order\n", \
70 zone_table, zone_NR, cc >>"/dev/stderr" 73 zone_table, zone_NR, cc >>"/dev/stderr"
71 status = 1 74 status = 1
72 } 75 }
73 cc0 = cc 76 cc0 = cc
74 if (tz2cc[tz]) { 77 cctz = cc tz
75 printf "%s:%d: %s: duplicate TZ column\n", \ 78 cctztab[cctz] = 1
76 zone_table, zone_NR, tz >>"/dev/stderr" 79 tztab[tz] = 1
77 status = 1 80 tz2comments[cctz] = comments
78 } 
79 tz2cc[tz] = cc 
80 tz2comments[tz] = comments 
81 tz2NR[tz] = zone_NR 81 tz2NR[tz] = zone_NR
82 if (cc2name[cc]) { 82 if (cc2name[cc]) {
83 cc_used[cc]++ 83 cc_used[cc]++
84 } else { 84 } else {
85 printf "%s:%d: %s: unknown country code\n", \ 85 printf "%s:%d: %s: unknown country code\n", \
86 zone_table, zone_NR, cc >>"/dev/stderr" 86 zone_table, zone_NR, cc >>"/dev/stderr"
87 status = 1 87 status = 1
88 } 88 }
89 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \ 89 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
90 && coordinates !~ /^[-+][0-9][0-9][0-5][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9][0-5][0-9]$/) { 90 && coordinates !~ /^[-+][0-9][0-9][0-5][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9][0-5][0-9]$/) {
91 printf "%s:%d: %s: invalid coordinates\n", \ 91 printf "%s:%d: %s: invalid coordinates\n", \
92 zone_table, zone_NR, coordinates >>"/dev/stderr" 92 zone_table, zone_NR, coordinates >>"/dev/stderr"
93 status = 1 93 status = 1
94 } 94 }
95 } 95 }
96 96
97 for (tz in tz2cc) { 97 for (cctz in cctztab) {
98 if (cc_used[tz2cc[tz]] == 1) { 98 cc = substr (cctz, 1, 2)
99 if (tz2comments[tz]) { 99 tz = substr (cctz, 3)
 100 if (cc_used[cc] == 1) {
 101 if (tz2comments[cctz]) {
100 printf "%s:%d: unnecessary comment `%s'\n", \ 102 printf "%s:%d: unnecessary comment `%s'\n", \
101 zone_table, tz2NR[tz], tz2comments[tz] \ 103 zone_table, tz2NR[tz], \
 104 tz2comments[cctz] \
102 >>"/dev/stderr" 105 >>"/dev/stderr"
103 status = 1 106 status = 1
104 } 107 }
105 } else { 108 } else {
106 if (!tz2comments[tz]) { 109 if (!tz2comments[cctz]) {
107 printf "%s:%d: missing comment\n", \ 110 printf "%s:%d: missing comment\n", \
108 zone_table, tz2NR[tz] >>"/dev/stderr" 111 zone_table, tz2NR[tz] >>"/dev/stderr"
109 status = 1 112 status = 1
110 } 113 }
111 } 114 }
112 } 115 }
113 116
114 FS = " " 117 FS = " "
115} 118}
116 119
117{ 120{
118 tz = "" 121 tz = ""
119 if ($1 == "Zone") tz = $2 122 if ($1 == "Zone") tz = $2
120 if ($1 == "Link") { 123 if ($1 == "Link") {
121 # Ignore Link commands if source and destination basenames 124 # Ignore Link commands if source and destination basenames
122 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul. 125 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
123 src = $2 126 src = $2
124 dst = $3 127 dst = $3
125 while ((i = index(src, "/"))) src = substr(src, i+1) 128 while ((i = index(src, "/"))) src = substr(src, i+1)
126 while ((i = index(dst, "/"))) dst = substr(dst, i+1) 129 while ((i = index(dst, "/"))) dst = substr(dst, i+1)
127 if (src != dst) tz = $3 130 if (src != dst) tz = $3
128 } 131 }
129 if (tz && tz ~ /\//) { 132 if (tz && tz ~ /\//) {
130 if (!tz2cc[tz]) { 133 if (!tztab[tz]) {
131 printf "%s: no data for `%s'\n", zone_table, tz \ 134 printf "%s: no data for `%s'\n", zone_table, tz \
132 >>"/dev/stderr" 135 >>"/dev/stderr"
133 status = 1 136 status = 1
134 } 137 }
135 zoneSeen[tz] = 1 138 zoneSeen[tz] = 1
136 } 139 }
137} 140}
138 141
139END { 142END {
140 for (tz in tz2cc) { 143 for (tz in tz2cc) {
141 if (!zoneSeen[tz]) { 144 if (!zoneSeen[tz]) {
142 printf "%s:%d: no Zone table for `%s'\n", \ 145 printf "%s:%d: no Zone table for `%s'\n", \
143 zone_table, tz2NR[tz], tz >>"/dev/stderr" 146 zone_table, tz2NR[tz], tz >>"/dev/stderr"

cvs diff -r1.47 -r1.48 src/lib/libc/time/ctime.3 (expand / switch to unified diff)

--- src/lib/libc/time/ctime.3 2013/01/19 11:56:17 1.47
+++ src/lib/libc/time/ctime.3 2013/09/20 19:06:54 1.48
@@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
1.\" $NetBSD: ctime.3,v 1.47 2013/01/19 11:56:17 apb Exp $ 1.\" $NetBSD: ctime.3,v 1.48 2013/09/20 19:06:54 christos Exp $
2.\" 2.\"
3.\" XXX: License missing? 3.\" XXX: License missing?
4.\" 4.\"
5.Dd January 19, 2013 5.Dd September 20, 2013
6.Dt CTIME 3 6.Dt CTIME 3
7.Os 7.Os
8.Sh NAME 8.Sh NAME
9.Nm asctime , 9.Nm asctime ,
10.Nm asctime_r , 10.Nm asctime_r ,
11.Nm ctime , 11.Nm ctime ,
12.Nm ctime_r , 12.Nm ctime_r ,
13.Nm ctime_rz , 13.Nm ctime_rz ,
14.Nm difftime , 14.Nm difftime ,
15.Nm gmtime , 15.Nm gmtime ,
16.Nm gmtime_r , 16.Nm gmtime_r ,
17.Nm localtime , 17.Nm localtime ,
18.Nm localtime_r , 18.Nm localtime_r ,
@@ -86,38 +86,48 @@ The @@ -86,38 +86,48 @@ The
86.Fn asctime_r 86.Fn asctime_r
87has the same behavior as 87has the same behavior as
88.Fn asctime , 88.Fn asctime ,
89but the result is stored to 89but the result is stored to
90.Fa buf , 90.Fa buf ,
91which should have a size of at least 26 bytes. 91which should have a size of at least 26 bytes.
92.It Fn ctime "clock" 92.It Fn ctime "clock"
93The 93The
94.Fn ctime 94.Fn ctime
95function converts a 95function converts a
96.Vt time_t , 96.Vt time_t ,
97pointed to by 97pointed to by
98.Fa clock , 98.Fa clock ,
99representing the time in seconds since 00:00:00 UTC, 1970-01-01, 
100and returns a pointer to a string with the format described above. 99and returns a pointer to a string with the format described above.
101Years requiring fewer than four characters are padded with leading zeroes. 100Years requiring fewer than four characters are padded with leading zeroes.
102For years longer than four characters, the string is of the form 101For years longer than four characters, the string is of the form
103.Bd -literal -offset indent 102.Bd -literal -offset indent
104.D1 "Thu Nov 24 18:22:48 81986\en\e0" 103.D1 "Thu Nov 24 18:22:48 81986\en\e0"
105.Ed 104.Ed
106.Pp 105.Pp
107with five spaces before the year. 106with five spaces before the year.
108These unusual formats are designed to make it less likely that older 107These unusual formats are designed to make it less likely that older
109software that expects exactly 26 bytes of output will mistakenly output 108software that expects exactly 26 bytes of output will mistakenly output
110misleading values for out-of-range years. 109misleading values for out-of-range years.
 110.Pp
 111The
 112.Fa clock
 113time stamp represents the time in seconds since 1970-01-01 00:00:00
 114Coordinated Universal Time (UTC).
 115The POSIX standard says that time stamps must be nonnegative
 116and must ignore leap seconds.
 117Many implementations extend POSIX by allowing negative time stamps,
 118and can therefore represent time stamps that predate the
 119introduction of UTC and are some other flavor of Universal Time (UT).
 120Some implementations support leap seconds, in contradiction to POSIX.
111.It Fn ctime_r "clock" "buf" 121.It Fn ctime_r "clock" "buf"
112The 122The
113.Fn ctime_r 123.Fn ctime_r
114is similar to 124is similar to
115.Fn ctime , 125.Fn ctime ,
116except it places the result of the conversion on the 126except it places the result of the conversion on the
117.Fa buf 127.Fa buf
118argument, which should be 26 or more bytes long, 128argument, which should be 26 or more bytes long,
119instead of using a global static buffer. 129instead of using a global static buffer.
120.It Fn ctime_rz "tz" "clock" "buf" 130.It Fn ctime_rz "tz" "clock" "buf"
121The 131The
122.Fn ctime_rz 132.Fn ctime_rz
123function is similar to 133function is similar to
@@ -319,26 +329,68 @@ returns the name for the given @@ -319,26 +329,68 @@ returns the name for the given
319If 329If
320.Fa isdst 330.Fa isdst
321is 331is
322.Va 0 , 332.Va 0 ,
323the call is equivalent to 333the call is equivalent to
324.Va tzname[0] . 334.Va tzname[0] .
325If 335If
326.Fa isdst 336.Fa isdst
327is set to 337is set to
328.Va 1 338.Va 1
329the call is equivalent to 339the call is equivalent to
330.Va tzname[1] . 340.Va tzname[1] .
331.El 341.El
 342.Pp
 343Declarations of all the functions and externals, and the
 344.Ft tm
 345structure, are in the
 346.In time.h
 347header file.
 348The structure (of type)
 349.Ft struct tm
 350includes the following fields:
 351.Bd -literal
 352 int tm_sec; /* seconds (0 - 60) */
 353 int tm_min; /* minutes (0 - 59) */
 354 int tm_hour; /* hours (0 - 23) */
 355 int tm_mday; /* day of month (1 - 31) */
 356 int tm_mon; /* month of year (0 - 11) */
 357 int tm_year; /* year - 1900 */
 358 int tm_wday; /* day of week (Sunday = 0) */
 359 int tm_yday; /* day of year (0 - 365) */
 360 int tm_isdst; /* is summer time in effect? */
 361 char *tm_zone; /* abbreviation of timezone name */
 362 long tm_gmtoff; /* offset from UT in seconds */
 363.Ed
 364.Pp
 365The
 366.Fa tm_zone
 367and
 368.Fa tm_gmtoff
 369fields exist, and are filled in, only if
 370arrangements to do so were made when the library containing these functions
 371was created.
 372There is no guarantee that these fields will continue to exist in this form
 373in future releases of this code.
 374.Bl -bullet
 375.It
 376.Va tm_isdst
 377is non-zero if summer time is in effect.
 378.It
 379.Va tm_gmtoff
 380is the offset (in seconds) of the time represented from UT,
 381with positive values indicating east of the Prime Meridian.
 382The field's name is derived from Greenwich Mean Time, a precursor of UT.
 383.El
332.Sh RETURN VALUES 384.Sh RETURN VALUES
333.Bl -bullet 385.Bl -bullet
334.It 386.It
335On success the 387On success the
336.Fn asctime 388.Fn asctime
337and 389and
338.Fn ctime 390.Fn ctime
339functions return a pointer to a static character buffer, and the 391functions return a pointer to a static character buffer, and the
340.Fn asctime_r , 392.Fn asctime_r ,
341.Fn ctime_r , 393.Fn ctime_r ,
342and 394and
343.Fn ctime_rz 395.Fn ctime_rz
344function return a pointer to the user-supplied buffer. 396function return a pointer to the user-supplied buffer.

cvs diff -r1.77 -r1.78 src/lib/libc/time/localtime.c (expand / switch to unified diff)

--- src/lib/libc/time/localtime.c 2013/07/30 15:30:37 1.77
+++ src/lib/libc/time/localtime.c 2013/09/20 19:06:54 1.78
@@ -1,49 +1,48 @@ @@ -1,49 +1,48 @@
1/* $NetBSD: localtime.c,v 1.77 2013/07/30 15:30:37 joerg Exp $ */ 1/* $NetBSD: localtime.c,v 1.78 2013/09/20 19:06:54 christos Exp $ */
2 2
3/* 3/*
4** This file is in the public domain, so clarified as of 4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson. 5** 1996-06-05 by Arthur David Olson.
6*/ 6*/
7 7
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#if defined(LIBC_SCCS) && !defined(lint) 9#if defined(LIBC_SCCS) && !defined(lint)
10#if 0 10#if 0
11static char elsieid[] = "@(#)localtime.c 8.17"; 11static char elsieid[] = "@(#)localtime.c 8.17";
12#else 12#else
13__RCSID("$NetBSD: localtime.c,v 1.77 2013/07/30 15:30:37 joerg Exp $"); 13__RCSID("$NetBSD: localtime.c,v 1.78 2013/09/20 19:06:54 christos Exp $");
14#endif 14#endif
15#endif /* LIBC_SCCS and not lint */ 15#endif /* LIBC_SCCS and not lint */
16 16
17/* 17/*
18** Leap second handling from Bradley White. 18** Leap second handling from Bradley White.
19** POSIX-style TZ environment variable handling from Guy Harris. 19** POSIX-style TZ environment variable handling from Guy Harris.
20*/ 20*/
21 21
22/*LINTLIBRARY*/ 22/*LINTLIBRARY*/
23 23
24#include "namespace.h" 24#include "namespace.h"
 25#include <assert.h>
25#include "private.h" 26#include "private.h"
26#include "tzfile.h" 27#include "tzfile.h"
27#include "fcntl.h" 28#include "fcntl.h"
28#include "reentrant.h" 29#include "reentrant.h"
29 30
30#if defined(__weak_alias) 31#if defined(__weak_alias)
31__weak_alias(daylight,_daylight) 32__weak_alias(daylight,_daylight)
32__weak_alias(tzname,_tzname) 33__weak_alias(tzname,_tzname)
33#endif 34#endif
34 35
35#include "float.h" /* for FLT_MAX and DBL_MAX */ 
36 
37#ifndef TZ_ABBR_MAX_LEN 36#ifndef TZ_ABBR_MAX_LEN
38#define TZ_ABBR_MAX_LEN 16 37#define TZ_ABBR_MAX_LEN 16
39#endif /* !defined TZ_ABBR_MAX_LEN */ 38#endif /* !defined TZ_ABBR_MAX_LEN */
40 39
41#ifndef TZ_ABBR_CHAR_SET 40#ifndef TZ_ABBR_CHAR_SET
42#define TZ_ABBR_CHAR_SET \ 41#define TZ_ABBR_CHAR_SET \
43 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" 42 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
44#endif /* !defined TZ_ABBR_CHAR_SET */ 43#endif /* !defined TZ_ABBR_CHAR_SET */
45 44
46#ifndef TZ_ABBR_ERR_CHAR 45#ifndef TZ_ABBR_ERR_CHAR
47#define TZ_ABBR_ERR_CHAR '_' 46#define TZ_ABBR_ERR_CHAR '_'
48#endif /* !defined TZ_ABBR_ERR_CHAR */ 47#endif /* !defined TZ_ABBR_ERR_CHAR */
49 48
@@ -87,31 +86,31 @@ static const char gmt[] = "GMT"; @@ -87,31 +86,31 @@ static const char gmt[] = "GMT";
87 86
88/* 87/*
89** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. 88** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
90** We default to US rules as of 1999-08-17. 89** We default to US rules as of 1999-08-17.
91** POSIX 1003.1 section 8.1.1 says that the default DST rules are 90** POSIX 1003.1 section 8.1.1 says that the default DST rules are
92** implementation dependent; for historical reasons, US rules are a 91** implementation dependent; for historical reasons, US rules are a
93** common default. 92** common default.
94*/ 93*/
95#ifndef TZDEFRULESTRING 94#ifndef TZDEFRULESTRING
96#define TZDEFRULESTRING ",M4.1.0,M10.5.0" 95#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
97#endif /* !defined TZDEFDST */ 96#endif /* !defined TZDEFDST */
98 97
99struct ttinfo { /* time type information */ 98struct ttinfo { /* time type information */
100 int_fast32_t tt_gmtoff; /* UTC offset in seconds */ 99 int_fast32_t tt_gmtoff; /* UT offset in seconds */
101 int tt_isdst; /* used to set tm_isdst */ 100 int tt_isdst; /* used to set tm_isdst */
102 int tt_abbrind; /* abbreviation list index */ 101 int tt_abbrind; /* abbreviation list index */
103 int tt_ttisstd; /* TRUE if transition is std time */ 102 int tt_ttisstd; /* TRUE if transition is std time */
104 int tt_ttisgmt; /* TRUE if transition is UTC */ 103 int tt_ttisgmt; /* TRUE if transition is UT */
105}; 104};
106 105
107struct lsinfo { /* leap second information */ 106struct lsinfo { /* leap second information */
108 time_t ls_trans; /* transition time */ 107 time_t ls_trans; /* transition time */
109 int_fast64_t ls_corr; /* correction to apply */ 108 int_fast64_t ls_corr; /* correction to apply */
110}; 109};
111 110
112#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 111#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
113 112
114#ifdef TZNAME_MAX 113#ifdef TZNAME_MAX
115#define MY_TZNAME_MAX TZNAME_MAX 114#define MY_TZNAME_MAX TZNAME_MAX
116#endif /* defined TZNAME_MAX */ 115#endif /* defined TZNAME_MAX */
117#ifndef TZNAME_MAX 116#ifndef TZNAME_MAX
@@ -347,29 +346,28 @@ settzname(void) @@ -347,29 +346,28 @@ settzname(void)
347 timezone = -(ttisp->tt_gmtoff); 346 timezone = -(ttisp->tt_gmtoff);
348#endif /* defined USG_COMPAT */ 347#endif /* defined USG_COMPAT */
349#ifdef ALTZONE 348#ifdef ALTZONE
350 if (ttisp->tt_isdst) 349 if (ttisp->tt_isdst)
351 altzone = -(ttisp->tt_gmtoff); 350 altzone = -(ttisp->tt_gmtoff);
352#endif /* defined ALTZONE */ 351#endif /* defined ALTZONE */
353 } 352 }
354 settzname_z(sp); 353 settzname_z(sp);
355} 354}
356 355
357static int 356static int
358differ_by_repeat(const time_t t1, const time_t t0) 357differ_by_repeat(const time_t t1, const time_t t0)
359{ 358{
360 if (TYPE_INTEGRAL(time_t) && 359 if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
361 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) 360 return 0;
362 return 0; 
363 return (int_fast64_t)t1 - (int_fast64_t)t0 == SECSPERREPEAT; 361 return (int_fast64_t)t1 - (int_fast64_t)t0 == SECSPERREPEAT;
364} 362}
365 363
366static int 364static int
367tzload(timezone_t sp, const char *name, const int doextend) 365tzload(timezone_t sp, const char *name, const int doextend)
368{ 366{
369 const char * p; 367 const char * p;
370 int i; 368 int i;
371 int fid; 369 int fid;
372 int stored; 370 int stored;
373 ssize_t nread; 371 ssize_t nread;
374 typedef union { 372 typedef union {
375 struct tzhead tzhead; 373 struct tzhead tzhead;
@@ -556,31 +554,29 @@ tzload(timezone_t sp, const char *name,  @@ -556,31 +554,29 @@ tzload(timezone_t sp, const char *name,
556 sp->timecnt = j; 554 sp->timecnt = j;
557 } 555 }
558 break; 556 break;
559 } 557 }
560 /* 558 /*
561 ** If this is an old file, we're done. 559 ** If this is an old file, we're done.
562 */ 560 */
563 if (up->tzhead.tzh_version[0] == '\0') 561 if (up->tzhead.tzh_version[0] == '\0')
564 break; 562 break;
565 nread -= p - up->buf; 563 nread -= p - up->buf;
566 for (i = 0; i < nread; ++i) 564 for (i = 0; i < nread; ++i)
567 up->buf[i] = p[i]; 565 up->buf[i] = p[i];
568 /* 566 /*
569 ** If this is a narrow integer time_t system, we're done. 567 ** If this is a narrow time_t system, we're done.
570 */ 568 */
571 if (stored >= (int) sizeof(time_t) 569 if (stored >= (int) sizeof(time_t))
572/* CONSTCOND */ 
573 && TYPE_INTEGRAL(time_t)) 
574 break; 570 break;
575 } 571 }
576 if (doextend && nread > 2 && 572 if (doextend && nread > 2 &&
577 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && 573 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
578 sp->typecnt + 2 <= TZ_MAX_TYPES) { 574 sp->typecnt + 2 <= TZ_MAX_TYPES) {
579 struct __state ts; 575 struct __state ts;
580 int result; 576 int result;
581 577
582 up->buf[nread - 1] = '\0'; 578 up->buf[nread - 1] = '\0';
583 result = tzparse(&ts, &up->buf[1], FALSE); 579 result = tzparse(&ts, &up->buf[1], FALSE);
584 if (result == 0 && ts.typecnt == 2 && 580 if (result == 0 && ts.typecnt == 2 &&
585 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { 581 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
586 for (i = 0; i < 2; ++i) 582 for (i = 0; i < 2; ++i)
@@ -870,34 +866,34 @@ getrule(const char *strp, struct rule *c @@ -870,34 +866,34 @@ getrule(const char *strp, struct rule *c
870 /* 866 /*
871 ** Day of year. 867 ** Day of year.
872 */ 868 */
873 rulep->r_type = DAY_OF_YEAR; 869 rulep->r_type = DAY_OF_YEAR;
874 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 870 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
875 } else return NULL; /* invalid format */ 871 } else return NULL; /* invalid format */
876 if (strp == NULL) 872 if (strp == NULL)
877 return NULL; 873 return NULL;
878 if (*strp == '/') { 874 if (*strp == '/') {
879 /* 875 /*
880 ** Time specified. 876 ** Time specified.
881 */ 877 */
882 ++strp; 878 ++strp;
883 strp = getsecs(strp, &rulep->r_time); 879 strp = getoffset(strp, &rulep->r_time);
884 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 880 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
885 return strp; 881 return strp;
886} 882}
887 883
888/* 884/*
889** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the 885** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
890** year, a rule, and the offset from UTC at the time that rule takes effect, 886** year, a rule, and the offset from UT at the time that rule takes effect,
891** calculate the Epoch-relative time that rule takes effect. 887** calculate the Epoch-relative time that rule takes effect.
892*/ 888*/
893 889
894static time_t 890static time_t
895transtime(const time_t janfirst, const int year, const struct rule *const rulep, 891transtime(const time_t janfirst, const int year, const struct rule *const rulep,
896 const int_fast32_t offset) 892 const int_fast32_t offset)
897{ 893{
898 int leapyear; 894 int leapyear;
899 time_t value; 895 time_t value;
900 int i; 896 int i;
901 int d, m1, yy0, yy1, yy2, dow; 897 int d, m1, yy0, yy1, yy2, dow;
902 898
903 INITIALIZE(value); 899 INITIALIZE(value);
@@ -960,30 +956,30 @@ transtime(const time_t janfirst, const i @@ -960,30 +956,30 @@ transtime(const time_t janfirst, const i
960 mon_lengths[leapyear][rulep->r_mon - 1]) 956 mon_lengths[leapyear][rulep->r_mon - 1])
961 break; 957 break;
962 d += DAYSPERWEEK; 958 d += DAYSPERWEEK;
963 } 959 }
964 960
965 /* 961 /*
966 ** "d" is the day-of-month (zero-origin) of the day we want. 962 ** "d" is the day-of-month (zero-origin) of the day we want.
967 */ 963 */
968 value += (time_t)(d * SECSPERDAY); 964 value += (time_t)(d * SECSPERDAY);
969 break; 965 break;
970 } 966 }
971 967
972 /* 968 /*
973 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in 969 ** "value" is the Epoch-relative time of 00:00:00 UT on the day in
974 ** question. To get the Epoch-relative time of the specified local 970 ** question. To get the Epoch-relative time of the specified local
975 ** time on that day, add the transition time and the current offset 971 ** time on that day, add the transition time and the current offset
976 ** from UTC. 972 ** from UT.
977 */ 973 */
978 return (time_t)(value + rulep->r_time + offset); 974 return (time_t)(value + rulep->r_time + offset);
979} 975}
980 976
981/* 977/*
982** Given a POSIX section 8-style TZ string, fill in the rule tables as 978** Given a POSIX section 8-style TZ string, fill in the rule tables as
983** appropriate. 979** appropriate.
984*/ 980*/
985 981
986static int 982static int
987tzparse(timezone_t sp, const char *name, const int lastditch) 983tzparse(timezone_t sp, const char *name, const int lastditch)
988{ 984{
989 const char * stdname; 985 const char * stdname;
@@ -1040,28 +1036,29 @@ tzparse(timezone_t sp, const char *name, @@ -1040,28 +1036,29 @@ tzparse(timezone_t sp, const char *name,
1040 name = getzname(name); 1036 name = getzname(name);
1041 dstlen = name - dstname; /* length of DST zone name */ 1037 dstlen = name - dstname; /* length of DST zone name */
1042 } 1038 }
1043 if (*name != '\0' && *name != ',' && *name != ';') { 1039 if (*name != '\0' && *name != ',' && *name != ';') {
1044 name = getoffset(name, &dstoffset); 1040 name = getoffset(name, &dstoffset);
1045 if (name == NULL) 1041 if (name == NULL)
1046 return -1; 1042 return -1;
1047 } else dstoffset = stdoffset - SECSPERHOUR; 1043 } else dstoffset = stdoffset - SECSPERHOUR;
1048 if (*name == '\0' && load_result != 0) 1044 if (*name == '\0' && load_result != 0)
1049 name = TZDEFRULESTRING; 1045 name = TZDEFRULESTRING;
1050 if (*name == ',' || *name == ';') { 1046 if (*name == ',' || *name == ';') {
1051 struct rule start; 1047 struct rule start;
1052 struct rule end; 1048 struct rule end;
1053 int year; 1049 int year;
1054 time_t janfirst; 1050 int yearlim;
 1051 time_t janfirst;
1055 time_t starttime; 1052 time_t starttime;
1056 time_t endtime; 1053 time_t endtime;
1057 1054
1058 ++name; 1055 ++name;
1059 if ((name = getrule(name, &start)) == NULL) 1056 if ((name = getrule(name, &start)) == NULL)
1060 return -1; 1057 return -1;
1061 if (*name++ != ',') 1058 if (*name++ != ',')
1062 return -1; 1059 return -1;
1063 if ((name = getrule(name, &end)) == NULL) 1060 if ((name = getrule(name, &end)) == NULL)
1064 return -1; 1061 return -1;
1065 if (*name != '\0') 1062 if (*name != '\0')
1066 return -1; 1063 return -1;
1067 sp->typecnt = 2; /* standard time and DST */ 1064 sp->typecnt = 2; /* standard time and DST */
@@ -1069,54 +1066,64 @@ tzparse(timezone_t sp, const char *name, @@ -1069,54 +1066,64 @@ tzparse(timezone_t sp, const char *name,
1069 ** Two transitions per year, from EPOCH_YEAR forward. 1066 ** Two transitions per year, from EPOCH_YEAR forward.
1070 */ 1067 */
1071 memset(sp->ttis, 0, sizeof(sp->ttis)); 1068 memset(sp->ttis, 0, sizeof(sp->ttis));
1072 sp->ttis[0].tt_gmtoff = -dstoffset; 1069 sp->ttis[0].tt_gmtoff = -dstoffset;
1073 sp->ttis[0].tt_isdst = 1; 1070 sp->ttis[0].tt_isdst = 1;
1074 sp->ttis[0].tt_abbrind = (int)(stdlen + 1); 1071 sp->ttis[0].tt_abbrind = (int)(stdlen + 1);
1075 sp->ttis[1].tt_gmtoff = -stdoffset; 1072 sp->ttis[1].tt_gmtoff = -stdoffset;
1076 sp->ttis[1].tt_isdst = 0; 1073 sp->ttis[1].tt_isdst = 0;
1077 sp->ttis[1].tt_abbrind = 0; 1074 sp->ttis[1].tt_abbrind = 0;
1078 atp = sp->ats; 1075 atp = sp->ats;
1079 typep = sp->types; 1076 typep = sp->types;
1080 janfirst = 0; 1077 janfirst = 0;
1081 sp->timecnt = 0; 1078 sp->timecnt = 0;
1082 for (year = EPOCH_YEAR; 1079 yearlim = EPOCH_YEAR + YEARSPERREPEAT;
1083 sp->timecnt + 2 <= TZ_MAX_TIMES; 1080 for (year = EPOCH_YEAR; year < yearlim; year++) {
1084 ++year) { 1081 int_fast32_t yearsecs;
1085 time_t newfirst; 
1086 1082
1087 starttime = transtime(janfirst, year, &start, 1083 starttime = transtime(janfirst, year, &start,
1088 stdoffset); 1084 stdoffset);
1089 endtime = transtime(janfirst, year, &end, 1085 endtime = transtime(janfirst, year, &end,
1090 dstoffset); 1086 dstoffset);
1091 if (starttime > endtime) { 1087 yearsecs = (year_lengths[isleap(year)]
1092 *atp++ = endtime; 1088 * SECSPERDAY);
1093 *typep++ = 1; /* DST ends */ 1089 if (starttime > endtime
1094 *atp++ = starttime; 1090 || (starttime < endtime
1095 *typep++ = 0; /* DST begins */ 1091 && (endtime - starttime
1096 } else { 1092 < (yearsecs
1097 *atp++ = starttime; 1093 + (stdoffset - dstoffset))))) {
1098 *typep++ = 0; /* DST begins */ 1094 if (&sp->ats[TZ_MAX_TIMES - 2] < atp)
1099 *atp++ = endtime; 1095 break;
1100 *typep++ = 1; /* DST ends */ 1096 yearlim = year + YEARSPERREPEAT + 1;
 1097 if (starttime > endtime) {
 1098 *atp++ = endtime;
 1099 *typep++ = 1; /* DST ends */
 1100 *atp++ = starttime;
 1101 *typep++ = 0; /* DST begins */
 1102 } else {
 1103 *atp++ = starttime;
 1104 *typep++ = 0; /* DST begins */
 1105 *atp++ = endtime;
 1106 *typep++ = 1; /* DST ends */
 1107 }
1101 } 1108 }
1102 sp->timecnt += 2; 1109 if (time_t_max - janfirst < yearsecs)
1103 newfirst = janfirst; 
1104 newfirst += (time_t) 
1105 (year_lengths[isleap(year)] * SECSPERDAY); 
1106 if (newfirst <= janfirst) 
1107 break; 1110 break;
1108 janfirst = newfirst; 1111 janfirst += yearsecs;
1109 } 1112 }
 1113 _DIAGASSERT(__type_fit(int, atp - sp->ats));
 1114 sp->timecnt = (int)(atp - sp->ats);
 1115 if (!sp->timecnt)
 1116 sp->typecnt = 1; /* Perpetual DST. */
1110 } else { 1117 } else {
1111 int_fast32_t theirstdoffset; 1118 int_fast32_t theirstdoffset;
1112 int_fast32_t theirdstoffset; 1119 int_fast32_t theirdstoffset;
1113 int_fast32_t theiroffset; 1120 int_fast32_t theiroffset;
1114 int isdst; 1121 int isdst;
1115 int i; 1122 int i;
1116 int j; 1123 int j;
1117 1124
1118 if (*name != '\0') 1125 if (*name != '\0')
1119 return -1; 1126 return -1;
1120 /* 1127 /*
1121 ** Initial values of theirstdoffset and theirdstoffset. 1128 ** Initial values of theirstdoffset and theirdstoffset.
1122 */ 1129 */
@@ -1352,56 +1359,48 @@ tzset(void) @@ -1352,56 +1359,48 @@ tzset(void)
1352static struct tm * 1359static struct tm *
1353localsub(const timezone_t sp, const time_t * const timep, const int_fast32_t offset, 1360localsub(const timezone_t sp, const time_t * const timep, const int_fast32_t offset,
1354 struct tm *const tmp) 1361 struct tm *const tmp)
1355{ 1362{
1356 const struct ttinfo * ttisp; 1363 const struct ttinfo * ttisp;
1357 int i; 1364 int i;
1358 struct tm * result; 1365 struct tm * result;
1359 const time_t t = *timep; 1366 const time_t t = *timep;
1360 1367
1361 if ((sp->goback && t < sp->ats[0]) || 1368 if ((sp->goback && t < sp->ats[0]) ||
1362 (sp->goahead && t > sp->ats[sp->timecnt - 1])) { 1369 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1363 time_t newt = t; 1370 time_t newt = t;
1364 time_t seconds; 1371 time_t seconds;
1365 time_t tcycles; 1372 time_t years;
1366 int_fast64_t icycles; 
1367 1373
1368 if (t < sp->ats[0]) 1374 if (t < sp->ats[0])
1369 seconds = sp->ats[0] - t; 1375 seconds = sp->ats[0] - t;
1370 else seconds = t - sp->ats[sp->timecnt - 1]; 1376 else seconds = t - sp->ats[sp->timecnt - 1];
1371 --seconds; 1377 --seconds;
1372 tcycles = (time_t) 1378 years = (time_t)((seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT);
1373 (seconds / YEARSPERREPEAT / AVGSECSPERYEAR); 1379 seconds = (time_t)(years * AVGSECSPERYEAR);
1374 ++tcycles; 
1375 icycles = tcycles; 
1376 if (tcycles - icycles >= 1 || icycles - tcycles >= 1) 
1377 return NULL; 
1378 seconds = (time_t) icycles; 
1379 seconds *= YEARSPERREPEAT; 
1380 seconds *= AVGSECSPERYEAR; 
1381 if (t < sp->ats[0]) 1380 if (t < sp->ats[0])
1382 newt += seconds; 1381 newt += seconds;
1383 else newt -= seconds; 1382 else newt -= seconds;
1384 if (newt < sp->ats[0] || 1383 if (newt < sp->ats[0] ||
1385 newt > sp->ats[sp->timecnt - 1]) 1384 newt > sp->ats[sp->timecnt - 1])
1386 return NULL; /* "cannot happen" */ 1385 return NULL; /* "cannot happen" */
1387 result = localsub(sp, &newt, offset, tmp); 1386 result = localsub(sp, &newt, offset, tmp);
1388 if (result == tmp) { 1387 if (result == tmp) {
1389 time_t newy; 1388 time_t newy;
1390 1389
1391 newy = tmp->tm_year; 1390 newy = tmp->tm_year;
1392 if (t < sp->ats[0]) 1391 if (t < sp->ats[0])
1393 newy -= (time_t)icycles * YEARSPERREPEAT; 1392 newy -= years;
1394 else newy += (time_t)icycles * YEARSPERREPEAT; 1393 else newy += years;
1395 tmp->tm_year = (int)newy; 1394 tmp->tm_year = (int)newy;
1396 if (tmp->tm_year != newy) 1395 if (tmp->tm_year != newy)
1397 return NULL; 1396 return NULL;
1398 } 1397 }
1399 return result; 1398 return result;
1400 } 1399 }
1401 if (sp->timecnt == 0 || t < sp->ats[0]) { 1400 if (sp->timecnt == 0 || t < sp->ats[0]) {
1402 i = sp->defaulttype; 1401 i = sp->defaulttype;
1403 } else { 1402 } else {
1404 int lo = 1; 1403 int lo = 1;
1405 int hi = sp->timecnt; 1404 int hi = sp->timecnt;
1406 1405
1407 while (lo < hi) { 1406 while (lo < hi) {
@@ -1480,27 +1479,27 @@ gmtsub(const timezone_t sp, const time_t @@ -1480,27 +1479,27 @@ gmtsub(const timezone_t sp, const time_t
1480 int saveerrno; 1479 int saveerrno;
1481 gmt_is_set = TRUE; 1480 gmt_is_set = TRUE;
1482 saveerrno = errno; 1481 saveerrno = errno;
1483 gmtptr = calloc(1, sizeof *gmtptr); 1482 gmtptr = calloc(1, sizeof *gmtptr);
1484 errno = saveerrno; 1483 errno = saveerrno;
1485 if (gmtptr != NULL) 1484 if (gmtptr != NULL)
1486 gmtload(gmtptr); 1485 gmtload(gmtptr);
1487 } 1486 }
1488 mutex_unlock(&gmt_mutex); 1487 mutex_unlock(&gmt_mutex);
1489 result = timesub(gmtptr, timep, offset, tmp); 1488 result = timesub(gmtptr, timep, offset, tmp);
1490#ifdef TM_ZONE 1489#ifdef TM_ZONE
1491 /* 1490 /*
1492 ** Could get fancy here and deliver something such as 1491 ** Could get fancy here and deliver something such as
1493 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, 1492 ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
1494 ** but this is no time for a treasure hunt. 1493 ** but this is no time for a treasure hunt.
1495 */ 1494 */
1496 if (offset != 0) 1495 if (offset != 0)
1497 tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr); 1496 tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr);
1498 else { 1497 else {
1499 if (gmtptr == NULL) 1498 if (gmtptr == NULL)
1500 tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt); 1499 tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt);
1501 else tmp->TM_ZONE = gmtptr->chars; 1500 else tmp->TM_ZONE = gmtptr->chars;
1502 } 1501 }
1503#endif /* defined TM_ZONE */ 1502#endif /* defined TM_ZONE */
1504 return result; 1503 return result;
1505} 1504}
1506 1505
@@ -1617,45 +1616,45 @@ timesub(const timezone_t sp, const time_ @@ -1617,45 +1616,45 @@ timesub(const timezone_t sp, const time_
1617 break; 1616 break;
1618 } 1617 }
1619 } 1618 }
1620 y = EPOCH_YEAR; 1619 y = EPOCH_YEAR;
1621 tdays = (time_t)(*timep / SECSPERDAY); 1620 tdays = (time_t)(*timep / SECSPERDAY);
1622 rem = (int_fast64_t) (*timep - tdays * SECSPERDAY); 1621 rem = (int_fast64_t) (*timep - tdays * SECSPERDAY);
1623 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { 1622 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1624 int newy; 1623 int newy;
1625 time_t tdelta; 1624 time_t tdelta;
1626 int idelta; 1625 int idelta;
1627 int leapdays; 1626 int leapdays;
1628 1627
1629 tdelta = tdays / DAYSPERLYEAR; 1628 tdelta = tdays / DAYSPERLYEAR;
1630 idelta = (int) tdelta; 1629 if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
1631 if (tdelta - idelta >= 1 || idelta - tdelta >= 1) 1630 && tdelta <= INT_MAX))
1632 return NULL; 1631 return NULL;
 1632 idelta = tdelta;
1633 if (idelta == 0) 1633 if (idelta == 0)
1634 idelta = (tdays < 0) ? -1 : 1; 1634 idelta = (tdays < 0) ? -1 : 1;
1635 newy = y; 1635 newy = y;
1636 if (increment_overflow(&newy, idelta)) 1636 if (increment_overflow(&newy, idelta))
1637 return NULL; 1637 return NULL;
1638 leapdays = leaps_thru_end_of(newy - 1) - 1638 leapdays = leaps_thru_end_of(newy - 1) -
1639 leaps_thru_end_of(y - 1); 1639 leaps_thru_end_of(y - 1);
1640 tdays -= ((time_t) newy - y) * DAYSPERNYEAR; 1640 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1641 tdays -= leapdays; 1641 tdays -= leapdays;
1642 y = newy; 1642 y = newy;
1643 } 1643 }
1644 { 1644 {
1645 int_fast32_t seconds; 1645 int_fast32_t seconds;
1646 const time_t half_second = (time_t)0.5; 
1647 1646
1648 seconds = (int_fast32_t)(tdays * SECSPERDAY + half_second); 1647 seconds = (int_fast32_t)(tdays * SECSPERDAY);
1649 tdays = (time_t)(seconds / SECSPERDAY); 1648 tdays = (time_t)(seconds / SECSPERDAY);
1650 rem += (int_fast64_t)(seconds - tdays * SECSPERDAY); 1649 rem += (int_fast64_t)(seconds - tdays * SECSPERDAY);
1651 } 1650 }
1652 /* 1651 /*
1653 ** Given the range, we can now fearlessly cast... 1652 ** Given the range, we can now fearlessly cast...
1654 */ 1653 */
1655 idays = (int) tdays; 1654 idays = (int) tdays;
1656 rem += offset - corr; 1655 rem += offset - corr;
1657 while (rem < 0) { 1656 while (rem < 0) {
1658 rem += SECSPERDAY; 1657 rem += SECSPERDAY;
1659 --idays; 1658 --idays;
1660 } 1659 }
1661 while (rem >= SECSPERDAY) { 1660 while (rem >= SECSPERDAY) {
@@ -1809,28 +1808,29 @@ normalize_overflow32(int_fast32_t *const @@ -1809,28 +1808,29 @@ normalize_overflow32(int_fast32_t *const
1809 1808
1810 tensdelta = (*unitsptr >= 0) ? 1809 tensdelta = (*unitsptr >= 0) ?
1811 (*unitsptr / base) : 1810 (*unitsptr / base) :
1812 (-1 - (-1 - *unitsptr) / base); 1811 (-1 - (-1 - *unitsptr) / base);
1813 *unitsptr -= tensdelta * base; 1812 *unitsptr -= tensdelta * base;
1814 return increment_overflow32(tensptr, tensdelta); 1813 return increment_overflow32(tensptr, tensdelta);
1815} 1814}
1816 1815
1817static int 1816static int
1818tmcomp(const struct tm *const atmp, const struct tm *const btmp) 1817tmcomp(const struct tm *const atmp, const struct tm *const btmp)
1819{ 1818{
1820 int result; 1819 int result;
1821 1820
1822 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1821 if (atmp->tm_year != btmp->tm_year)
1823 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1822 return atmp->tm_year < btmp->tm_year ? -1 : 1;
 1823 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1824 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1824 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1825 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1825 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1826 (result = (atmp->tm_min - btmp->tm_min)) == 0) 1826 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1827 result = atmp->tm_sec - btmp->tm_sec; 1827 result = atmp->tm_sec - btmp->tm_sec;
1828 return result; 1828 return result;
1829} 1829}
1830 1830
1831static time_t 1831static time_t
1832time2sub(const timezone_t sp, struct tm *const tmp, subfun_t funcp, 1832time2sub(const timezone_t sp, struct tm *const tmp, subfun_t funcp,
1833 const int_fast32_t offset, int *const okayp, const int do_norm_secs) 1833 const int_fast32_t offset, int *const okayp, const int do_norm_secs)
1834{ 1834{
1835 int dir; 1835 int dir;
1836 int i, j; 1836 int i, j;
@@ -1913,68 +1913,59 @@ again: @@ -1913,68 +1913,59 @@ again:
1913 saved_seconds = yourtm.tm_sec; 1913 saved_seconds = yourtm.tm_sec;
1914 yourtm.tm_sec = SECSPERMIN - 1; 1914 yourtm.tm_sec = SECSPERMIN - 1;
1915 } else { 1915 } else {
1916 saved_seconds = yourtm.tm_sec; 1916 saved_seconds = yourtm.tm_sec;
1917 yourtm.tm_sec = 0; 1917 yourtm.tm_sec = 0;
1918 } 1918 }
1919 /* 1919 /*
1920 ** Do a binary search (this works whatever time_t's type is). 1920 ** Do a binary search (this works whatever time_t's type is).
1921 */ 1921 */
1922 /* LINTED const not */ 1922 /* LINTED const not */
1923 if (!TYPE_SIGNED(time_t)) { 1923 if (!TYPE_SIGNED(time_t)) {
1924 lo = 0; 1924 lo = 0;
1925 hi = lo - 1; 1925 hi = lo - 1;
1926 /* LINTED const not */ 
1927 } else if (!TYPE_INTEGRAL(time_t)) { 
1928 /* CONSTCOND */ 
1929 if (sizeof(time_t) > sizeof(float)) 
1930 /* LINTED assumed double */ 
1931 hi = (time_t) DBL_MAX; 
1932 /* LINTED assumed float */ 
1933 else hi = (time_t) FLT_MAX; 
1934 lo = -hi; 
1935 } else { 1926 } else {
1936 lo = 1; 1927 lo = 1;
1937 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) 1928 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1938 lo *= 2; 1929 lo *= 2;
1939 hi = -(lo + 1); 1930 hi = -(lo + 1);
1940 } 1931 }
1941#ifdef NO_ERROR_IN_DST_GAP 1932#ifdef NO_ERROR_IN_DST_GAP
1942 ilo = lo; 1933 ilo = lo;
1943#endif 1934#endif
1944 for ( ; ; ) { 1935 for ( ; ; ) {
1945 t = lo / 2 + hi / 2; 1936 t = lo / 2 + hi / 2;
1946 if (t < lo) 1937 if (t < lo)
1947 t = lo; 1938 t = lo;
1948 else if (t > hi) 1939 else if (t > hi)
1949 t = hi; 1940 t = hi;
1950 if ((*funcp)(sp, &t, offset, &mytm) == NULL) { 1941 if ((*funcp)(sp, &t, offset, &mytm) == NULL) {
1951 /* 1942 /*
1952 ** Assume that t is too extreme to be represented in 1943 ** Assume that t is too extreme to be represented in
1953 ** a struct tm; arrange things so that it is less 1944 ** a struct tm; arrange things so that it is less
1954 ** extreme on the next pass. 1945 ** extreme on the next pass.
1955 */ 1946 */
1956 dir = (t > 0) ? 1 : -1; 1947 dir = (t > 0) ? 1 : -1;
1957 } else dir = tmcomp(&mytm, &yourtm); 1948 } else dir = tmcomp(&mytm, &yourtm);
1958 if (dir != 0) { 1949 if (dir != 0) {
1959 if (t == lo) { 1950 if (t == lo) {
1960 ++t; 1951 if (t == time_t_max)
1961 if (t <= lo) 
1962 goto overflow; 1952 goto overflow;
 1953 ++t;
1963 ++lo; 1954 ++lo;
1964 } else if (t == hi) { 1955 } else if (t == hi) {
1965 --t; 1956 if (t == time_t_min)
1966 if (t >= hi) 
1967 goto overflow; 1957 goto overflow;
 1958 --t;
1968 --hi; 1959 --hi;
1969 } 1960 }
1970#ifdef NO_ERROR_IN_DST_GAP 1961#ifdef NO_ERROR_IN_DST_GAP
1971 if (ilo != lo && lo - 1 == hi && yourtm.tm_isdst < 0 && 1962 if (ilo != lo && lo - 1 == hi && yourtm.tm_isdst < 0 &&
1972 do_norm_secs) { 1963 do_norm_secs) {
1973 for (i = sp->typecnt - 1; i >= 0; --i) { 1964 for (i = sp->typecnt - 1; i >= 0; --i) {
1974 for (j = sp->typecnt - 1; j >= 0; --j) { 1965 for (j = sp->typecnt - 1; j >= 0; --j) {
1975 time_t off; 1966 time_t off;
1976 if (sp->ttis[j].tt_isdst == 1967 if (sp->ttis[j].tt_isdst ==
1977 sp->ttis[i].tt_isdst) 1968 sp->ttis[i].tt_isdst)
1978 continue; 1969 continue;
1979 off = sp->ttis[j].tt_gmtoff - 1970 off = sp->ttis[j].tt_gmtoff -
1980 sp->ttis[i].tt_gmtoff; 1971 sp->ttis[i].tt_gmtoff;
@@ -2198,27 +2189,27 @@ timeoff(struct tm *const tmp, long offse @@ -2198,27 +2189,27 @@ timeoff(struct tm *const tmp, long offse
2198 t = time1(gmtptr, tmp, gmtsub, (int_fast32_t)offset); 2189 t = time1(gmtptr, tmp, gmtsub, (int_fast32_t)offset);
2199 return t; 2190 return t;
2200} 2191}
2201 2192
2202#endif /* defined STD_INSPIRED */ 2193#endif /* defined STD_INSPIRED */
2203 2194
2204#ifdef CMUCS 2195#ifdef CMUCS
2205 2196
2206/* 2197/*
2207** The following is supplied for compatibility with 2198** The following is supplied for compatibility with
2208** previous versions of the CMUCS runtime library. 2199** previous versions of the CMUCS runtime library.
2209*/ 2200*/
2210 2201
2211int_fast32_t 2202long
2212gtime(struct tm *const tmp) 2203gtime(struct tm *const tmp)
2213{ 2204{
2214 const time_t t = mktime(tmp); 2205 const time_t t = mktime(tmp);
2215 2206
2216 if (t == WRONG) 2207 if (t == WRONG)
2217 return -1; 2208 return -1;
2218 return t; 2209 return t;
2219} 2210}
2220 2211
2221#endif /* defined CMUCS */ 2212#endif /* defined CMUCS */
2222 2213
2223/* 2214/*
2224** XXX--is the below the right way to conditionalize?? 2215** XXX--is the below the right way to conditionalize??

cvs diff -r1.29 -r1.30 src/lib/libc/time/private.h (expand / switch to unified diff)

--- src/lib/libc/time/private.h 2013/07/17 20:13:04 1.29
+++ src/lib/libc/time/private.h 2013/09/20 19:06:54 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: private.h,v 1.29 2013/07/17 20:13:04 christos Exp $ */ 1/* $NetBSD: private.h,v 1.30 2013/09/20 19:06:54 christos Exp $ */
2 2
3#ifndef PRIVATE_H 3#ifndef PRIVATE_H
4#define PRIVATE_H 4#define PRIVATE_H
5 5
6/* NetBSD defaults */ 6/* NetBSD defaults */
7#define TM_GMTOFF tm_gmtoff 7#define TM_GMTOFF tm_gmtoff
8#define TM_ZONE tm_zone 8#define TM_ZONE tm_zone
9#define STD_INSPIRED 1 9#define STD_INSPIRED 1
10#define HAVE_LONG_DOUBLE 1 10#define HAVE_LONG_DOUBLE 1
11 11
12/* For when we build zic as a host tool. */ 12/* For when we build zic as a host tool. */
13#if HAVE_NBTOOL_CONFIG_H 13#if HAVE_NBTOOL_CONFIG_H
14#include "nbtool_config.h" 14#include "nbtool_config.h"
@@ -168,56 +168,69 @@ typedef long int_fast64_t; @@ -168,56 +168,69 @@ typedef long int_fast64_t;
168#endif /* !defined INT_FAST64_MAX */ 168#endif /* !defined INT_FAST64_MAX */
169 169
170#ifndef INT_FAST32_MAX 170#ifndef INT_FAST32_MAX
171# if INT_MAX >> 31 == 0 171# if INT_MAX >> 31 == 0
172typedef long int_fast32_t; 172typedef long int_fast32_t;
173# else 173# else
174typedef int int_fast32_t; 174typedef int int_fast32_t;
175# endif 175# endif
176#endif 176#endif
177 177
178#ifndef INTMAX_MAX 178#ifndef INTMAX_MAX
179# if defined LLONG_MAX || defined __LONG_LONG_MAX__ 179# if defined LLONG_MAX || defined __LONG_LONG_MAX__
180typedef long long intmax_t; 180typedef long long intmax_t;
 181# define strtoimax strtoll
181# define PRIdMAX "lld" 182# define PRIdMAX "lld"
 183# ifdef LLONG_MAX
 184# define INTMAX_MAX LLONG_MAX
 185# define INTMAX_MIN LLONG_MIN
 186# else
 187# define INTMAX_MAX __LONG_LONG_MAX__
 188# define INTMAX_MIN __LONG_LONG_MIN__
 189# endif
182# else 190# else
183typedef long intmax_t; 191typedef long intmax_t;
 192# define strtoimax strtol
184# define PRIdMAX "ld" 193# define PRIdMAX "ld"
 194# define INTMAX_MAX LONG_MAX
 195# define INTMAX_MIN LONG_MIN
185# endif 196# endif
186#endif 197#endif
187 198
188#ifndef UINTMAX_MAX 199#ifndef UINTMAX_MAX
189# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ 200# if defined ULLONG_MAX || defined __LONG_LONG_MAX__
190typedef unsigned long long uintmax_t; 201typedef unsigned long long uintmax_t;
191# define PRIuMAX "llu" 202# define PRIuMAX "llu"
192# else 203# else
193typedef unsigned long uintmax_t; 204typedef unsigned long uintmax_t;
194# define PRIuMAX "lu" 205# define PRIuMAX "lu"
195# endif 206# endif
196#endif 207#endif
197 208
198#ifndef INT32_MAX 209#ifndef INT32_MAX
199#define INT32_MAX 0x7fffffff 210#define INT32_MAX 0x7fffffff
200#endif /* !defined INT32_MAX */ 211#endif /* !defined INT32_MAX */
201#ifndef INT32_MIN 212#ifndef INT32_MIN
202#define INT32_MIN (-1 - INT32_MAX) 213#define INT32_MIN (-1 - INT32_MAX)
203#endif /* !defined INT32_MIN */ 214#endif /* !defined INT32_MIN */
204 215
205#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) 216#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
206# define ATTRIBUTE_CONST __attribute__ ((__const__)) 217# define ATTRIBUTE_CONST __attribute__ ((__const__))
207# define ATTRIBUTE_PURE __attribute__ ((__pure__)) 218# define ATTRIBUTE_PURE __attribute__ ((__pure__))
 219# define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
208#else 220#else
209# define ATTRIBUTE_CONST /* empty */ 221# define ATTRIBUTE_CONST /* empty */
210# define ATTRIBUTE_PURE /* empty */ 222# define ATTRIBUTE_PURE /* empty */
 223# define ATTRIBUTE_FORMAT(spec) /* empty */
211#endif 224#endif
212 225
213#if !defined _Noreturn && __STDC_VERSION__ < 201112 226#if !defined _Noreturn && __STDC_VERSION__ < 201112
214# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) 227# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__)
215# define _Noreturn __attribute__ ((__noreturn__)) 228# define _Noreturn __attribute__ ((__noreturn__))
216# else 229# else
217# define _Noreturn 230# define _Noreturn
218# endif 231# endif
219#endif 232#endif
220 233
221#if __STDC_VERSION__ < 199901 && !defined restrict 234#if __STDC_VERSION__ < 199901 && !defined restrict
222# define restrict /* empty */ 235# define restrict /* empty */
223#endif 236#endif
@@ -306,34 +319,36 @@ const char * scheck(const char * string, @@ -306,34 +319,36 @@ const char * scheck(const char * string,
306 319
307#ifndef FALSE 320#ifndef FALSE
308#define FALSE 0 321#define FALSE 0
309#endif /* !defined FALSE */ 322#endif /* !defined FALSE */
310 323
311#ifndef TYPE_BIT 324#ifndef TYPE_BIT
312#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) 325#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
313#endif /* !defined TYPE_BIT */ 326#endif /* !defined TYPE_BIT */
314 327
315#ifndef TYPE_SIGNED 328#ifndef TYPE_SIGNED
316#define TYPE_SIGNED(type) (/*CONSTCOND*/((type) -1) < 0) 329#define TYPE_SIGNED(type) (/*CONSTCOND*/((type) -1) < 0)
317#endif /* !defined TYPE_SIGNED */ 330#endif /* !defined TYPE_SIGNED */
318 331
319/* 332/* The minimum and maximum finite time values. */
320** Since the definition of TYPE_INTEGRAL contains floating point numbers, 333static time_t const time_t_min =
321** it cannot be used in preprocessor directives. 334 (TYPE_SIGNED(time_t)
322*/ 335 ? (time_t) -1 << (int)(CHAR_BIT * sizeof (time_t) - 1)
323 336/*###336 [lint] warning semantics of 'p << p' change in ANSI C; use explicit cast [118]%%%*/
324#ifndef TYPE_INTEGRAL 337 : 0);
325#define TYPE_INTEGRAL(type) (/*CONSTCOND*/((type) 0.5) != 0.5) 338static time_t const time_t_max =
326#endif /* !defined TYPE_INTEGRAL */ 339 (TYPE_SIGNED(time_t)
 340 ? - (~ 0 < 0) - ((time_t) -1 << (int)(CHAR_BIT * sizeof (time_t) - 1))
 341 : -1);
327 342
328#ifndef INT_STRLEN_MAXIMUM 343#ifndef INT_STRLEN_MAXIMUM
329/* 344/*
330** 302 / 1000 is log10(2.0) rounded up. 345** 302 / 1000 is log10(2.0) rounded up.
331** Subtract one for the sign bit if the type is signed; 346** Subtract one for the sign bit if the type is signed;
332** add one for integer division truncation; 347** add one for integer division truncation;
333** add one more for a minus sign if the type is signed. 348** add one more for a minus sign if the type is signed.
334*/ 349*/
335#define INT_STRLEN_MAXIMUM(type) \ 350#define INT_STRLEN_MAXIMUM(type) \
336 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ 351 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
337 1 + TYPE_SIGNED(type)) 352 1 + TYPE_SIGNED(type))
338#endif /* !defined INT_STRLEN_MAXIMUM */ 353#endif /* !defined INT_STRLEN_MAXIMUM */
339 354

cvs diff -r1.29 -r1.30 src/lib/libc/time/strftime.3 (expand / switch to unified diff)

--- src/lib/libc/time/strftime.3 2012/04/06 11:35:39 1.29
+++ src/lib/libc/time/strftime.3 2013/09/20 19:06:54 1.30
@@ -20,27 +20,27 @@ @@ -20,27 +20,27 @@
20.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30.\" SUCH DAMAGE. 30.\" SUCH DAMAGE.
31.\" 31.\"
32.\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91 32.\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91
33.\" $NetBSD: strftime.3,v 1.29 2012/04/06 11:35:39 wiz Exp $ 33.\" $NetBSD: strftime.3,v 1.30 2013/09/20 19:06:54 christos Exp $
34.\" 34.\"
35.Dd April 14, 2011 35.Dd April 14, 2011
36.Dt STRFTIME 3 36.Dt STRFTIME 3
37.Os 37.Os
38.Sh NAME 38.Sh NAME
39.Nm strftime , 39.Nm strftime ,
40.Nm strftime_z 40.Nm strftime_z
41.Nd format date and time 41.Nd format date and time
42.Sh LIBRARY 42.Sh LIBRARY
43.Lb libc 43.Lb libc
44.Sh SYNOPSIS 44.Sh SYNOPSIS
45.In time.h 45.In time.h
46.Ft size_t 46.Ft size_t
@@ -139,28 +139,28 @@ or @@ -139,28 +139,28 @@ or
139.Dq Tn PM . 139.Dq Tn PM .
140.It Cm \&%R 140.It Cm \&%R
141is replaced by the time in the format 141is replaced by the time in the format
142.Dq Li %H:%M . 142.Dq Li %H:%M .
143.It Cm \&%r 143.It Cm \&%r
144is replaced by the locale's representation of 12-hour clock time 144is replaced by the locale's representation of 12-hour clock time
145using AM/PM notation. 145using AM/PM notation.
146.It Cm \&%S 146.It Cm \&%S
147is replaced by the second as a decimal number [00,61]. 147is replaced by the second as a decimal number [00,61].
148The range of 148The range of
149seconds is (00-61) instead of (00-59) to allow for the periodic occurrence 149seconds is (00-61) instead of (00-59) to allow for the periodic occurrence
150of leap seconds and double leap seconds. 150of leap seconds and double leap seconds.
151.It Cm %s 151.It Cm %s
152is replaced by the number of seconds since the Epoch, UTC (see 152is replaced by the number of seconds since the Epoch (see
153.Xr mktime 3 ) . 153.Xr ctime 3 ) .
154.It Cm \&%T 154.It Cm \&%T
155is replaced by the time in the format 155is replaced by the time in the format
156.Dq Li %H:%M:%S . 156.Dq Li %H:%M:%S .
157.It Cm \&%t 157.It Cm \&%t
158is replaced by a tab. 158is replaced by a tab.
159.It Cm \&%U 159.It Cm \&%U
160is replaced by the week number of the year (Sunday as the first day of 160is replaced by the week number of the year (Sunday as the first day of
161the week) as a decimal number [00,53]. 161the week) as a decimal number [00,53].
162.It Cm \&%u 162.It Cm \&%u
163is replaced by the weekday (Monday as the first day of the week) 163is replaced by the weekday (Monday as the first day of the week)
164as a decimal number [1,7]. 164as a decimal number [1,7].
165.It Cm \&%V 165.It Cm \&%V
166is replaced by the week number of the year (Monday as the first day of 166is replaced by the week number of the year (Monday as the first day of
@@ -180,27 +180,30 @@ the week) as a decimal number [00,53]. @@ -180,27 +180,30 @@ the week) as a decimal number [00,53].
180is replaced by the weekday (Sunday as the first day of the week) 180is replaced by the weekday (Sunday as the first day of the week)
181as a decimal number [0,6]. 181as a decimal number [0,6].
182.It Cm \&%X 182.It Cm \&%X
183is replaced by the locale's appropriate time representation. 183is replaced by the locale's appropriate time representation.
184.It Cm \&%x 184.It Cm \&%x
185is replaced by the locale's appropriate date representation. 185is replaced by the locale's appropriate date representation.
186.It Cm \&%Y 186.It Cm \&%Y
187is replaced by the year with century as a decimal number. 187is replaced by the year with century as a decimal number.
188.It Cm \&%y 188.It Cm \&%y
189is replaced by the year without century as a decimal number [00,99]. 189is replaced by the year without century as a decimal number [00,99].
190.It Cm \&%Z 190.It Cm \&%Z
191is replaced by the time zone name. 191is replaced by the time zone name.
192.It Cm \&%z 192.It Cm \&%z
193is replaced by the offset from UTC in the ISO 8601 format 193is replaced by the offset from the Prime Meridian in the format
 194+HHMM or -HHMM (ISO 8601) as appropriate, with positive values representing
 195locations east of Greenwich, or by the empty string if this is
 196not determinable.
194.Dq Li [-]hhmm . 197.Dq Li [-]hhmm .
195.It Cm %% 198.It Cm %%
196is replaced by 199is replaced by
197.Ql % . 200.Ql % .
198.El 201.El
199.Pp 202.Pp
200The 203The
201.Fn strftime_z 204.Fn strftime_z
202function is similar to 205function is similar to
203.Fn strftime , 206.Fn strftime ,
204but it also takes a 207but it also takes a
205.Ft "const timezone_t" 208.Ft "const timezone_t"
206.Fa tz 209.Fa tz

cvs diff -r1.28 -r1.29 src/lib/libc/time/strftime.c (expand / switch to unified diff)

--- src/lib/libc/time/strftime.c 2013/07/17 23:09:26 1.28
+++ src/lib/libc/time/strftime.c 2013/09/20 19:06:54 1.29
@@ -1,22 +1,22 @@ @@ -1,22 +1,22 @@
1/* $NetBSD: strftime.c,v 1.28 2013/07/17 23:09:26 christos Exp $ */ 1/* $NetBSD: strftime.c,v 1.29 2013/09/20 19:06:54 christos Exp $ */
2 2
3#include <sys/cdefs.h> 3#include <sys/cdefs.h>
4#if defined(LIBC_SCCS) && !defined(lint) 4#if defined(LIBC_SCCS) && !defined(lint)
5#if 0 5#if 0
6static char elsieid[] = "@(#)strftime.c 7.64"; 6static char elsieid[] = "@(#)strftime.c 7.64";
7static char elsieid[] = "@(#)strftime.c 8.3"; 7static char elsieid[] = "@(#)strftime.c 8.3";
8#else 8#else
9__RCSID("$NetBSD: strftime.c,v 1.28 2013/07/17 23:09:26 christos Exp $"); 9__RCSID("$NetBSD: strftime.c,v 1.29 2013/09/20 19:06:54 christos Exp $");
10#endif 10#endif
11#endif /* LIBC_SCCS and not lint */ 11#endif /* LIBC_SCCS and not lint */
12 12
13#include "namespace.h" 13#include "namespace.h"
14 14
15#include <stddef.h> 15#include <stddef.h>
16#include <locale.h> 16#include <locale.h>
17#include "setlocale_local.h" 17#include "setlocale_local.h"
18 18
19/* 19/*
20** Based on the UCB version with the copyright notice and sccsid 20** Based on the UCB version with the copyright notice and sccsid
21** appearing below. 21** appearing below.
22** 22**
@@ -494,27 +494,27 @@ label: @@ -494,27 +494,27 @@ label:
494 */ 494 */
495 continue; 495 continue;
496 case 'z': 496 case 'z':
497 { 497 {
498 int diff; 498 int diff;
499 char const * sign; 499 char const * sign;
500 500
501 if (t->tm_isdst < 0) 501 if (t->tm_isdst < 0)
502 continue; 502 continue;
503#ifdef TM_GMTOFF 503#ifdef TM_GMTOFF
504 diff = (int)t->TM_GMTOFF; 504 diff = (int)t->TM_GMTOFF;
505#else /* !defined TM_GMTOFF */ 505#else /* !defined TM_GMTOFF */
506 /* 506 /*
507 ** C99 says that the UTC offset must 507 ** C99 says that the UT offset must
508 ** be computed by looking only at 508 ** be computed by looking only at
509 ** tm_isdst. This requirement is 509 ** tm_isdst. This requirement is
510 ** incorrect, since it means the code 510 ** incorrect, since it means the code
511 ** must rely on magic (in this case 511 ** must rely on magic (in this case
512 ** altzone and timezone), and the 512 ** altzone and timezone), and the
513 ** magic might not have the correct 513 ** magic might not have the correct
514 ** offset. Doing things correctly is 514 ** offset. Doing things correctly is
515 ** tricky and requires disobeying C99; 515 ** tricky and requires disobeying C99;
516 ** see GNU C strftime for details. 516 ** see GNU C strftime for details.
517 ** For now, punt and conform to the 517 ** For now, punt and conform to the
518 ** standard, even though it's incorrect. 518 ** standard, even though it's incorrect.
519 ** 519 **
520 ** C99 says that %z must be replaced by the 520 ** C99 says that %z must be replaced by the

cvs diff -r1.11 -r1.12 src/lib/libc/time/Attic/tz-link.htm (expand / switch to unified diff)

--- src/lib/libc/time/Attic/tz-link.htm 2013/07/17 20:13:04 1.11
+++ src/lib/libc/time/Attic/tz-link.htm 2013/09/20 19:06:54 1.12
@@ -1,24 +1,24 @@ @@ -1,24 +1,24 @@
1<!DOCTYPE html 1<!DOCTYPE html
2 PUBLIC "-//W3C//DTD HTML 4.01//EN" 2 PUBLIC "-//W3C//DTD HTML 4.01//EN"
3 "http://www.w3.org/TR/html4/strict.dtd"> 3 "http://www.w3.org/TR/html4/strict.dtd">
4<html> 4<html>
5<head> 5<head>
6<title>Sources for Time Zone and Daylight Saving Time Data</title> 6<title>Sources for Time Zone and Daylight Saving Time Data</title>
7<link rel="schema.DC" href="http://purl.org/DC/elements/1.1/"> 7<link rel="schema.DC" href="http://purl.org/DC/elements/1.1/">
8<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"'> 8<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"'>
9<meta name="DC.Creator" content="Eggert, Paul"> 9<meta name="DC.Creator" content="Eggert, Paul">
10<meta name="DC.Contributor" content="Olson, Arthur David"> 10<meta name="DC.Contributor" content="Olson, Arthur David">
11<meta name="DC.Date" content="2013-07-03"> 11<meta name="DC.Date" content="2013-09-05">
12<meta name="DC.Description" 12<meta name="DC.Description"
13 content="Sources of information about time zones and daylight saving time"> 13 content="Sources of information about time zones and daylight saving time">
14<meta name="DC.Identifier" 14<meta name="DC.Identifier"
15 content="http://www.iana.org/time-zones/repository/tz-link.htm"> 15 content="http://www.iana.org/time-zones/repository/tz-link.htm">
16<meta name="Keywords" 16<meta name="Keywords"
17 content="database,daylight saving,DST,time zone,timezone,tz,zoneinfo"> 17 content="database,daylight saving,DST,time zone,timezone,tz,zoneinfo">
18</head> 18</head>
19<body> 19<body>
20<h1>Sources for Time Zone and Daylight Saving Time Data</h1> 20<h1>Sources for Time Zone and Daylight Saving Time Data</h1>
21<h2>The <code>tz</code> database</h2> 21<h2>The <code>tz</code> database</h2>
22<p> 22<p>
23The <a href="http://en.wikipedia.org/wiki/Public_domain">public-domain</a> 23The <a href="http://en.wikipedia.org/wiki/Public_domain">public-domain</a>
24time zone database contains code and data 24time zone database contains code and data
@@ -384,32 +384,35 @@ of the University of Texas at Austin has @@ -384,32 +384,35 @@ of the University of Texas at Austin has
384recent editions. 384recent editions.
385The pictorial quality is good, 385The pictorial quality is good,
386but the maps do not indicate summer time, 386but the maps do not indicate summer time,
387and parts of the data are a few years out of date.</li> 387and parts of the data are a few years out of date.</li>
388<li><a href="http://worldtimezone.com/">Current time around the world 388<li><a href="http://worldtimezone.com/">Current time around the world
389and standard time zones map of the world</a> 389and standard time zones map of the world</a>
390has several fancy time zone maps; it covers Russia particularly well. 390has several fancy time zone maps; it covers Russia particularly well.
391The maps' pictorial quality is not quite as good as the 391The maps' pictorial quality is not quite as good as the
392<abbr>CIA</abbr>'s 392<abbr>CIA</abbr>'s
393but the maps are more up to date.</li> 393but the maps are more up to date.</li>
394</ul> 394</ul>
395<h2>Time zone boundaries</h2> 395<h2>Time zone boundaries</h2>
396<ul> 396<ul>
397<li><a href="http://efele.net/maps/tz/">TZ timezone maps</a> contains a <a 397<li><a href="http://efele.net/maps/tz/">TZ timezones maps</a> contains <a
398href="http://en.wikipedia.org/wiki/Shapefile">shapefile</a> of the 398href="http://en.wikipedia.org/wiki/Shapefile">shapefiles</a> of
399<code>tz</code> regions in the world.</li> 399sets of <code>tz</code> regions.</li>
400<li><a href="http://statoids.com/statoids.html">Administrative Divisions 400<li><a href="http://derickrethans.nl/what-time-is-it.html">What Time
401of Countries ("Statoids")</a> contains detailed lists of 401is It Here?</a> applies <a href="http://www.mongodb.org/">MongoDB</a>
402<code>tz</code>-related zone subdivision data.</li> 402geospatial query operators to shapefiles' data.</li>
 403<li><a href="http://statoids.com/statoids.html">Administrative
 404Divisions of Countries ("Statoids")</a> contains lists of
 405political subdivision data related to time zones.</li>
403<li><a href="http://home.tiscali.nl/~t876506/Multizones.html">Time 406<li><a href="http://home.tiscali.nl/~t876506/Multizones.html">Time
404zone boundaries for multizone countries</a> summarizes legal 407zone boundaries for multizone countries</a> summarizes legal
405boundaries between time zones within countries.</li> 408boundaries between time zones within countries.</li>
406<li>Manifold.net's <a 409<li>Manifold.net's <a
407href="http://manifold.net/info/freestuff.shtml">Free Stuff for 410href="http://manifold.net/info/freestuff.shtml">Free Stuff for
408Manifold System Users</a> includes a Manifold-format map of 411Manifold System Users</a> includes a Manifold-format map of
409world time zone boundaries distributed under the 412world time zone boundaries distributed under the
410<abbr>GPL</abbr>.</li> 413<abbr>GPL</abbr>.</li>
411<li>The <abbr>US</abbr> Geological Survey's National Atlas of 414<li>The <abbr>US</abbr> Geological Survey's National Atlas of
412the United States 415the United States
413publishes the <a href="http://nationalatlas.gov/mld/timeznp.html">Time 416publishes the <a href="http://nationalatlas.gov/mld/timeznp.html">Time
414Zones of the United States</a> in the public domain.</li> 417Zones of the United States</a> in the public domain.</li>
415<li>The GeoCommunity lists several commercial sources for <a 418<li>The GeoCommunity lists several commercial sources for <a

cvs diff -r1.11 -r1.12 src/lib/libc/time/Attic/tzfile.h (expand / switch to unified diff)

--- src/lib/libc/time/Attic/tzfile.h 2013/07/17 20:13:04 1.11
+++ src/lib/libc/time/Attic/tzfile.h 2013/09/20 19:06:54 1.12
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: tzfile.h,v 1.11 2013/07/17 20:13:04 christos Exp $ */ 1/* $NetBSD: tzfile.h,v 1.12 2013/09/20 19:06:54 christos Exp $ */
2 2
3#ifndef TZFILE_H 3#ifndef TZFILE_H
4#define TZFILE_H 4#define TZFILE_H
5 5
6/* 6/*
7** This file is in the public domain, so clarified as of 7** This file is in the public domain, so clarified as of
8** 1996-06-05 by Arthur David Olson. 8** 1996-06-05 by Arthur David Olson.
9*/ 9*/
10 10
11/* 11/*
12** This header is for use ONLY with the time conversion code. 12** This header is for use ONLY with the time conversion code.
13** There is no guarantee that it will remain unchanged, 13** There is no guarantee that it will remain unchanged,
14** or that it will remain at all. 14** or that it will remain at all.
@@ -30,69 +30,76 @@ @@ -30,69 +30,76 @@
30 30
31#ifndef TZDEFRULES 31#ifndef TZDEFRULES
32#define TZDEFRULES "posixrules" 32#define TZDEFRULES "posixrules"
33#endif /* !defined TZDEFRULES */ 33#endif /* !defined TZDEFRULES */
34 34
35/* 35/*
36** Each file begins with. . . 36** Each file begins with. . .
37*/ 37*/
38 38
39#define TZ_MAGIC "TZif" 39#define TZ_MAGIC "TZif"
40 40
41struct tzhead { 41struct tzhead {
42 char tzh_magic[4]; /* TZ_MAGIC */ 42 char tzh_magic[4]; /* TZ_MAGIC */
43 char tzh_version[1]; /* '\0' or '2' as of 2005 */ 43 char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
44 char tzh_reserved[15]; /* reserved--must be zero */ 44 char tzh_reserved[15]; /* reserved--must be zero */
45 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ 45 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
46 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ 46 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
47 char tzh_leapcnt[4]; /* coded number of leap seconds */ 47 char tzh_leapcnt[4]; /* coded number of leap seconds */
48 char tzh_timecnt[4]; /* coded number of transition times */ 48 char tzh_timecnt[4]; /* coded number of transition times */
49 char tzh_typecnt[4]; /* coded number of local time types */ 49 char tzh_typecnt[4]; /* coded number of local time types */
50 char tzh_charcnt[4]; /* coded number of abbr. chars */ 50 char tzh_charcnt[4]; /* coded number of abbr. chars */
51}; 51};
52 52
53/* 53/*
54** . . .followed by. . . 54** . . .followed by. . .
55** 55**
56** tzh_timecnt (char [4])s coded transition times a la time(2) 56** tzh_timecnt (char [4])s coded transition times a la time(2)
57** tzh_timecnt (unsigned char)s types of local time starting at above 57** tzh_timecnt (unsigned char)s types of local time starting at above
58** tzh_typecnt repetitions of 58** tzh_typecnt repetitions of
59** one (char [4]) coded UTC offset in seconds 59** one (char [4]) coded UT offset in seconds
60** one (unsigned char) used to set tm_isdst 60** one (unsigned char) used to set tm_isdst
61** one (unsigned char) that's an abbreviation list index 61** one (unsigned char) that's an abbreviation list index
62** tzh_charcnt (char)s '\0'-terminated zone abbreviations 62** tzh_charcnt (char)s '\0'-terminated zone abbreviations
63** tzh_leapcnt repetitions of 63** tzh_leapcnt repetitions of
64** one (char [4]) coded leap second transition times 64** one (char [4]) coded leap second transition times
65** one (char [4]) total correction after above 65** one (char [4]) total correction after above
66** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition 66** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
67** time is standard time, if FALSE, 67** time is standard time, if FALSE,
68** transition time is wall clock time 68** transition time is wall clock time
69** if absent, transition times are 69** if absent, transition times are
70** assumed to be wall clock time 70** assumed to be wall clock time
71** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition 71** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
72** time is UTC, if FALSE, 72** time is UT, if FALSE,
73** transition time is local time 73** transition time is local time
74** if absent, transition times are 74** if absent, transition times are
75** assumed to be local time 75** assumed to be local time
76*/ 76*/
77 77
78/* 78/*
79** If tzh_version is '2' or greater, the above is followed by a second instance 79** If tzh_version is '2' or greater, the above is followed by a second instance
80** of tzhead and a second instance of the data in which each coded transition 80** of tzhead and a second instance of the data in which each coded transition
81** time uses 8 rather than 4 chars, 81** time uses 8 rather than 4 chars,
82** then a POSIX-TZ-environment-variable-style string for use in handling 82** then a POSIX-TZ-environment-variable-style string for use in handling
83** instants after the last transition time stored in the file 83** instants after the last transition time stored in the file
84** (with nothing between the newlines if there is no POSIX representation for 84** (with nothing between the newlines if there is no POSIX representation for
85** such instants). 85** such instants).
 86**
 87** If tz_version is '3' or greater, the above is extended as follows.
 88** First, the POSIX TZ string's hour offset may range from -167
 89** through 167 as compared to the POSIX-required 0 through 24.
 90** Second, its DST start time may be January 1 at 00:00 and its stop
 91** time December 31 at 24:00 plus the difference between DST and
 92** standard time, indicating DST all year.
86*/ 93*/
87 94
88/* 95/*
89** In the current implementation, "tzset()" refuses to deal with files that 96** In the current implementation, "tzset()" refuses to deal with files that
90** exceed any of the limits below. 97** exceed any of the limits below.
91*/ 98*/
92 99
93#ifndef TZ_MAX_TIMES 100#ifndef TZ_MAX_TIMES
94#define TZ_MAX_TIMES 1200 101#define TZ_MAX_TIMES 1200
95#endif /* !defined TZ_MAX_TIMES */ 102#endif /* !defined TZ_MAX_TIMES */
96 103
97#ifndef TZ_MAX_TYPES 104#ifndef TZ_MAX_TYPES
98#ifndef NOSOLAR 105#ifndef NOSOLAR

cvs diff -r1.19 -r1.20 src/lib/libc/time/tzfile.5 (expand / switch to unified diff)

--- src/lib/libc/time/tzfile.5 2013/03/02 21:24:28 1.19
+++ src/lib/libc/time/tzfile.5 2013/09/20 19:06:54 1.20
@@ -1,103 +1,99 @@ @@ -1,103 +1,99 @@
1.\" $NetBSD: tzfile.5,v 1.19 2013/03/02 21:24:28 christos Exp $ 1.\" $NetBSD: tzfile.5,v 1.20 2013/09/20 19:06:54 christos Exp $
2.\" 2.\"
3.\" This file is in the public domain, so clarified as of 3.\" This file is in the public domain, so clarified as of
4.\" 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). 4.\" 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
5.Dd September 16, 2001 5.Dd September 20, 2013
6.Dt TZFILE 5 6.Dt TZFILE 5
7.Os 7.Os
8.Sh NAME 8.Sh NAME
9.Nm tzfile 9.Nm tzfile
10.Nd time zone information 10.Nd time zone information
11.Sh SYNOPSIS 11.Sh SYNOPSIS
12.In tzfile.h 12.In tzfile.h
13.Sh DESCRIPTION 13.Sh DESCRIPTION
14The time zone information files used by 14The time zone information files used by
15.Xr tzset 3 15.Xr tzset 3
16begin with the magic characters 16begin with the magic characters
17.Dq TZif 17.Dq TZif
18to identify them as time zone information files, 18to identify them as time zone information files,
19followed by a character identifying the version of the file's format 19followed by a character identifying the version of the file's format
20(as of 2005, either an ASCII NUL or a '2') 20(as of 2013, either an ASCII NUL or a '2', or '3')
21followed by fifteen bytes containing zeroes reserved for future use, 21followed by fifteen bytes containing zeroes reserved for future use,
22followed by six four-byte values of type 22followed by six four-byte values of type
23.Fa long , 23.Fa long ,
24written in a 24followed by six four-byte integer values written in a
25.Dq standard 25.Dq standard
26byte order (the high-order byte of the value is written first). 26byte order (the high-order byte of the value is written first).
27These values are, in order: 27These values are, in order:
28.Bl -tag -width XXXXXX -compact 28.Bl -tag -width XXXXXX -compact
29.It Va tzh_ttisgmtcnt 29.It Va tzh_ttisgmtcnt
30The number of UTC/local indicators stored in the file. 30The number of UT/local indicators stored in the file.
31.It Va tzh_ttisstdcnt 31.It Va tzh_ttisstdcnt
32The number of standard/wall indicators stored in the file. 32The number of standard/wall indicators stored in the file.
33.It Va tzh_leapcnt 33.It Va tzh_leapcnt
34The number of leap seconds for which data is stored in the file. 34The number of leap seconds for which data is stored in the file.
35.It Va tzh_timecnt 35.It Va tzh_timecnt
36The number of 36The number of
37.Dq transition times 37.Dq transition times
38for which data is stored in the file. 38for which data is stored in the file.
39.It Va tzh_typecnt 39.It Va tzh_typecnt
40The number of 40The number of
41.Dq local time types 41.Dq local time types
42for which data is stored in the file (must not be zero). 42for which data is stored in the file (must not be zero).
43.It Va tzh_charcnt 43.It Va tzh_charcnt
44The number of characters of "time zone abbreviation strings" 44The number of characters of "time zone abbreviation strings"
45stored in the file. 45stored in the file.
46.El 46.El
47.Pp 47.Pp
48The above header is followed by 48The above header is followed by
49.Va tzh_timecnt 49.Va tzh_timecnt
50four-byte values of type 50four-byte signed integer values sorted in ascending order.
51.Fa long , 51These values are written in
52sorted in ascending order. 
53These values are written in 52These values are written in
54.Dq standard 53.Dq standard
55byte order. 54byte order.
56Each is used as a transition time (as returned by 55Each is used as a transition time (as returned by
57.Xr time 3 ) 56.Xr time 3 )
58at which the rules for computing local time change. 57at which the rules for computing local time change.
59Next come 58Next come
60.Va tzh_timecnt 59.Va tzh_timecnt
61one-byte values of type 60one-byte unsigned integer values;
62.Fa unsigned char ; 
63each one tells which of the different types of 61each one tells which of the different types of
64.Dq local time 62.Dq local time
65types described in the file is associated with the same-indexed 63types described in the file is associated with the same-indexed
66transition time. 64transition time.
67These values serve as indices into an array of 65These values serve as indices into an array of
68.Fa ttinfo 66.Fa ttinfo
69structures (with 67structures (with
70.Va tzh_typecnt 68.Va tzh_typecnt
71entries) that appears next in the file; 69entries) that appears next in the file;
72these structures are defined as follows: 70these structures are defined as follows:
73.Bd -literal 71.Bd -literal
74struct ttinfo { 72struct ttinfo {
75 long tt_gmtoff; 73 int32_t tt_gmtoff;
76 int tt_isdst; 74 unsigned char tt_isdst;
77 unsigned int tt_abbrind; 75 unsigned char tt_abbrind;
78}; 76};
79.Ed 77.Ed
80Each structure is written as a four-byte value for 78Each structure is written as a four-byte signed integer value for
81.Va tt_gmtoff 79.Va tt_gmtoff
82of type 
83.Fa long , 
84in a standard byte order, followed by a one-byte value for 80in a standard byte order, followed by a one-byte value for
85.Va tt_isdst 81.Va tt_isdst
86and a one-byte value for 82and a one-byte value for
87.Va tt_abbrind . 83.Va tt_abbrind .
88In each structure, 84In each structure,
89.Va tt_gmtoff 85.Va tt_gmtoff
90gives the number of seconds to be added to UTC, 86gives the number of seconds to be added to UT,
91.Va tt_isdst 87.Va tt_isdst
92tells whether 88tells whether
93.Va tm_isdst 89.Va tm_isdst
94should be set by 90should be set by
95.Xr localtime 3 91.Xr localtime 3
96and 92and
97.Va tt_abbrind 93.Va tt_abbrind
98serves as an index into the array of time zone abbreviation characters 94serves as an index into the array of time zone abbreviation characters
99that follow the 95that follow the
100.Va ttinfo 96.Va ttinfo
101structure(s) in the file. 97structure(s) in the file.
102.Pp 98.Pp
103Then there are 99Then there are
@@ -112,48 +108,62 @@ the second gives the @@ -112,48 +108,62 @@ the second gives the
112number of leap seconds to be applied after the given time. 108number of leap seconds to be applied after the given time.
113The pairs of values are sorted in ascending order by time. 109The pairs of values are sorted in ascending order by time.
114.Pp 110.Pp
115Then there are 111Then there are
116.Va tzh_ttisstdcnt 112.Va tzh_ttisstdcnt
117standard/wall indicators, each stored as a one-byte value; 113standard/wall indicators, each stored as a one-byte value;
118they tell whether the transition times associated with local time types 114they tell whether the transition times associated with local time types
119were specified as standard time or wall clock time, 115were specified as standard time or wall clock time,
120and are used when a time zone file is used in handling POSIX-style 116and are used when a time zone file is used in handling POSIX-style
121time zone environment variables. 117time zone environment variables.
122.Pp 118.Pp
123Finally there are 119Finally there are
124.Va tzh_ttisgmtcnt 120.Va tzh_ttisgmtcnt
125UTC/local indicators, each stored as a one-byte value; 121UT/local indicators, each stored as a one-byte value;
126they tell whether the transition times associated with local time types 122they tell whether the transition times associated with local time types
127were specified as UTC or local time, 123were specified as UT or local time,
128and are used when a time zone file is used in handling POSIX-style 124and are used when a time zone file is used in handling POSIX-style
129time zone environment variables. 125time zone environment variables.
130.Pp 126.Pp
131.Xr localtime 3 127.Xr localtime 3
132uses the first standard-time 128uses the first standard-time
133.Fa ttinfo 129.Fa ttinfo
134structure in the file 130structure in the file
135(or simply the first 131(or simply the first
136.Fa ttinfo 132.Fa ttinfo
137structure in the absence of a standard-time structure) 133structure in the absence of a standard-time structure)
138if either 134if either
139.Va tzh_timecnt 135.Va tzh_timecnt
140is zero or the time argument is less than the first transition time recorded 136is zero or the time argument is less than the first transition time recorded
141in the file. 137in the file.
142.Pp 138.Pp
143For version-2-format time zone files, 139For version-2-format time zone files,
144the above header and data are followed by a second header and data, 140the above header and data are followed by a second header and data,
145identical in format except that 141identical in format except that
146eight bytes are used for each transition time or leap second time. 142eight bytes are used for each transition time or leap second time.
147After the second header and data comes a newline-enclosed, 143After the second header and data comes a newline-enclosed,
148POSIX-TZ-environment-variable-style string for use in handling instants 144POSIX-TZ-environment-variable-style string for use in handling instants
149after the last transition time stored in the file 145after the last transition time stored in the file
150(with nothing between the newlines if there is no POSIX representation for 146(with nothing between the newlines if there is no POSIX representation for
151such instants). 147such instants).
 148.Pp
 149For version-3-format time zone files, the POSIX-TZ-style string may
 150use two minor extensions to the POSIX TZ format, as described in
 151.Xr tzset 3 .
 152First, the hours part of its transition times may be signed and range from
 153\(mi167 through 167 instead of the POSIX-required unsigned values
 154from 0 through 24.
 155Second, DST is in effect all year if it starts
 156January 1 at 00:00 and ends December 31 at 24:00 plus the difference
 157between daylight saving and standard time.
 158.Pp
 159Future changes to the format may append more data.
152.Sh SEE ALSO 160.Sh SEE ALSO
153.Xr ctime 3 , 161.Xr ctime 3 ,
154.Xr localtime 3 , 162.Xr localtime 3 ,
155.Xr time 3 , 163.Xr time 3 ,
 164.Xr tzset 3 ,
156.Xr zdump 8 165.Xr zdump 8
 166.Xr zic 8
157.\" @(#)tzfile.5 8.3 167.\" @(#)tzfile.5 8.3
158.\" This file is in the public domain, so clarified as of 168.\" This file is in the public domain, so clarified as of
159.\" 1996-06-05 by Arthur David Olson. 169.\" 1996-06-05 by Arthur David Olson.

cvs diff -r1.4 -r1.5 src/lib/libc/time/tzselect.8 (expand / switch to unified diff)

--- src/lib/libc/time/tzselect.8 2009/12/31 22:49:16 1.4
+++ src/lib/libc/time/tzselect.8 2013/09/20 19:06:54 1.5
@@ -1,45 +1,115 @@ @@ -1,45 +1,115 @@
1.\" $NetBSD: tzselect.8,v 1.4 2009/12/31 22:49:16 mlelstv Exp $ 1.\" $NetBSD: tzselect.8,v 1.5 2013/09/20 19:06:54 christos Exp $
2.\" 2.\"
3.TH TZSELECT 8 3.TH TZSELECT 8
4.SH NAME 4.SH NAME
5tzselect \- select a time zone 5tzselect \- select a time zone
6.SH SYNOPSIS 6.SH SYNOPSIS
7.B tzselect 7.B tzselect
 8[
 9.B \-c
 10.I coord
 11] [
 12.B \-n
 13.I limit
 14] [
 15.B \-\-help
 16] [
 17.B \-\-version
 18]
8.SH DESCRIPTION 19.SH DESCRIPTION
9The 20The
10.B tzselect 21.B tzselect
11program asks the user for information about the current location, 22program asks the user for information about the current location,
12and outputs the resulting time zone description to standard output. 23and outputs the resulting time zone description to standard output.
13The output is suitable as a value for the TZ environment variable. 24The output is suitable as a value for the TZ environment variable.
14.PP 25.PP
15All interaction with the user is done via standard input and standard error. 26All interaction with the user is done via standard input and standard error.
 27.SH OPTIONS
 28.TP
 29.BI "\-c " coord
 30Instead of asking for continent and then country and then city,
 31ask for selection from time zones whose largest cities
 32are closest to the location with geographical coordinates
 33.I coord.
 34Use ISO 6709 notation for
 35.I coord,
 36that is, a latitude immediately followed by a longitude. The latitude
 37and longitude should be signed integers followed by an optional
 38decimal point and fraction: positive numbers represent north and east,
 39negative south and west. Latitudes with two and longitudes with three
 40integer digits are treated as degrees; latitudes with four or six and
 41longitudes with five or seven integer digits are treated as
 42.I "DDMM, DDDMM, DDMMSS,"
 43or
 44.I DDDMMSS
 45representing
 46.I DD
 47or
 48.I DDD
 49degrees,
 50.I MM
 51minutes,
 52and zero or
 53.I SS
 54seconds, with any trailing fractions represent fractional minutes or
 55(if
 56.I SS
 57is present) seconds. The decimal point is that of the current locale.
 58For example, in the (default) C locale,
 59.B "\-c\ +40.689\-074.045"
 60specifies 40.689\(de\|N, 74.045\(de\|W,
 61.B "\-c\ +4041.4\-07402.7"
 62specifies 40\(de\|41.4\(fm\|N, 74\(de\|2.7\(fm\|W, and
 63.B "\-c\ +404121\-0740240"
 64specifies 40\(de\|41\(fm\|21\(sd\|N, 74\(de\|2\(fm\|40\(sd\|W.
 65If
 66.I coord
 67is not one of the documented forms, the resulting behavior is unspecified.
 68.TP
 69.BI "\-n " limit
 70When
 71.B \-c
 72is used, display the closest
 73.I limit
 74locations (default 10).
 75.PP
 76Applications should not assume that
 77.BR tzselect 's
 78output matches the user's political preferences.
 79.RE
 80.TP
 81.B "\-\-help"
 82Output help information and exit.
 83.TP
 84.B "\-\-version"
 85Output version information and exit.
16.SH "ENVIRONMENT VARIABLES" 86.SH "ENVIRONMENT VARIABLES"
17.TP 87.TP
18\f3AWK\fP 88\f3AWK\fP
19Name of a Posix-compliant 89Name of a Posix-compliant
20.I awk 90.I awk
21program (default: 91program (default:
22.BR awk ). 92.BR awk ).
23.TP 93.TP
24\f3TZDIR\fP 94\f3TZDIR\fP
25Name of the directory containing time zone data files (default: 95Name of the directory containing time zone data files (default:
26.BR /usr/local/etc/zoneinfo ). 96.BR /usr/local/etc/zoneinfo ).
27.SH FILES 97.SH FILES
28.TP 98.TP
29\f2TZDIR\fP\f3/iso3166.tab\fP 99\f2TZDIR\fP\f3/iso3166.tab\fP
30Table of ISO 3166 2-letter country codes and country names. 100Table of ISO 3166 2-letter country codes and country names.
31.TP 101.TP
32\f2TZDIR\fP\f3/zone.tab\fP 102\f2TZDIR\fP\f3/zone.tab\fP
33Table of country codes, latitude and longitude, TZ values, and 103Tables of country codes, latitude and longitude, zone names, and
34descriptive comments. 104descriptive comments.
35.TP 105.TP
36\f2TZDIR\fP\f3/\fP\f2TZ\fP 106\f2TZDIR\fP\f3/\fP\f2TZ\fP
37Time zone data file for time zone \f2TZ\fP. 107Time zone data file for time zone \f2TZ\fP.
38.SH "EXIT STATUS" 108.SH "EXIT STATUS"
39The exit status is zero if a time zone was successfully obtained from the user, 109The exit status is zero if a time zone was successfully obtained from the user,
40nonzero otherwise. 110nonzero otherwise.
41.SH "SEE ALSO" 111.SH "SEE ALSO"
42newctime(3), tzfile(5), zdump(8), zic(8) 112newctime(3), tzfile(5), zdump(8), zic(8)
43.\" @(#)tzselect.8 8.2 113.\" @(#)tzselect.8 8.2
44.\" This file is in the public domain, so clarified as of 114.\" This file is in the public domain, so clarified as of
45.\" 2009-05-17 by Arthur David Olson. 115.\" 2009-05-17 by Arthur David Olson.

cvs diff -r1.8 -r1.9 src/lib/libc/time/tzselect.ksh (expand / switch to unified diff)

--- src/lib/libc/time/tzselect.ksh 2013/03/02 21:24:28 1.8
+++ src/lib/libc/time/tzselect.ksh 2013/09/20 19:06:54 1.9
@@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
1#! /bin/bash 1#! /bin/bash
2# 2#
3# $NetBSD: tzselect.ksh,v 1.8 2013/03/02 21:24:28 christos Exp $ 3# $NetBSD: tzselect.ksh,v 1.9 2013/09/20 19:06:54 christos Exp $
4# 4#
5PKGVERSION='(tzcode) ' 5PKGVERSION='(tzcode) '
6TZVERSION=see_Makefile 6TZVERSION=see_Makefile
7REPORT_BUGS_TO=tz@iana.org 7REPORT_BUGS_TO=tz@iana.org
8 8
9# Ask the user about the time zone, and output the resulting TZ value to stdout. 9# Ask the user about the time zone, and output the resulting TZ value to stdout.
10# Interact with the user via stderr and stdin. 10# Interact with the user via stderr and stdin.
11 11
12# Contributed by Paul Eggert. 12# Contributed by Paul Eggert.
13 13
14# Porting notes: 14# Porting notes:
15# 15#
16# This script requires a Posix-like shell with the extension of a 16# This script requires a Posix-like shell with the extension of a
@@ -32,130 +32,279 @@ REPORT_BUGS_TO=tz@iana.org @@ -32,130 +32,279 @@ REPORT_BUGS_TO=tz@iana.org
32 32
33 33
34# Specify default values for environment variables if they are unset. 34# Specify default values for environment variables if they are unset.
35: ${AWK=awk} 35: ${AWK=awk}
36: ${TZDIR=$(pwd)} 36: ${TZDIR=$(pwd)}
37 37
38# Check for awk Posix compliance. 38# Check for awk Posix compliance.
39($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1 39($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1
40[ $? = 123 ] || { 40[ $? = 123 ] || {
41 echo >&2 "$0: Sorry, your \`$AWK' program is not Posix compatible." 41 echo >&2 "$0: Sorry, your \`$AWK' program is not Posix compatible."
42 exit 1 42 exit 1
43} 43}
44 44
45if [ "$1" = "--help" ]; then 45coord=
46 cat <<EOF 46location_limit=10
47Usage: tzselect 47
 48usage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT]
48Select a time zone interactively. 49Select a time zone interactively.
49 50
50Report bugs to $REPORT_BUGS_TO. 51Options:
51EOF 52
52 exit 53 -c COORD
53elif [ "$1" = "--version" ]; then 54 Instead of asking for continent and then country and then city,
54 cat <<EOF 55 ask for selection from time zones whose largest cities
55tzselect $TZVERSION 56 are closest to the location with geographical coordinates COORD.
56EOF 57 COORD should use ISO 6709 notation, for example, '-c +4852+00220'
57 exit 58 for Paris (in degrees and minutes, North and East), or
58fi 59 '-c -35-058' for Buenos Aires (in degrees, South and West).
 60
 61 -n LIMIT
 62 Display at most LIMIT locations when -c is used (default $location_limit).
 63
 64 --version
 65 Output version information.
 66
 67 --help
 68 Output this help.
 69
 70Report bugs to $REPORT_BUGS_TO."
 71
 72while getopts c:n:-: opt
 73do
 74 case $opt$OPTARG in
 75 c*)
 76 coord=$OPTARG ;;
 77 n*)
 78 location_limit=$OPTARG ;;
 79 -help)
 80 exec echo "$usage" ;;
 81 -version)
 82 exec echo "tzselect $PKGVERSION$TZVERSION" ;;
 83 -*)
 84 echo >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1 ;;
 85 *)
 86 echo >&2 "$0: try '$0 --help'"; exit 1 ;;
 87 esac
 88done
 89
 90shift $((OPTIND-1))
 91case $# in
 920) ;;
 93*) echo >&2 "$0: $1: unknown argument"; exit 1 ;;
 94esac
59 95
60# Make sure the tables are readable. 96# Make sure the tables are readable.
61TZ_COUNTRY_TABLE=$TZDIR/iso3166.tab 97TZ_COUNTRY_TABLE=$TZDIR/iso3166.tab
62TZ_ZONE_TABLE=$TZDIR/zone.tab 98TZ_ZONE_TABLE=$TZDIR/zone.tab
63for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE 99for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE
64do 100do
65 <$f || { 101 <$f || {
66 echo >&2 "$0: time zone files are not set up correctly" 102 echo >&2 "$0: time zone files are not set up correctly"
67 exit 1 103 exit 1
68 } 104 }
69done 105done
70 106
71newline=' 107newline='
72' 108'
73IFS=$newline 109IFS=$newline
74 110
75 111
76# Work around a bug in bash 1.14.7 and earlier, where $PS3 is sent to stdout. 112# Work around a bug in bash 1.14.7 and earlier, where $PS3 is sent to stdout.
77case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in 113case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in
78?*) PS3= 114?*) PS3=
79esac 115esac
80 116
 117# Awk script to read a time zone table and output the same table,
 118# with each column preceded by its distance from 'here'.
 119output_distances='
 120 BEGIN {
 121 FS = "\t"
 122 while (getline <TZ_COUNTRY_TABLE)
 123 if ($0 ~ /^[^#]/)
 124 country[$1] = $2
 125 country["US"] = "US" # Otherwise the strings get too long.
 126 }
 127 function convert_coord(coord, deg, min, ilen, sign, sec) {
 128 if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) {
 129 degminsec = coord
 130 intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000)
 131 minsec = degminsec - intdeg * 10000
 132 intmin = minsec < 0 ? -int(-minsec / 100) : int(minsec / 100)
 133 sec = minsec - intmin * 100
 134 deg = (intdeg * 3600 + intmin * 60 + sec) / 3600
 135 } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) {
 136 degmin = coord
 137 intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100)
 138 min = degmin - intdeg * 100
 139 deg = (intdeg * 60 + min) / 60
 140 } else
 141 deg = coord
 142 return deg * 0.017453292519943296
 143 }
 144 function convert_latitude(coord) {
 145 match(coord, /..*[-+]/)
 146 return convert_coord(substr(coord, 1, RLENGTH - 1))
 147 }
 148 function convert_longitude(coord) {
 149 match(coord, /..*[-+]/)
 150 return convert_coord(substr(coord, RLENGTH))
 151 }
 152 # Great-circle distance between points with given latitude and longitude.
 153 # Inputs and output are in radians. This uses the great-circle special
 154 # case of the Vicenty formula for distances on ellipsoids.
 155 function dist(lat1, long1, lat2, long2, dlong, x, y, num, denom) {
 156 dlong = long2 - long1
 157 x = cos (lat2) * sin (dlong)
 158 y = cos (lat1) * sin (lat2) - sin (lat1) * cos (lat2) * cos (dlong)
 159 num = sqrt (x * x + y * y)
 160 denom = sin (lat1) * sin (lat2) + cos (lat1) * cos (lat2) * cos (dlong)
 161 return atan2(num, denom)
 162 }
 163 BEGIN {
 164 coord_lat = convert_latitude(coord)
 165 coord_long = convert_longitude(coord)
 166 }
 167 /^[^#]/ {
 168 here_lat = convert_latitude($2)
 169 here_long = convert_longitude($2)
 170 line = $1 "\t" $2 "\t" $3 "\t" country[$1]
 171 if (NF == 4)
 172 line = line " - " $4
 173 printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), line
 174 }
 175'
81 176
82# Begin the main loop. We come back here if the user wants to retry. 177# Begin the main loop. We come back here if the user wants to retry.
83while 178while
84 179
85 echo >&2 'Please identify a location' \ 180 echo >&2 'Please identify a location' \
86 'so that time zone rules can be set correctly.' 181 'so that time zone rules can be set correctly.'
87 182
88 continent= 183 continent=
89 country= 184 country=
90 region= 185 region=
91 186
 187 case $coord in
 188 ?*)
 189 continent=coord;;
 190 '')
92 191
93 # Ask the user for continent or ocean. 192 # Ask the user for continent or ocean.
94 193
95 echo >&2 'Please select a continent or ocean.' 194 echo >&2 'Please select a continent, ocean, "coord", or "TZ".'
96 195
97 select continent in \ 196 quoted_continents=$(
98 Africa \ 197 $AWK -F'\t' '
99 Americas \ 198 /^[^#]/ {
100 Antarctica \ 199 entry = substr($3, 1, index($3, "/") - 1)
101 'Arctic Ocean' \ 200 if (entry == "America")
102 Asia \ 201 entry = entry "s"
103 'Atlantic Ocean' \ 202 if (entry ~ /^(Arctic|Atlantic|Indian|Pacific)$/)
104 Australia \ 203 entry = entry " Ocean"
105 Europe \ 204 printf "'\''%s'\''\n", entry
106 'Indian Ocean' \ 205 }
107 'Pacific Ocean' \ 206 ' $TZ_ZONE_TABLE |
108 'none - I want to specify the time zone using the Posix TZ format.' 207 sort -u |
109 do 208 tr '\n' ' '
110 case $continent in 209 echo ''
111 '') 210 )
112 echo >&2 'Please enter a number in range.';; 211
113 ?*) 212 eval '
 213 select continent in '"$quoted_continents"' \
 214 "coord - I want to use geographical coordinates." \
 215 "TZ - I want to specify the time zone using the Posix TZ format."
 216 do
114 case $continent in 217 case $continent in
115 Americas) continent=America;; 218 "")
116 *' '*) continent=$(expr "$continent" : '\([^ ]*\)') 219 echo >&2 "Please enter a number in range.";;
 220 ?*)
 221 case $continent in
 222 Americas) continent=America;;
 223 *" "*) continent=$(expr "$continent" : '\''\([^ ]*\)'\'')
 224 esac
 225 break
117 esac 226 esac
118 break 227 done
119 esac 228 '
120 done 229 esac
 230
121 case $continent in 231 case $continent in
122 '') 232 '')
123 exit 1;; 233 exit 1;;
124 none) 234 TZ)
125 # Ask the user for a Posix TZ string. Check that it conforms. 235 # Ask the user for a Posix TZ string. Check that it conforms.
126 while 236 while
127 echo >&2 'Please enter the desired value' \ 237 echo >&2 'Please enter the desired value' \
128 'of the TZ environment variable.' 238 'of the TZ environment variable.'
129 echo >&2 'For example, GST-10 is a zone named GST' \ 239 echo >&2 'For example, GST-10 is a zone named GST' \
130 'that is 10 hours ahead (east) of UTC.' 240 'that is 10 hours ahead (east) of UTC.'
131 read TZ 241 read TZ
132 $AWK -v TZ="$TZ" 'BEGIN { 242 $AWK -v TZ="$TZ" 'BEGIN {
133 tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+" 243 tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+"
134 time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?" 244 time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?"
135 offset = "[-+]?" time 245 offset = "[-+]?" time
136 date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)" 246 date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)"
137 datetime = "," date "(/" time ")?" 247 datetime = "," date "(/" time ")?"
138 tzpattern = "^(:.*|" tzname offset "(" tzname \ 248 tzpattern = "^(:.*|" tzname offset "(" tzname \
139 "(" offset ")?(" datetime datetime ")?)?)$" 249 "(" offset ")?(" datetime datetime ")?)?)$"
140 if (TZ ~ tzpattern) exit 1 250 if (TZ ~ tzpattern) exit 1
141 exit 0 251 exit 0
142 }' 252 }'
143 do 253 do
144 echo >&2 "\`$TZ' is not a conforming" \ 254 echo >&2 "\`$TZ' is not a conforming" \
145 'Posix time zone string.' 255 'Posix time zone string.'
146 done 256 done
147 TZ_for_date=$TZ;; 257 TZ_for_date=$TZ;;
148 *) 258 *)
 259 case $continent in
 260 coord)
 261 case $coord in
 262 '')
 263 echo >&2 'Please enter coordinates' \
 264 'in ISO 6709 notation.'
 265 echo >&2 'For example, +4042-07403 stands for'
 266 echo >&2 '40 degrees 42 minutes north,' \
 267 '74 degrees 3 minutes west.'
 268 read coord;;
 269 esac
 270 distance_table=$($AWK \
 271 -v coord="$coord" \
 272 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
 273 "$output_distances" <$TZ_ZONE_TABLE |
 274 sort -n |
 275 sed "${location_limit}q"
 276 )
 277 regions=$(echo "$distance_table" | $AWK '
 278 BEGIN { FS = "\t" }
 279 { print $NF }
 280 ')
 281 echo >&2 'Please select one of the following' \
 282 'time zone regions,'
 283 echo >&2 'listed roughly in increasing order' \
 284 "of distance from $coord".
 285 select region in $regions
 286 do
 287 case $region in
 288 '') echo >&2 'Please enter a number in range.';;
 289 ?*) break;;
 290 esac
 291 done
 292 TZ=$(echo "$distance_table" | $AWK -v region="$region" '
 293 BEGIN { FS="\t" }
 294 $NF == region { print $4 }
 295 ')
 296 ;;
 297 *)
149 # Get list of names of countries in the continent or ocean. 298 # Get list of names of countries in the continent or ocean.
150 countries=$($AWK -F'\t' \ 299 countries=$($AWK -F'\t' \
151 -v continent="$continent" \ 300 -v continent="$continent" \
152 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ 301 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
153 ' 302 '
154 /^#/ { next } 303 /^#/ { next }
155 $3 ~ ("^" continent "/") { 304 $3 ~ ("^" continent "/") {
156 if (!cc_seen[$1]++) cc_list[++ccs] = $1 305 if (!cc_seen[$1]++) cc_list[++ccs] = $1
157 } 306 }
158 END { 307 END {
159 while (getline <TZ_COUNTRY_TABLE) { 308 while (getline <TZ_COUNTRY_TABLE) {
160 if ($0 !~ /^#/) cc_name[$1] = $2 309 if ($0 !~ /^#/) cc_name[$1] = $2
161 } 310 }
@@ -163,27 +312,28 @@ while @@ -163,27 +312,28 @@ while
163 country = cc_list[i] 312 country = cc_list[i]
164 if (cc_name[country]) { 313 if (cc_name[country]) {
165 country = cc_name[country] 314 country = cc_name[country]
166 } 315 }
167 print country 316 print country
168 } 317 }
169 } 318 }
170 ' <$TZ_ZONE_TABLE | sort -f) 319 ' <$TZ_ZONE_TABLE | sort -f)
171 320
172 321
173 # If there's more than one country, ask the user which one. 322 # If there's more than one country, ask the user which one.
174 case $countries in 323 case $countries in
175 *"$newline"*) 324 *"$newline"*)
176 echo >&2 'Please select a country.' 325 echo >&2 'Please select a country' \
 326 'whose clocks agree with yours.'
177 select country in $countries 327 select country in $countries
178 do 328 do
179 case $country in 329 case $country in
180 '') echo >&2 'Please enter a number in range.';; 330 '') echo >&2 'Please enter a number in range.';;
181 ?*) break 331 ?*) break
182 esac 332 esac
183 done 333 done
184 334
185 case $country in 335 case $country in
186 '') exit 1 336 '') exit 1
187 esac;; 337 esac;;
188 *) 338 *)
189 country=$countries 339 country=$countries
@@ -234,26 +384,27 @@ while @@ -234,26 +384,27 @@ while
234 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ 384 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
235 ' 385 '
236 BEGIN { 386 BEGIN {
237 cc = country 387 cc = country
238 while (getline <TZ_COUNTRY_TABLE) { 388 while (getline <TZ_COUNTRY_TABLE) {
239 if ($0 !~ /^#/ && country == $2) { 389 if ($0 !~ /^#/ && country == $2) {
240 cc = $1 390 cc = $1
241 break 391 break
242 } 392 }
243 } 393 }
244 } 394 }
245 $1 == cc && $4 == region { print $3 } 395 $1 == cc && $4 == region { print $3 }
246 ' <$TZ_ZONE_TABLE) 396 ' <$TZ_ZONE_TABLE)
 397 esac
247 398
248 # Make sure the corresponding zoneinfo file exists. 399 # Make sure the corresponding zoneinfo file exists.
249 TZ_for_date=$TZDIR/$TZ 400 TZ_for_date=$TZDIR/$TZ
250 <$TZ_for_date || { 401 <$TZ_for_date || {
251 echo >&2 "$0: time zone files are not set up correctly" 402 echo >&2 "$0: time zone files are not set up correctly"
252 exit 1 403 exit 1
253 } 404 }
254 esac 405 esac
255 406
256 407
257 # Use the proposed TZ to output the current date relative to UTC. 408 # Use the proposed TZ to output the current date relative to UTC.
258 # Loop until they agree in seconds. 409 # Loop until they agree in seconds.
259 # Give up after 8 unsuccessful tries. 410 # Give up after 8 unsuccessful tries.
@@ -270,48 +421,50 @@ while @@ -270,48 +421,50 @@ while
270 extra_info=" 421 extra_info="
271Local time is now: $TZdate. 422Local time is now: $TZdate.
272Universal Time is now: $UTdate." 423Universal Time is now: $UTdate."
273 break 424 break
274 esac 425 esac
275 done 426 done
276 427
277 428
278 # Output TZ info and ask the user to confirm. 429 # Output TZ info and ask the user to confirm.
279 430
280 echo >&2 "" 431 echo >&2 ""
281 echo >&2 "The following information has been given:" 432 echo >&2 "The following information has been given:"
282 echo >&2 "" 433 echo >&2 ""
283 case $country+$region in 434 case $country%$region%$coord in
284 ?*+?*) echo >&2 " $country$newline $region";; 435 ?*%?*%) echo >&2 " $country$newline $region";;
285 ?*+) echo >&2 " $country";; 436 ?*%%) echo >&2 " $country";;
 437 %?*%?*) echo >&2 " coord $coord$newline $region";;
 438 %%?*) echo >&2 " coord $coord";;
286 +) echo >&2 " TZ='$TZ'" 439 +) echo >&2 " TZ='$TZ'"
287 esac 440 esac
288 echo >&2 "" 441 echo >&2 ""
289 echo >&2 "Therefore TZ='$TZ' will be used.$extra_info" 442 echo >&2 "Therefore TZ='$TZ' will be used.$extra_info"
290 echo >&2 "Is the above information OK?" 443 echo >&2 "Is the above information OK?"
291 444
292 ok= 445 ok=
293 select ok in Yes No 446 select ok in Yes No
294 do 447 do
295 case $ok in 448 case $ok in
296 '') echo >&2 'Please enter 1 for Yes, or 2 for No.';; 449 '') echo >&2 'Please enter 1 for Yes, or 2 for No.';;
297 ?*) break 450 ?*) break
298 esac 451 esac
299 done 452 done
300 case $ok in 453 case $ok in
301 '') exit 1;; 454 '') exit 1;;
302 Yes) break 455 Yes) break
303 esac 456 esac
304do : 457do coord=
305done 458done
306 459
307case $SHELL in 460case $SHELL in
308*csh) file=.login line="setenv TZ '$TZ'";; 461*csh) file=.login line="setenv TZ '$TZ'";;
309*) file=.profile line="TZ='$TZ'; export TZ" 462*) file=.profile line="TZ='$TZ'; export TZ"
310esac 463esac
311 464
312echo >&2 " 465echo >&2 "
313You can make this change permanent for yourself by appending the line 466You can make this change permanent for yourself by appending the line
314 $line 467 $line
315to the file '$file' in your home directory; then log out and log in again. 468to the file '$file' in your home directory; then log out and log in again.
316 469
317Here is that TZ value again, this time on standard output so that you 470Here is that TZ value again, this time on standard output so that you

cvs diff -r1.25 -r1.26 src/lib/libc/time/tzset.3 (expand / switch to unified diff)

--- src/lib/libc/time/tzset.3 2010/12/17 01:29:45 1.25
+++ src/lib/libc/time/tzset.3 2013/09/20 19:06:54 1.26
@@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
1.\" $NetBSD: tzset.3,v 1.25 2010/12/17 01:29:45 wiz Exp $ 1.\" $NetBSD: tzset.3,v 1.26 2013/09/20 19:06:54 christos Exp $
2.Dd April 1, 2001 2.Dd September 20, 2013
3.Dt TZSET 3 3.Dt TZSET 3
4.Os 4.Os
5.Sh NAME 5.Sh NAME
6.Nm tzset 6.Nm tzset
7.Nd initialize time conversion information 7.Nd initialize time conversion information
8.Sh LIBRARY 8.Sh LIBRARY
9.Lb libc 9.Lb libc
10.Sh SYNOPSIS 10.Sh SYNOPSIS
11.In time.h 11.In time.h
12.Ft void 12.Ft void
13.Fn tzset "void" 13.Fn tzset "void"
14.Sh DESCRIPTION 14.Sh DESCRIPTION
15The 15The
@@ -21,28 +21,30 @@ to set time conversion information used  @@ -21,28 +21,30 @@ to set time conversion information used
21If 21If
22.Ev TZ 22.Ev TZ
23does not appear in the environment, 23does not appear in the environment,
24the best available approximation to local wall clock time, as 24the best available approximation to local wall clock time, as
25specified by the 25specified by the
26.Xr tzfile 5 26.Xr tzfile 5
27format file 27format file
28.Pa /etc/localtime 28.Pa /etc/localtime
29is used by 29is used by
30.Xr localtime 3 . 30.Xr localtime 3 .
31If 31If
32.Ev TZ 32.Ev TZ
33appears in the environment but its value is a null string, 33appears in the environment but its value is a null string,
34Coordinated Universal Time (UTC) is used (without leap second 34Universal Time (UT) is used, with the abbreviation
35correction). 35.Dq UTC
 36and without leap second correction; please see
 37.Xr ctime 3 .
36If 38If
37.Ev TZ 39.Ev TZ
38appears in the environment and its value is not a null string: 40appears in the environment and its value is not a null string:
39.Bl -dash 41.Bl -dash
40.It 42.It
41if the value begins with a colon, it is used as a pathname of a file 43if the value begins with a colon, it is used as a pathname of a file
42from which to read the time conversion information; 44from which to read the time conversion information;
43.It 45.It
44if the value does not begin with a colon, it is first used as the 46if the value does not begin with a colon, it is first used as the
45pathname of a file from which to read the time conversion information, 47pathname of a file from which to read the time conversion information,
46and, if that file cannot be read, is used directly as a specification 48and, if that file cannot be read, is used directly as a specification
47of the time conversion information. 49of the time conversion information.
48.El 50.El
@@ -141,26 +143,30 @@ has the form: @@ -141,26 +143,30 @@ has the form:
141.Ed 143.Ed
142.Sm on 144.Sm on
143.Pp 145.Pp
144where the first 146where the first
145.Cm date 147.Cm date
146describes when the change from standard to summer time occurs and the 148describes when the change from standard to summer time occurs and the
147second 149second
148.Cm date 150.Cm date
149describes when the change back happens. 151describes when the change back happens.
150Each 152Each
151.Cm time 153.Cm time
152field describes when, in current local time, the change to the other 154field describes when, in current local time, the change to the other
153time is made. 155time is made.
 156As an extension to POSIX, daylight saving is assumed to be in effect
 157all year if it begins January 1 at 00:00 and ends December 31 at
 15824:00 plus the difference between daylight saving and standard time,
 159leaving no room for standard time in the calendar.
154The format of 160The format of
155.Fa date 161.Fa date
156is one of the following: 162is one of the following:
157.Bl -tag -width "The Julian day" -compact 163.Bl -tag -width "The Julian day" -compact
158.It Cm J Ns Ar n 164.It Cm J Ns Ar n
159The Julian day 165The Julian day
160.Ar n 166.Ar n
161(1 \*[Le] 167(1 \*[Le]
162.Ar n 168.Ar n
163\*[Le] 365). 169\*[Le] 365).
164Leap days are not counted; that is, in all years \(em including leap 170Leap days are not counted; that is, in all years \(em including leap
165years \(em February 28 is day 59 and March 1 is day 60. 171years \(em February 28 is day 59 and March 1 is day 60.
166It is impossible to explicitly refer to the occasional February 29. 172It is impossible to explicitly refer to the occasional February 29.
@@ -189,36 +195,77 @@ of the year @@ -189,36 +195,77 @@ of the year
189.Ar m 195.Ar m
190\*[Le]\ 12, where week 5 means 196\*[Le]\ 12, where week 5 means
191.Dq the\ last Ar d No day\ in\ month Ar m 197.Dq the\ last Ar d No day\ in\ month Ar m
192which may occur in either the fourth or the fifth week). 198which may occur in either the fourth or the fifth week).
193Week 1 is the first week in which the 199Week 1 is the first week in which the
194.Ar d Ns 'th 200.Ar d Ns 'th
195day occurs. 201day occurs.
196Day zero is Sunday. 202Day zero is Sunday.
197.El 203.El
198The 204The
199.Cm time 205.Cm time
200has the same format as 206has the same format as
201.Cm offset 207.Cm offset
202except that no leading sign 208except that POSIX does not allow a leading sign
203.Dq - 209.Dq -
204or 210or
205.Dq + 211.Dq +
206is allowed. 212is allowed.
 213As an extension to POSIX, the hours part of
 214.Cm time
 215can range from \(mi167 through 167; this allows for unusual rules such as
 216.Dq the Saturday before the first Sunday of March .
207The default, if 217The default, if
208.Cm time 218.Cm time
209is not given, is 219is not given, is
210.Cm 02:00:00 . 220.Cm 02:00:00 .
211.El 221.El
 222.Pp
 223Here are some examples of
 224.Va TZ
 225values that directly specify the time zone rules; they use some of the
 226extensions to POSIX.
 227.Bl -tag
 228.It EST5
 229stands for US eastern
 230time (EST), 5 hours behind UTC, without daylight saving.
 231.It FJT\(mi12FJST,M10.3.1/146,M1.3.4/75
 232stands for Fiji Time (FJT) and Fiji Summer Time (FJST), 12 hours ahead
 233of UTC, springing forward on October's third Monday at
 234146:00 (i.e., 02:00 on the first Sunday on or after October 21), and
 235falling back on January's third Thursday at 75:00 (i.e., 03:00 on the
 236first Sunday on or after January 18).
 237.It IST\(mi2IDT,M3.4.4/26,M10.5.0
 238stands for Israel Standard Time (IST) and Israel Daylight Time (IDT),
 2392 hours ahead of UTC, springing forward on March's fourth
 240Tuesday at 26:00 (i.e., 02:00 on the first Friday on or after March
 24123), and falling back on October's last Sunday at 02:00.
 242.It WART4WARST,J1/0,J365/25
 243stands for Western Argentina Summer Time (WARST), 3 hours behind UTC.
 244There is a dummy fall-back transition on December 31 at 25:00 daylight
 245saving time (i.e., 24:00 standard time, equivalent to January 1 at
 24600:00 standard time), and a simultaneous spring-forward transition on
 247January 1 at 00:00 standard time, so daylight saving time is in effect
 248all year and the initial
 249.Em WART
 250is a placeholder.
 251.It WGT3WGST,M3.5.0/\(mi2,M10.5.0/\(mi1
 252stands for Western Greenland time (WGT) and Western Greenland Summer
 253Time (WGST), 3 hours behind UTC, where clocks follow the EU rules of
 254springing forward on March's last Sunday at 01:00 UTC (\(mi02:00 local
 255time) and falling back on October's last Sunday at 01:00 UTC
 256(\(mi01:00 local time).
 257.El
 258.Pp
212If no 259If no
213.Cm rule 260.Cm rule
214is present in 261is present in
215.Ev TZ , 262.Ev TZ ,
216the rules specified by the 263the rules specified by the
217.Xr tzfile 5 264.Xr tzfile 5
218format file 265format file
219.Pa posixrules 266.Pa posixrules
220in 267in
221.Pa /usr/share/zoneinfo 268.Pa /usr/share/zoneinfo
222are used, with the standard and summer time offsets from UTC replaced 269are used, with the standard and summer time offsets from UTC replaced
223by those specified by the 270by those specified by the
224.Cm offset 271.Cm offset

cvs diff -r1.1 -r1.2 src/lib/libc/time/Attic/version.h (expand / switch to unified diff)

--- src/lib/libc/time/Attic/version.h 2012/08/09 12:38:26 1.1
+++ src/lib/libc/time/Attic/version.h 2013/09/20 19:06:54 1.2

cvs diff -r1.10 -r1.11 src/lib/libc/time/zdump.8 (expand / switch to unified diff)

--- src/lib/libc/time/zdump.8 2013/07/17 20:13:04 1.10
+++ src/lib/libc/time/zdump.8 2013/09/20 19:06:54 1.11
@@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
1.\" $NetBSD: zdump.8,v 1.10 2013/07/17 20:13:04 christos Exp $ 1.\" $NetBSD: zdump.8,v 1.11 2013/09/20 19:06:54 christos Exp $
2.Dd July 17, 2013 2.Dd September 20, 2013
3.Dt ZDUMP 8 3.Dt ZDUMP 8
4.Os 4.Os
5.Sh NAME 5.Sh NAME
6.Nm zdump 6.Nm zdump
7.Nd time zone dumper 7.Nd time zone dumper
8.Sh SYNOPSIS 8.Sh SYNOPSIS
9.Nm zdump 9.Nm zdump
10.Op Fl \-version 10.Op Fl \-version
11.Op Fl v 11.Op Fl v
12.Op Fl V 12.Op Fl V
13.Op Fl c Ar [loyear,]highyear 13.Op Fl c Ar [loyear,]highyear
14.Op Ar zonename ... 14.Op Ar zonename ...
15.Nm zdump 15.Nm zdump
@@ -46,31 +46,37 @@ Cut off the verbose output near the star @@ -46,31 +46,37 @@ Cut off the verbose output near the star
46By default, 46By default,
47the program cuts off verbose output near the starts of the years \-500 and 2500. 47the program cuts off verbose output near the starts of the years \-500 and 2500.
48.It Fl t Ar [loyear,]highyear 48.It Fl t Ar [loyear,]highyear
49Cut off verbose output at the start of the given time(s), 49Cut off verbose output at the start of the given time(s),
50given in decimal seconds since 1970-01-01 00:00:00 UTC. 50given in decimal seconds since 1970-01-01 00:00:00 UTC.
51.It Fl V 51.It Fl V
52Like 52Like
53.Fl v , 53.Fl v ,
54except omit the times relative to the extreme time values. 54except omit the times relative to the extreme time values.
55This generates output that is easier to compare to that of 55This generates output that is easier to compare to that of
56implementations with different time representations. 56implementations with different time representations.
57.El 57.El
58.Sh LIMITATIONS 58.Sh LIMITATIONS
59The 
60.Fl v 
61and 
62.Fl V 
63options may not be used on systems with floating-point time_t values 
64that are neither float nor double. 
65.Pp 
66Time discontinuities are found by sampling the results returned by localtime 59Time discontinuities are found by sampling the results returned by localtime
67at twelve-hour intervals. 60at twelve-hour intervals.
68This works in all real-world cases; 61This works in all real-world cases;
69one can construct artificial time zones for which this fails. 62one can construct artificial time zones for which this fails.
 63.Pp
 64In the output,
 65.Dq UT
 66denotes the value returned by
 67.Xr gmtime 3 ,
 68which uses UTC for modern time stamps and some other UT flavor for
 69time stamps that predate the introduction of UTC.
 70No attempt is currently made to have the output use
 71.Dq UTC
 72for newer and
 73.Dq UT
 74for older time stamps,
 75partly because the exact date of the introduction of UTC is problematic.
70.Sh SEE ALSO 76.Sh SEE ALSO
71.Xr ctime 3 , 77.Xr ctime 3 ,
72.Xr tzfile 5 , 78.Xr tzfile 5 ,
73.Xr zic 8 79.Xr zic 8
74.\" @(#)zdump.8 8.2 80.\" @(#)zdump.8 8.2
75.\" This file is in the public domain, so clarified as of 81.\" This file is in the public domain, so clarified as of
76.\" 2009-05-17 by Arthur David Olson. 82.\" 2009-05-17 by Arthur David Olson.

cvs diff -r1.30 -r1.31 src/lib/libc/time/zdump.c (expand / switch to unified diff)

--- src/lib/libc/time/zdump.c 2013/07/17 23:09:26 1.30
+++ src/lib/libc/time/zdump.c 2013/09/20 19:06:54 1.31
@@ -1,43 +1,42 @@ @@ -1,43 +1,42 @@
1/* $NetBSD: zdump.c,v 1.30 2013/07/17 23:09:26 christos Exp $ */ 1/* $NetBSD: zdump.c,v 1.31 2013/09/20 19:06:54 christos Exp $ */
2/* 2/*
3** This file is in the public domain, so clarified as of 3** This file is in the public domain, so clarified as of
4** 2009-05-17 by Arthur David Olson. 4** 2009-05-17 by Arthur David Olson.
5*/ 5*/
6 6
7#include <sys/cdefs.h> 7#include <sys/cdefs.h>
8#ifndef lint 8#ifndef lint
9__RCSID("$NetBSD: zdump.c,v 1.30 2013/07/17 23:09:26 christos Exp $"); 9__RCSID("$NetBSD: zdump.c,v 1.31 2013/09/20 19:06:54 christos Exp $");
10#endif /* !defined lint */ 10#endif /* !defined lint */
11 11
12#include "version.h" 12#include "version.h"
13/* 13/*
14** This code has been made independent of the rest of the time 14** This code has been made independent of the rest of the time
15** conversion package to increase confidence in the verification it provides. 15** conversion package to increase confidence in the verification it provides.
16** You can use this code to help in verifying other implementations. 16** You can use this code to help in verifying other implementations.
17** 17**
18** However, include private.h when debugging, so that it overrides 18** However, include private.h when debugging, so that it overrides
19** time_t consistently with the rest of the package. 19** time_t consistently with the rest of the package.
20*/ 20*/
21 21
22#include "private.h" 22#include "private.h"
23 23
24#include "stdio.h" /* for stdout, stderr */ 24#include "stdio.h" /* for stdout, stderr */
25#include "string.h" /* for strcpy */ 25#include "string.h" /* for strcpy */
26#include "sys/types.h" /* for time_t */ 26#include "sys/types.h" /* for time_t */
27#include "time.h" /* for struct tm */ 27#include "time.h" /* for struct tm */
28#include "stdlib.h" /* for exit, malloc, atoi */ 28#include "stdlib.h" /* for exit, malloc, atoi */
29#include <err.h> 29#include <err.h>
30#include "float.h" /* for FLT_MAX and DBL_MAX */ 
31#include "ctype.h" /* for isalpha et al. */ 30#include "ctype.h" /* for isalpha et al. */
32#ifndef isascii 31#ifndef isascii
33#define isascii(x) 1 32#define isascii(x) 1
34#endif /* !defined isascii */ 33#endif /* !defined isascii */
35 34
36/* 35/*
37** Substitutes for pre-C99 compilers. 36** Substitutes for pre-C99 compilers.
38** Much of this section of code is stolen from private.h. 37** Much of this section of code is stolen from private.h.
39*/ 38*/
40 39
41#ifndef HAVE_STDINT_H 40#ifndef HAVE_STDINT_H
42# define HAVE_STDINT_H \ 41# define HAVE_STDINT_H \
43 (199901 <= __STDC_VERSION__ || 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) 42 (199901 <= __STDC_VERSION__ || 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
@@ -54,29 +53,35 @@ __RCSID("$NetBSD: zdump.c,v 1.30 2013/07 @@ -54,29 +53,35 @@ __RCSID("$NetBSD: zdump.c,v 1.30 2013/07
54 53
55#ifndef INT_FAST32_MAX 54#ifndef INT_FAST32_MAX
56# if INT_MAX >> 31 == 0 55# if INT_MAX >> 31 == 0
57typedef long int_fast32_t; 56typedef long int_fast32_t;
58# else 57# else
59typedef int int_fast32_t; 58typedef int int_fast32_t;
60# endif 59# endif
61#endif 60#endif
62 61
63#ifndef INTMAX_MAX 62#ifndef INTMAX_MAX
64# if defined LLONG_MAX || defined __LONG_LONG_MAX__ 63# if defined LLONG_MAX || defined __LONG_LONG_MAX__
65typedef long long intmax_t; 64typedef long long intmax_t;
66# define PRIdMAX "lld" 65# define PRIdMAX "lld"
 66# ifdef LLONG_MAX
 67# define INTMAX_MAX LLONG_MAX
 68# else
 69# define INTMAX_MAX __LONG_LONG_MAX__
 70# endif
67# else 71# else
68typedef long intmax_t; 72typedef long intmax_t;
69# define PRIdMAX "ld" 73# define PRIdMAX "ld"
 74# define INTMAX_MAX LONG_MAX
70# endif 75# endif
71#endif 76#endif
72#ifndef SCNdMAX 77#ifndef SCNdMAX
73# define SCNdMAX PRIdMAX 78# define SCNdMAX PRIdMAX
74#endif 79#endif
75 80
76 81
77#ifndef ZDUMP_LO_YEAR 82#ifndef ZDUMP_LO_YEAR
78#define ZDUMP_LO_YEAR (-500) 83#define ZDUMP_LO_YEAR (-500)
79#endif /* !defined ZDUMP_LO_YEAR */ 84#endif /* !defined ZDUMP_LO_YEAR */
80 85
81#ifndef ZDUMP_HI_YEAR 86#ifndef ZDUMP_HI_YEAR
82#define ZDUMP_HI_YEAR 2500 87#define ZDUMP_HI_YEAR 2500
@@ -134,26 +139,37 @@ typedef long intmax_t; @@ -134,26 +139,37 @@ typedef long intmax_t;
134#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) 139#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
135#endif /* !defined isleap */ 140#endif /* !defined isleap */
136 141
137#ifndef isleap_sum 142#ifndef isleap_sum
138/* 143/*
139** See tzfile.h for details on isleap_sum. 144** See tzfile.h for details on isleap_sum.
140*/ 145*/
141#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 146#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
142#endif /* !defined isleap_sum */ 147#endif /* !defined isleap_sum */
143 148
144#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) 149#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
145#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 150#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
146#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 151#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
 152#define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \
 153 + SECSPERLYEAR * (intmax_t) (100 - 3))
 154
 155/*
 156** True if SECSPER400YEARS is known to be representable as an
 157** intmax_t. It's OK that SECSPER400YEARS_FITS can in theory be false
 158** even if SECSPER400YEARS is representable, because when that happens
 159** the code merely runs a bit more slowly, and this slowness doesn't
 160** occur on any practical platform.
 161*/
 162enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
147 163
148#ifndef HAVE_GETTEXT 164#ifndef HAVE_GETTEXT
149#define HAVE_GETTEXT 0 165#define HAVE_GETTEXT 0
150#endif 166#endif
151#if HAVE_GETTEXT 167#if HAVE_GETTEXT
152#include "locale.h" /* for setlocale */ 168#include "locale.h" /* for setlocale */
153#include "libintl.h" 169#include "libintl.h"
154#endif /* HAVE_GETTEXT */ 170#endif /* HAVE_GETTEXT */
155 171
156#ifndef GNUC_or_lint 172#ifndef GNUC_or_lint
157#ifdef lint 173#ifdef lint
158#define GNUC_or_lint 174#define GNUC_or_lint
159#else /* !defined lint */ 175#else /* !defined lint */
@@ -195,77 +211,62 @@ typedef long intmax_t; @@ -195,77 +211,62 @@ typedef long intmax_t;
195 211
196#ifndef TZ_DOMAIN 212#ifndef TZ_DOMAIN
197#define TZ_DOMAIN "tz" 213#define TZ_DOMAIN "tz"
198#endif /* !defined TZ_DOMAIN */ 214#endif /* !defined TZ_DOMAIN */
199 215
200extern char ** environ; 216extern char ** environ;
201extern int getopt(int argc, char * const argv[], 217extern int getopt(int argc, char * const argv[],
202 const char * options); 218 const char * options);
203extern char * optarg; 219extern char * optarg;
204extern int optind; 220extern int optind;
205 221
206/* The minimum and maximum finite time values. */ 222/* The minimum and maximum finite time values. */
207static time_t absolute_min_time = 223static time_t absolute_min_time =
208 ((time_t) 0.5 == 0.5 224 ((time_t) -1 < 0
209 ? (sizeof (time_t) == sizeof (float) ? (time_t) -FLT_MAX 
210 : sizeof (time_t) == sizeof (double) ? (time_t) -DBL_MAX 
211 : sizeof (time_t) == sizeof (long double) ? (time_t) -LDBL_MAX 
212 : 0) 
213#ifndef TIME_T_FLOATING 
214 : (time_t) -1 < 0 
215 ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) 225 ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
216#endif 
217 : 0); 226 : 0);
218static time_t absolute_max_time = 227static time_t absolute_max_time =
219 ((time_t) 0.5 == 0.5 228 ((time_t) -1 < 0
220 ? (sizeof (time_t) == sizeof (float) ? (time_t) FLT_MAX 229 ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
221 : sizeof (time_t) == sizeof (double) ? (time_t) DBL_MAX 
222 : sizeof (time_t) == sizeof (long double) ? (time_t) LDBL_MAX 
223 : -1) 
224#ifndef TIME_T_FLOATING 
225 : (time_t) -1 < 0 
226 ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)) 
227#endif 
228 : -1); 230 : -1);
229static size_t longest; 231static size_t longest;
230static char * progname; 232static char * progname;
231static int warned; 233static int warned;
232 234
233static const char * abbr(struct tm * tmp); 235static const char * abbr(struct tm * tmp);
234static void abbrok(const char * abbrp, const char * zone); 236static void abbrok(const char * abbrp, const char * zone);
235static intmax_t delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE; 237static intmax_t delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE;
236static void dumptime(const struct tm * tmp); 238static void dumptime(const struct tm * tmp);
237static time_t hunt(char * name, time_t lot, time_t hit); 239static time_t hunt(char * name, time_t lot, time_t hit);
238static void checkabsolutes(void); 
239static void show(char * zone, time_t t, int v); 240static void show(char * zone, time_t t, int v);
240static const char * tformat(void); 241static const char * tformat(void);
241static time_t yeartot(long y) ATTRIBUTE_PURE; 242static time_t yeartot(long y) ATTRIBUTE_PURE;
242 243
243#ifndef TYPECHECK 244#ifndef TYPECHECK
244#define my_localtime localtime 245#define my_localtime localtime
245#else /* !defined TYPECHECK */ 246#else /* !defined TYPECHECK */
246static struct tm * 247static struct tm *
247my_localtime(time_t *tp) 248my_localtime(time_t *tp)
248{ 249{
249 struct tm *tmp; 250 struct tm *tmp;
250 251
251 tmp = localtime(tp); 252 tmp = localtime(tp);
252 if (tp != NULL && tmp != NULL) { 253 if (tp != NULL && tmp != NULL) {
253 struct tm tm; 254 struct tm tm;
254 time_t t; 255 time_t t;
255 256
256 tm = *tmp; 257 tm = *tmp;
257 t = mktime(&tm); 258 t = mktime(&tm);
258 if (t - *tp >= 1 || *tp - t >= 1) { 259 if (t != *tp) {
259 (void) fflush(stdout); 260 (void) fflush(stdout);
260 (void) fprintf(stderr, "\n%s: ", progname); 261 (void) fprintf(stderr, "\n%s: ", progname);
261 (void) fprintf(stderr, tformat(), *tp); 262 (void) fprintf(stderr, tformat(), *tp);
262 (void) fprintf(stderr, " ->"); 263 (void) fprintf(stderr, " ->");
263 (void) fprintf(stderr, " year=%d", tmp->tm_year); 264 (void) fprintf(stderr, " year=%d", tmp->tm_year);
264 (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 265 (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
265 (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 266 (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
266 (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 267 (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
267 (void) fprintf(stderr, " min=%d", tmp->tm_min); 268 (void) fprintf(stderr, " min=%d", tmp->tm_min);
268 (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 269 (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
269 (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 270 (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
270 (void) fprintf(stderr, " -> "); 271 (void) fprintf(stderr, " -> ");
271 (void) fprintf(stderr, tformat(), t); 272 (void) fprintf(stderr, tformat(), t);
@@ -385,27 +386,26 @@ main(int argc, char *argv[]) @@ -385,27 +386,26 @@ main(int argc, char *argv[])
385 if (cutarg != NULL) { 386 if (cutarg != NULL) {
386 if (sscanf(cutarg, "%"SCNdMAX"%c", &hi, &dummy) == 1) { 387 if (sscanf(cutarg, "%"SCNdMAX"%c", &hi, &dummy) == 1) {
387 cuthiyear = hi; 388 cuthiyear = hi;
388 } else if (sscanf(cutarg, "%"SCNdMAX",%"SCNdMAX"%c", 389 } else if (sscanf(cutarg, "%"SCNdMAX",%"SCNdMAX"%c",
389 &lo, &hi, &dummy) == 2) { 390 &lo, &hi, &dummy) == 2) {
390 cutloyear = lo; 391 cutloyear = lo;
391 cuthiyear = hi; 392 cuthiyear = hi;
392 } else { 393 } else {
393(void) fprintf(stderr, _("%s: wild -c argument %s\n"), 394(void) fprintf(stderr, _("%s: wild -c argument %s\n"),
394 progname, cutarg); 395 progname, cutarg);
395 exit(EXIT_FAILURE); 396 exit(EXIT_FAILURE);
396 } 397 }
397 } 398 }
398 checkabsolutes(); 
399 if (cutarg != NULL || cuttimes == NULL) { 399 if (cutarg != NULL || cuttimes == NULL) {
400 cutlotime = yeartot(cutloyear); 400 cutlotime = yeartot(cutloyear);
401 cuthitime = yeartot(cuthiyear); 401 cuthitime = yeartot(cuthiyear);
402 } 402 }
403 if (cuttimes != NULL) { 403 if (cuttimes != NULL) {
404 if (sscanf(cuttimes, "%"SCNdMAX"%c", &hi, &dummy) == 1) { 404 if (sscanf(cuttimes, "%"SCNdMAX"%c", &hi, &dummy) == 1) {
405 if (hi < cuthitime) { 405 if (hi < cuthitime) {
406 if (hi < absolute_min_time) 406 if (hi < absolute_min_time)
407 hi = absolute_min_time; 407 hi = absolute_min_time;
408 cuthitime = hi; 408 cuthitime = hi;
409 } 409 }
410 } else if (sscanf(cuttimes, "%"SCNdMAX",%"SCNdMAX"%c", 410 } else if (sscanf(cuttimes, "%"SCNdMAX",%"SCNdMAX"%c",
411 &lo, &hi, &dummy) == 2) { 411 &lo, &hi, &dummy) == 2) {
@@ -454,114 +454,117 @@ main(int argc, char *argv[]) @@ -454,114 +454,117 @@ main(int argc, char *argv[])
454 } 454 }
455 for (i = optind; i < argc; ++i) { 455 for (i = optind; i < argc; ++i) {
456 static char buf[MAX_STRING_LENGTH]; 456 static char buf[MAX_STRING_LENGTH];
457 457
458 (void) strcpy(&fakeenv[0][3], argv[i]); /* XXX strcpy is safe */ 458 (void) strcpy(&fakeenv[0][3], argv[i]); /* XXX strcpy is safe */
459 if (! (vflag | Vflag)) { 459 if (! (vflag | Vflag)) {
460 show(argv[i], now, FALSE); 460 show(argv[i], now, FALSE);
461 continue; 461 continue;
462 } 462 }
463 warned = FALSE; 463 warned = FALSE;
464 t = absolute_min_time; 464 t = absolute_min_time;
465 if (!Vflag) { 465 if (!Vflag) {
466 show(argv[i], t, TRUE); 466 show(argv[i], t, TRUE);
467 t += SECSPERHOUR * HOURSPERDAY; 467 t += SECSPERDAY;
468 show(argv[i], t, TRUE); 468 show(argv[i], t, TRUE);
469 } 469 }
470 if (t < cutlotime) 470 if (t < cutlotime)
471 t = cutlotime; 471 t = cutlotime;
472 tmp = my_localtime(&t); 472 tmp = my_localtime(&t);
473 if (tmp != NULL) { 473 if (tmp != NULL) {
474 tm = *tmp; 474 tm = *tmp;
475 (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); 475 (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
476 } 476 }
477 for ( ; ; ) { 477 for ( ; ; ) {
478 if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) 478 newt = (t < absolute_max_time - SECSPERDAY / 2
 479 ? t + SECSPERDAY / 2
 480 : absolute_max_time);
 481 if (cuthitime <= newt)
479 break; 482 break;
480 newt = t + SECSPERHOUR * 12; 
481 newtmp = localtime(&newt); 483 newtmp = localtime(&newt);
482 if (newtmp != NULL) 484 if (newtmp != NULL)
483 newtm = *newtmp; 485 newtm = *newtmp;
484 if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 486 if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
485 (delta(&newtm, &tm) != (newt - t) || 487 (delta(&newtm, &tm) != (newt - t) ||
486 newtm.tm_isdst != tm.tm_isdst || 488 newtm.tm_isdst != tm.tm_isdst ||
487 strcmp(abbr(&newtm), buf) != 0)) { 489 strcmp(abbr(&newtm), buf) != 0)) {
488 newt = hunt(argv[i], t, newt); 490 newt = hunt(argv[i], t, newt);
489 newtmp = localtime(&newt); 491 newtmp = localtime(&newt);
490 if (newtmp != NULL) { 492 if (newtmp != NULL) {
491 newtm = *newtmp; 493 newtm = *newtmp;
492 (void) strncpy(buf, 494 (void) strncpy(buf,
493 abbr(&newtm), 495 abbr(&newtm),
494 (sizeof buf) - 1); 496 (sizeof buf) - 1);
495 } 497 }
496 } 498 }
497 t = newt; 499 t = newt;
498 tm = newtm; 500 tm = newtm;
499 tmp = newtmp; 501 tmp = newtmp;
500 } 502 }
501 if (!Vflag) { 503 if (!Vflag) {
502 t = absolute_max_time; 504 t = absolute_max_time;
503 t -= SECSPERHOUR * HOURSPERDAY; 505 t -= SECSPERDAY;
504 show(argv[i], t, TRUE); 506 show(argv[i], t, TRUE);
505 t += SECSPERHOUR * HOURSPERDAY; 507 t += SECSPERDAY;
506 show(argv[i], t, TRUE); 508 show(argv[i], t, TRUE);
507 } 509 }
508 } 510 }
509 if (fflush(stdout) || ferror(stdout)) { 511 if (fflush(stdout) || ferror(stdout)) {
510 err(EXIT_FAILURE, _("Error writing standard output")); 512 err(EXIT_FAILURE, _("Error writing standard output"));
511 } 513 }
512 exit(EXIT_SUCCESS); 514 exit(EXIT_SUCCESS);
513 /* If exit fails to exit... */ 515 /* If exit fails to exit... */
514 return EXIT_FAILURE; 516 return EXIT_FAILURE;
515} 517}
516 518
517static void 
518checkabsolutes(void) 
519{ 
520 if (absolute_max_time < absolute_min_time) { 
521 (void) fprintf(stderr, 
522_("%s: use of -v on system with floating time_t other than float or double\n"), 
523 progname); 
524 exit(EXIT_FAILURE); 
525 } 
526} 
527 
528static time_t 519static time_t
529yeartot(const long y) 520yeartot(const long y)
530{ 521{
531 intmax_t myy; 522 intmax_t myy, seconds, years;
532 int_fast32_t seconds; 
533 time_t t; 523 time_t t;
534 524
535 myy = EPOCH_YEAR; 525 myy = EPOCH_YEAR;
536 t = 0; 526 t = 0;
537 while (myy != y) { 527 while (myy < y) {
538 if (myy < y) { 528 if (SECSPER400YEARS_FITS && 400 <= y - myy) {
 529 intmax_t diff400 = (y - myy) / 400;
 530 if (INTMAX_MAX / SECSPER400YEARS < diff400)
 531 return absolute_max_time;
 532 seconds = diff400 * SECSPER400YEARS;
 533 years = diff400 * 400;
 534 } else {
539 seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 535 seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
540 ++myy; 536 years = 1;
541 if (t > absolute_max_time - seconds) { 537 }
542 t = absolute_max_time; 538 myy += years;
543 break; 539 if (t > absolute_max_time - seconds)
544 } 540 return absolute_max_time;
545 t += seconds; 541 t += seconds;
 542 }
 543 while (y < myy) {
 544 if (SECSPER400YEARS_FITS && y + 400 <= myy && myy < 0) {
 545 intmax_t diff400 = (myy - y) / 400;
 546 if (INTMAX_MAX / SECSPER400YEARS < diff400)
 547 return absolute_min_time;
 548 seconds = diff400 * SECSPER400YEARS;
 549 years = diff400 * 400;
546 } else { 550 } else {
547 --myy; 551 seconds = isleap(myy - 1) ? SECSPERLYEAR : SECSPERNYEAR;
548 seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 552 years = 1;
549 if (t < absolute_min_time + seconds) { 
550 t = absolute_min_time; 
551 break; 
552 } 
553 t -= seconds; 
554 } 553 }
 554 myy -= years;
 555 if (t < absolute_min_time + seconds)
 556 return absolute_min_time;
 557 t -= seconds;
555 } 558 }
556 return t; 559 return t;
557} 560}
558 561
559static time_t 562static time_t
560hunt(char *name, time_t lot, time_t hit) 563hunt(char *name, time_t lot, time_t hit)
561{ 564{
562 time_t t; 565 time_t t;
563 struct tm lotm; 566 struct tm lotm;
564 struct tm * lotmp; 567 struct tm * lotmp;
565 struct tm tm; 568 struct tm tm;
566 struct tm * tmp; 569 struct tm * tmp;
567 char loab[MAX_STRING_LENGTH]; 570 char loab[MAX_STRING_LENGTH];
@@ -625,27 +628,27 @@ delta(struct tm *newp, struct tm *oldp) @@ -625,27 +628,27 @@ delta(struct tm *newp, struct tm *oldp)
625 628
626static void 629static void
627show(char *zone, time_t t, int v) 630show(char *zone, time_t t, int v)
628{ 631{
629 struct tm * tmp; 632 struct tm * tmp;
630 633
631 (void) printf("%-*s ", (int) longest, zone); 634 (void) printf("%-*s ", (int) longest, zone);
632 if (v) { 635 if (v) {
633 tmp = gmtime(&t); 636 tmp = gmtime(&t);
634 if (tmp == NULL) { 637 if (tmp == NULL) {
635 (void) printf(tformat(), t); 638 (void) printf(tformat(), t);
636 } else { 639 } else {
637 dumptime(tmp); 640 dumptime(tmp);
638 (void) printf(" UTC"); 641 (void) printf(" UT");
639 } 642 }
640 (void) printf(" = "); 643 (void) printf(" = ");
641 } 644 }
642 tmp = my_localtime(&t); 645 tmp = my_localtime(&t);
643 dumptime(tmp); 646 dumptime(tmp);
644 if (tmp != NULL) { 647 if (tmp != NULL) {
645 if (*abbr(tmp) != '\0') 648 if (*abbr(tmp) != '\0')
646 (void) printf(" %s", abbr(tmp)); 649 (void) printf(" %s", abbr(tmp));
647 if (v) { 650 if (v) {
648 (void) printf(" isdst=%d", tmp->tm_isdst); 651 (void) printf(" isdst=%d", tmp->tm_isdst);
649#ifdef TM_GMTOFF 652#ifdef TM_GMTOFF
650 (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 653 (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
651#endif /* defined TM_GMTOFF */ 654#endif /* defined TM_GMTOFF */
@@ -666,31 +669,26 @@ abbr(struct tm *tmp) @@ -666,31 +669,26 @@ abbr(struct tm *tmp)
666 return &nada; 669 return &nada;
667 result = tzname[tmp->tm_isdst]; 670 result = tzname[tmp->tm_isdst];
668 return (result == NULL) ? &nada : result; 671 return (result == NULL) ? &nada : result;
669} 672}
670 673
671/* 674/*
672** The code below can fail on certain theoretical systems; 675** The code below can fail on certain theoretical systems;
673** it works on all known real-world systems as of 2004-12-30. 676** it works on all known real-world systems as of 2004-12-30.
674*/ 677*/
675 678
676static const char * 679static const char *
677tformat(void) 680tformat(void)
678{ 681{
679 if (0.5 == (time_t) 0.5) { /* floating */ 
680 if (sizeof (time_t) > sizeof (double)) 
681 return "%Lg"; 
682 return "%g"; 
683 } 
684 if (0 > (time_t) -1) { /* signed */ 682 if (0 > (time_t) -1) { /* signed */
685 if (sizeof (time_t) == sizeof (intmax_t)) 683 if (sizeof (time_t) == sizeof (intmax_t))
686 return "%"PRIdMAX; 684 return "%"PRIdMAX;
687 if (sizeof (time_t) > sizeof (long)) 685 if (sizeof (time_t) > sizeof (long))
688 return "%lld"; 686 return "%lld";
689 if (sizeof (time_t) > sizeof (int)) 687 if (sizeof (time_t) > sizeof (int))
690 return "%ld"; 688 return "%ld";
691 return "%d"; 689 return "%d";
692 } 690 }
693#ifdef PRIuMAX 691#ifdef PRIuMAX
694 if (sizeof (time_t) == sizeof (uintmax_t)) 692 if (sizeof (time_t) == sizeof (uintmax_t))
695 return "%"PRIuMAX; 693 return "%"PRIuMAX;
696#endif 694#endif

cvs diff -r1.20 -r1.21 src/lib/libc/time/zic.8 (expand / switch to unified diff)

--- src/lib/libc/time/zic.8 2012/08/09 12:38:26 1.20
+++ src/lib/libc/time/zic.8 2013/09/20 19:06:54 1.21
@@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
1.\" $NetBSD: zic.8,v 1.20 2012/08/09 12:38:26 christos Exp $ 1.\" $NetBSD: zic.8,v 1.21 2013/09/20 19:06:54 christos Exp $
2.Dd December 20, 2003 2.Dd September 20, 2013
3.Dt ZIC 8 3.Dt ZIC 8
4.Os 4.Os
5.Sh NAME 5.Sh NAME
6.Nm zic 6.Nm zic
7.Nd time zone compiler 7.Nd time zone compiler
8.Sh SYNOPSIS 8.Sh SYNOPSIS
9.Nm 9.Nm
10.Op Fl \-version 10.Op Fl \-version
11.Op Fl d Ar directory 11.Op Fl d Ar directory
12.Op Fl L Ar leapsecondfilename 12.Op Fl L Ar leapsecondfilename
13.Op Fl l Ar localtime 13.Op Fl l Ar localtime
14.Op Fl p Ar posixrules 14.Op Fl p Ar posixrules
15.Op Fl s 15.Op Fl s
@@ -43,42 +43,63 @@ Use the given time zone as local time. @@ -43,42 +43,63 @@ Use the given time zone as local time.
43will act as if the input contained a link line of the form 43will act as if the input contained a link line of the form
44.Dl Link timezone localtime 44.Dl Link timezone localtime
45.It Fl p Ar timezone 45.It Fl p Ar timezone
46Use the given time zone's rules when handling POSIX-format 46Use the given time zone's rules when handling POSIX-format
47time zone environment variables. 47time zone environment variables.
48.Nm 48.Nm
49will act as if the input contained a link line of the form 49will act as if the input contained a link line of the form
50.Dl Link timezone posixrules 50.Dl Link timezone posixrules
51.It Fl s 51.It Fl s
52Limit time values stored in output files to values that are the same 52Limit time values stored in output files to values that are the same
53whether they're taken to be signed or unsigned. 53whether they're taken to be signed or unsigned.
54You can use this option to generate SVVS-compatible files. 54You can use this option to generate SVVS-compatible files.
55.It Fl v 55.It Fl v
56Complain if a year that appears in a data file is outside the range 56Be more verbose, and complain about the following situations:
57of years representable by 57.Bl -dash
58.Xr time 3 58.It The input data specifies a link to a link.
59values. 59.It A year that appears in a data file is outside the range
60Also complain if a time of 24:00 60.It A time of 24:00 or more appears in the input.
61.Pq which cannot be handled by pre-1998 versions of Nm 61Pre-1998 versions of
62appears in the input. 62.Xr zic 8
 63prohibit 24:00, and pre-2007 versions prohibit times greater than 24:00.
 64.It A rule goes past the start or end of the month.
 65Pre-2004 versions of
 66.Xr zic 8
 67prohibit this.
 68.It The output file does not contain all the information about the
 69long-term future of a zone, because the future cannot be summarized as
 70an extended POSIX TZ string.
 71For example, as of 2013 this problem
 72occurs for Iran's daylight-saving rules for the predicted future, as
 73these rules are based on the Iranian calendar, which cannot be
 74represented.
 75.It The output contains data that may not be handled properly by client
 76code designed for older
 77.Xr zic 8
 78output formats.
 79These compatibility issues affect only time stamps
 80before 1970 or after the start of 2038.
 81.It A time zone abbreviation has fewer than 3 characters.
 82POSIX requires at least 3.
 83.El
63.It Fl y Ar command 84.It Fl y Ar command
64Use the given 85Use the given
65.Ar command 86.Ar command
66rather than 87rather than
67.Em yearistype 88.Em yearistype
68when checking year types (see below). 89when checking year types (see below).
69.Pp 90.Pp
70Input lines are made up of fields. 91Input lines are made up of fields.
71Fields are separated from one another by any number of white space characters. 92Fields are separated from one another by one or more white space characters.
72Leading and trailing white space on input lines is ignored. 93Leading and trailing white space on input lines is ignored.
73An unquoted sharp character (#) in the input introduces a comment which extends 94An unquoted sharp character (#) in the input introduces a comment which extends
74to the end of the line the sharp character appears on. 95to the end of the line the sharp character appears on.
75White space characters and sharp characters may be enclosed in double 96White space characters and sharp characters may be enclosed in double
76quotes 97quotes
77.Pq \&" 98.Pq \&"
78.\" XXX " 99.\" XXX "
79if they're to be used as part of a field. 100if they're to be used as part of a field.
80Any line that is blank (after comment stripping) is ignored. 101Any line that is blank (after comment stripping) is ignored.
81Non-blank lines are expected to be of one of three types: 102Non-blank lines are expected to be of one of three types:
82rule lines, zone lines, and link lines. 103rule lines, zone lines, and link lines.
83.Pp 104.Pp
84Names (such as month names) must be in English and are case insensitive. 105Names (such as month names) must be in English and are case insensitive.
@@ -225,55 +246,55 @@ the variable part is null. @@ -225,55 +246,55 @@ the variable part is null.
225.Pp 246.Pp
226A zone line has the form 247A zone line has the form
227.sp 248.sp
228.Dl Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]] 249.Dl Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]]
229For example: 250For example:
230.Dl Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00 251.Dl Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
231The fields that make up a zone line are: 252The fields that make up a zone line are:
232.Bl -tag -width "RULES/SAVE" -compact 253.Bl -tag -width "RULES/SAVE" -compact
233.It NAME 254.It NAME
234The name of the time zone. 255The name of the time zone.
235This is the name used in creating the time conversion information file for the 256This is the name used in creating the time conversion information file for the
236zone. 257zone.
237.It GMTOFF 258.It GMTOFF
238The amount of time to add to UTC to get standard time in this zone. 259The amount of time to add to UT to get standard time in this zone.
239This field has the same format as the 260This field has the same format as the
240.Em AT 261.Em AT
241and 262and
242.Em SAVE 263.Em SAVE
243fields of rule lines; 264fields of rule lines;
244begin the field with a minus sign if time must be subtracted from UTC. 265begin the field with a minus sign if time must be subtracted from UT.
245.It RULES/SAVE 266.It RULES/SAVE
246The name of the rule(s) that apply in the time zone or, 267The name of the rule(s) that apply in the time zone or,
247alternatively, an amount of time to add to local standard time. 268alternatively, an amount of time to add to local standard time.
248If this field is 269If this field is
249.Em \&- 270.Em \&-
250then standard time always applies in the time zone. 271then standard time always applies in the time zone.
251.It FORMAT 272.It FORMAT
252The format for time zone abbreviations in this time zone. 273The format for time zone abbreviations in this time zone.
253The pair of characters 274The pair of characters
254.Em %s 275.Em %s
255is used to show where the 276is used to show where the
256.Dq variable part 277.Dq variable part
257of the time zone abbreviation goes. 278of the time zone abbreviation goes.
258Alternatively, 279Alternatively,
259a slash 280a slash
260.Pq \&/ 281.Pq \&/
261separates standard and daylight abbreviations. 282separates standard and daylight abbreviations.
262.It UNTILYEAR [MONTH [DAY [TIME]]] 283.It UNTILYEAR [MONTH [DAY [TIME]]]
263The time at which the UTC offset or the rule(s) change for a location. 284The time at which the UT offset or the rule(s) change for a location.
264It is specified as a year, a month, a day, and a time of day. 285It is specified as a year, a month, a day, and a time of day.
265If this is specified, 286If this is specified,
266the time zone information is generated from the given UTC offset 287the time zone information is generated from the given UT offset
267and rule change until the time specified. 288and rule change until the time specified.
268The month, day, and time of day have the same format as the IN, ON, and AT 289The month, day, and time of day have the same format as the IN, ON, and AT
269fields of a rule; trailing fields can be omitted, and default to the 290fields of a rule; trailing fields can be omitted, and default to the
270earliest possible value for the missing fields. 291earliest possible value for the missing fields.
271.El 292.El
272The next line must be a 293The next line must be a
273.Dq continuation 294.Dq continuation
274line; this has the same form as a zone line except that the 295line; this has the same form as a zone line except that the
275string 296string
276.Dq Zone 297.Dq Zone
277and the name are omitted, as the continuation line will 298and the name are omitted, as the continuation line will
278place information starting at the time specified as the 299place information starting at the time specified as the
279.Em until 300.Em until
@@ -288,26 +309,29 @@ A link line has the form @@ -288,26 +309,29 @@ A link line has the form
288For example: 309For example:
289.Dl Link Europe/Istanbul Asia/Istanbul 310.Dl Link Europe/Istanbul Asia/Istanbul
290The 311The
291.Em LINK-FROM 312.Em LINK-FROM
292field should appear as the 313field should appear as the
293.Em NAME 314.Em NAME
294field in some zone line; 315field in some zone line;
295the 316the
296.Em LINK-TO 317.Em LINK-TO
297field is used as an alternative name for that zone. 318field is used as an alternative name for that zone.
298.Pp 319.Pp
299Except for continuation lines, 320Except for continuation lines,
300lines may appear in any order in the input. 321lines may appear in any order in the input.
 322However, the behavior is unspecified if multiple zone or link lines
 323define the same name, or if the source of one link line is the target
 324of another.
301.Pp 325.Pp
302Lines in the file that describes leap seconds have the following form: 326Lines in the file that describes leap seconds have the following form:
303.Dl Leap YEAR MONTH DAY HH:MM:SS CORR R/S 327.Dl Leap YEAR MONTH DAY HH:MM:SS CORR R/S
304For example: 328For example:
305.Dl Leap 1974 Dec 31 23:59:60 + S 329.Dl Leap 1974 Dec 31 23:59:60 + S
306The 330The
307.Em YEAR , 331.Em YEAR ,
308.Em MONTH , 332.Em MONTH ,
309.Em DAY , 333.Em DAY ,
310and 334and
311.Em HH:MM:SS 335.Em HH:MM:SS
312fields tell when the leap second happened. 336fields tell when the leap second happened.
313The 337The
@@ -338,91 +362,88 @@ should be (an abbreviation of) @@ -338,91 +362,88 @@ should be (an abbreviation of)
338if the leap second time given by the other fields should be interpreted as UTC 362if the leap second time given by the other fields should be interpreted as UTC
339or 363or
340(an abbreviation of) 364(an abbreviation of)
341.Dq Rolling 365.Dq Rolling
342if the leap second time given by the other fields should be interpreted as 366if the leap second time given by the other fields should be interpreted as
343local wall clock time. 367local wall clock time.
344.El 368.El
345.Sh EXTENDED EXAMPLE 369.Sh EXTENDED EXAMPLE
346Here is an extended example of 370Here is an extended example of
347.Ic zic 371.Ic zic
348input, intended to illustrate many of its features. 372input, intended to illustrate many of its features.
349.Bl -column -compact "# Rule" "Swiss" "FROM" "1995" "TYPE" "Oct" "lastSun" "1:00u" "SAVE" "LETTER/S" 373.Bl -column -compact "# Rule" "Swiss" "FROM" "1995" "TYPE" "Oct" "lastSun" "1:00u" "SAVE" "LETTER/S"
350.It # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S 374.It # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
351.It Rule Swiss 1940 only - Nov 2 0:00 1:00 S 375.It Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S
352.It Rule Swiss 1940 only - Dec 31 0:00 0 - 376.It Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 -
353.It Rule Swiss 1941 1942 - May Sun>=1 2:00 1:00 S 
354.It Rule Swiss 1941 1942 - Oct Sun>=1 0:00 0 
355.Pp 377.Pp
356.It Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S 378.It Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S
357.It Rule EU 1977 only - Sep lastSun 1:00u 0 - 379.It Rule EU 1977 only - Sep lastSun 1:00u 0 -
358.It Rule EU 1978 only - Oct 1 1:00u 0 - 380.It Rule EU 1978 only - Oct 1 1:00u 0 -
359.It Rule EU 1979 1995 - Sep lastSun 1:00u 0 - 381.It Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
360.It Rule EU 1981 max - Mar lastSun 1:00u 1:00 S 382.It Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
361.It Rule EU 1996 max - Oct lastSun 1:00u 0 - 383.It Rule EU 1996 max - Oct lastSun 1:00u 0 -
362.El 384.El
363.Pp 385.Pp
364.Bl -column -compact "# Zone" "Europe/Zurich" "0:29:44" "RULES" "FORMAT" "UNTIL" 386.Bl -column -compact "# Zone" "Europe/Zurich" "0:34:08" "RULES/SAVE" "FORMAT" "UNTIL"
365.It # Zone NAME GMTOFF RULES FORMAT UNTIL 387.It # Zone NAME GMTOFF RULES/SAVE FORMAT UNTIL
366.It Zone Europe/Zurich 0:34:08 - LMT 1848 Sep 12 388.It Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16
367.It 0:29:44 - BMT 1894 Jun 389.It 0:29:44 - BMT 1894 Jun
368.It 1:00 Swiss CE%sT 1981 390.It 1:00 Swiss CE%sT 1981
369.It 1:00 EU CE%sT 391.It 1:00 EU CE%sT
370.It Link Europe/Zurich Switzerland 392.It Link Europe/Zurich Switzerland
371.El 393.El
372.Pp 394.Pp
373In this example, the zone is named Europe/Zurich but it has an alias 395In this example, the zone is named Europe/Zurich but it has an alias
374as Switzerland. 396as Switzerland.
375Zurich was 34 minutes and 8 seconds west of GMT until 397This example says that Zurich was 34 minutes and 8
3761848-09-12 at 00:00, when the offset changed to 29 minutes and 44 398seconds west of UT until 1853-07-16 at 00:00, when the legal offset
377seconds. 399was changed to 7\(de\|26\(fm\|22.50\(sd; although this works out to
378After 1894-06-01 at 00:00 Swiss daylight saving rules (defined 4000:29:45.50, the input format cannot represent fractional seconds so it
379with lines beginning with "Rule Swiss") apply, and the GMT offset 401is rounded here.
 402After 1894-06-01 at 00:00 Swiss daylight saving rules
 403(defined with lines beginning with "Rule Swiss") apply, and the UT offset
380became one hour. 404became one hour.
381From 1981 to the present, EU daylight saving rules have 405From 1981 to the present, EU daylight saving rules have
382applied, and the UTC offset has remained at one hour. 406applied, and the UTC offset has remained at one hour.
383.Pp 407.Pp
384In 1940, daylight saving time applied from November 2 at 00:00 to 408In 1941 and 1942, daylight saving time applied from the first Monday
385December 31 at 00:00. 409in May at 01:00 to the first Monday in October at 02:00.
386In 1941 and 1942, daylight saving time applied 
387from the first Sunday in May at 02:00 to the first Sunday in October 
388at 00:00. 
389The pre-1981 EU daylight-saving rules have no effect 410The pre-1981 EU daylight-saving rules have no effect
390here, but are included for completeness. 411here, but are included for completeness.
391Since 1981, daylight 412Since 1981, daylight
392saving has begun on the last Sunday in March at 01:00 UTC. 413saving has begun on the last Sunday in March at 01:00 UTC.
393Until 1995 it ended the last Sunday in September at 01:00 UTC, 414Until 1995 it ended the last Sunday in September at 01:00 UTC,
394but this changed to the last Sunday in October starting in 1996. 415but this changed to the last Sunday in October starting in 1996.
395.Pp 416.Pp
396For purposes of 417For purposes of
397display, "LMT" and "BMT" were initially used, respectively. 418display, "LMT" and "BMT" were initially used, respectively.
398Since 419Since
399Swiss rules and later EU rules were applied, the display name for the 420Swiss rules and later EU rules were applied, the display name for the
400timezone has been CET for standard time and CEST for daylight saving 421timezone has been CET for standard time and CEST for daylight saving
401time. 422time.
402.Sh NOTES 423.Sh NOTES
403For areas with more than two types of local time, 424For areas with more than two types of local time,
404you may need to use local standard time in the 425you may need to use local standard time in the
405.Em AT 426.Em AT
406field of the earliest transition time's rule to ensure that 427field of the earliest transition time's rule to ensure that
407the earliest transition time recorded in the compiled file is correct. 428the earliest transition time recorded in the compiled file is correct.
408.Pp 429.Pp
409If, 430If,
410for a particular zone, 431for a particular zone,
411a clock advance caused by the start of daylight saving 432a clock advance caused by the start of daylight saving
412coincides with and is equal to 433coincides with and is equal to
413a clock retreat caused by a change in UTC offset, 434a clock retreat caused by a change in UT offset,
414.Ic zic 435.Ic zic
415produces a single transition to daylight saving at the new UTC offset 436produces a single transition to daylight saving at the new UT offset
416(without any change in wall clock time). 437(without any change in wall clock time).
417To get separate transitions 438To get separate transitions
418use multiple zone continuation lines 439use multiple zone continuation lines
419specifying transition instants using universal time. 440specifying transition instants using universal time.
420.Sh FILES 441.Sh FILES
421.Pa /usr/share/zoneinfo 442.Pa /usr/share/zoneinfo
422- standard directory used for created files 443- standard directory used for created files
423.Sh SEE ALSO 444.Sh SEE ALSO
424.Xr ctime 3 , 445.Xr ctime 3 ,
425.Xr tzfile 5 , 446.Xr tzfile 5 ,
426.Xr zdump 8 447.Xr zdump 8
427.\" @(#)zic.8 8.6 448.\" @(#)zic.8 8.6
428.\" This file is in the public domain, so clarified as of 449.\" This file is in the public domain, so clarified as of

cvs diff -r1.42 -r1.43 src/lib/libc/time/zic.c (expand / switch to unified diff)

--- src/lib/libc/time/zic.c 2013/08/06 05:48:39 1.42
+++ src/lib/libc/time/zic.c 2013/09/20 19:06:54 1.43
@@ -1,55 +1,57 @@ @@ -1,55 +1,57 @@
1/* $NetBSD: zic.c,v 1.42 2013/08/06 05:48:39 christos Exp $ */ 1/* $NetBSD: zic.c,v 1.43 2013/09/20 19:06:54 christos Exp $ */
2/* 2/*
3** This file is in the public domain, so clarified as of 3** This file is in the public domain, so clarified as of
4** 2006-07-17 by Arthur David Olson. 4** 2006-07-17 by Arthur David Olson.
5*/ 5*/
6 6
7#if HAVE_NBTOOL_CONFIG_H 7#if HAVE_NBTOOL_CONFIG_H
8#include "nbtool_config.h" 8#include "nbtool_config.h"
9#endif 9#endif
10 10
11#include <sys/cdefs.h> 11#include <sys/cdefs.h>
12#ifndef lint 12#ifndef lint
13__RCSID("$NetBSD: zic.c,v 1.42 2013/08/06 05:48:39 christos Exp $"); 13__RCSID("$NetBSD: zic.c,v 1.43 2013/09/20 19:06:54 christos Exp $");
14#endif /* !defined lint */ 14#endif /* !defined lint */
15 15
16#include "version.h" 16#include "version.h"
17#include "private.h" 17#include "private.h"
18#include "locale.h" 18#include "locale.h"
19#include "tzfile.h" 19#include "tzfile.h"
20 20
21#define ZIC_VERSION '2' 21#include <stdarg.h>
 22#include <unistd.h>
 23
 24#define ZIC_VERSION_PRE_2013 '2'
 25#define ZIC_VERSION '3'
22 26
23typedef int_fast64_t zic_t; 27typedef int_fast64_t zic_t;
24#define ZIC_MIN INT_FAST64_MIN 28#define ZIC_MIN INT_FAST64_MIN
25#define ZIC_MAX INT_FAST64_MAX 29#define ZIC_MAX INT_FAST64_MAX
26#define SCNdZIC SCNdFAST64 30#define SCNdZIC SCNdFAST64
27 31
28#ifndef ZIC_MAX_ABBR_LEN_WO_WARN 32#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
29#define ZIC_MAX_ABBR_LEN_WO_WARN 6 33#define ZIC_MAX_ABBR_LEN_WO_WARN 6
30#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 34#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
31 35
32#if HAVE_SYS_STAT_H 36#if HAVE_SYS_STAT_H
33#include "sys/stat.h" 37#include "sys/stat.h"
34#endif 38#endif
35#ifdef S_IRUSR 39#ifdef S_IRUSR
36#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 40#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
37#else 41#else
38#define MKDIR_UMASK 0755 42#define MKDIR_UMASK 0755
39#endif 43#endif
40 44
41#include "unistd.h" 
42 
43/* 45/*
44** On some ancient hosts, predicates like `isspace(C)' are defined 46** On some ancient hosts, predicates like `isspace(C)' are defined
45** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 47** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
46** which says they are defined only if C == ((unsigned char) C) || C == EOF. 48** which says they are defined only if C == ((unsigned char) C) || C == EOF.
47** Neither the C Standard nor Posix require that `isascii' exist. 49** Neither the C Standard nor Posix require that `isascii' exist.
48** For portability, we check both ancient and modern requirements. 50** For portability, we check both ancient and modern requirements.
49** If isascii is not defined, the isascii check succeeds trivially. 51** If isascii is not defined, the isascii check succeeds trivially.
50*/ 52*/
51#include "ctype.h" 53#include "ctype.h"
52#ifndef isascii 54#ifndef isascii
53#define isascii(x) 1 55#define isascii(x) 1
54#endif 56#endif
55 57
@@ -125,27 +127,26 @@ static void associate(void); @@ -125,27 +127,26 @@ static void associate(void);
125static void dolink(const char * fromfield, const char * tofield); 127static void dolink(const char * fromfield, const char * tofield);
126static char ** getfields(char * buf); 128static char ** getfields(char * buf);
127static zic_t gethms(const char * string, const char * errstrng, 129static zic_t gethms(const char * string, const char * errstrng,
128 int signable); 130 int signable);
129static void infile(const char * filename); 131static void infile(const char * filename);
130static void inleap(char ** fields, int nfields); 132static void inleap(char ** fields, int nfields);
131static void inlink(char ** fields, int nfields); 133static void inlink(char ** fields, int nfields);
132static void inrule(char ** fields, int nfields); 134static void inrule(char ** fields, int nfields);
133static int inzcont(char ** fields, int nfields); 135static int inzcont(char ** fields, int nfields);
134static int inzone(char ** fields, int nfields); 136static int inzone(char ** fields, int nfields);
135static int inzsub(char ** fields, int nfields, int iscont); 137static int inzsub(char ** fields, int nfields, int iscont);
136static int itsdir(const char * name); 138static int itsdir(const char * name);
137static int lowerit(int c); 139static int lowerit(int c);
138int main(int, char **); 
139static int mkdirs(char * filename); 140static int mkdirs(char * filename);
140static void newabbr(const char * abbr); 141static void newabbr(const char * abbr);
141static zic_t oadd(zic_t t1, zic_t t2); 142static zic_t oadd(zic_t t1, zic_t t2);
142static void outzone(const struct zone * zp, int ntzones); 143static void outzone(const struct zone * zp, int ntzones);
143static int rcomp(const void * leftp, const void * rightp); 144static int rcomp(const void * leftp, const void * rightp);
144static zic_t rpytime(const struct rule * rp, zic_t wantedy); 145static zic_t rpytime(const struct rule * rp, zic_t wantedy);
145static void rulesub(struct rule * rp, 146static void rulesub(struct rule * rp,
146 const char * loyearp, const char * hiyearp, 147 const char * loyearp, const char * hiyearp,
147 const char * typep, const char * monthp, 148 const char * typep, const char * monthp,
148 const char * dayp, const char * timep); 149 const char * dayp, const char * timep);
149static zic_t tadd(zic_t t1, zic_t t2); 150static zic_t tadd(zic_t t1, zic_t t2);
150static int yearistype(int year, const char * type); 151static int yearistype(int year, const char * type);
151static int atcomp(const void *avp, const void *bvp); 152static int atcomp(const void *avp, const void *bvp);
@@ -395,52 +396,60 @@ eats(const char *const name, const int n @@ -395,52 +396,60 @@ eats(const char *const name, const int n
395{ 396{
396 filename = name; 397 filename = name;
397 linenum = num; 398 linenum = num;
398 rfilename = rname; 399 rfilename = rname;
399 rlinenum = rnum; 400 rlinenum = rnum;
400} 401}
401 402
402static void 403static void
403eat(const char *const name, const int num) 404eat(const char *const name, const int num)
404{ 405{
405 eats(name, num, NULL, -1); 406 eats(name, num, NULL, -1);
406} 407}
407 408
408static void 409static void ATTRIBUTE_FORMAT((printf, 1, 0))
409error(const char *const string) 410verror(const char *const string, va_list args)
410{ 411{
411 /* 412 /*
412 ** Match the format of "cc" to allow sh users to 413 ** Match the format of "cc" to allow sh users to
413 ** zic ... 2>&1 | error -t "*" -v 414 ** zic ... 2>&1 | error -t "*" -v
414 ** on BSD systems. 415 ** on BSD systems.
415 */ 416 */
416 (void) fprintf(stderr, _("\"%s\", line %d: %s"), 417 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
417 filename, linenum, string); 418 vfprintf(stderr, string, args);
418 if (rfilename != NULL) 419 if (rfilename != NULL)
419 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), 420 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
420 rfilename, rlinenum); 421 rfilename, rlinenum);
421 (void) fprintf(stderr, "\n"); 422 (void) fprintf(stderr, "\n");
422 ++errors; 423 ++errors;
423} 424}
424 425
425static void 426static void ATTRIBUTE_FORMAT((printf, 1, 2))
426warning(const char *const string) 427error(const char *const string, ...)
427{ 428{
428 char * cp; 429 va_list args;
429 430 va_start(args, string);
430 cp = ecpyalloc(_("warning: ")); 431 verror(string, args);
431 cp = ecatalloc(cp, string); 432 va_end(args);
432 error(cp); 433}
433 free(cp); 434
 435static void ATTRIBUTE_FORMAT((printf, 1, 2))
 436warning(const char *const string, ...)
 437{
 438 va_list args;
 439 fprintf(stderr, _("warning: "));
 440 va_start(args, string);
 441 verror(string, args);
 442 va_end(args);
434 --errors; 443 --errors;
435} 444}
436 445
437static _Noreturn void 446static _Noreturn void
438usage(FILE *stream, int status) 447usage(FILE *stream, int status)
439{ 448{
440 (void) fprintf(stream, _("%s: usage is %s \ 449 (void) fprintf(stream, _("%s: usage is %s \
441[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\ 450[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
442\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\ 451\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
443\n\ 452\n\
444Report bugs to %s.\n"), 453Report bugs to %s.\n"),
445 progname, progname, REPORT_BUGS_TO); 454 progname, progname, REPORT_BUGS_TO);
446 exit(status); 455 exit(status);
@@ -749,27 +758,27 @@ associate(void) @@ -749,27 +758,27 @@ associate(void)
749 zp = &zones[i]; 758 zp = &zones[i];
750 if (zp->z_nrules == 0) { 759 if (zp->z_nrules == 0) {
751 /* 760 /*
752 ** Maybe we have a local standard time offset. 761 ** Maybe we have a local standard time offset.
753 */ 762 */
754 eat(zp->z_filename, zp->z_linenum); 763 eat(zp->z_filename, zp->z_linenum);
755 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 764 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
756 TRUE); 765 TRUE);
757 /* 766 /*
758 ** Note, though, that if there's no rule, 767 ** Note, though, that if there's no rule,
759 ** a '%s' in the format is a bad thing. 768 ** a '%s' in the format is a bad thing.
760 */ 769 */
761 if (strchr(zp->z_format, '%') != 0) 770 if (strchr(zp->z_format, '%') != 0)
762 error(_("%s in ruleless zone")); 771 error("%s", _("%s in ruleless zone"));
763 } 772 }
764 } 773 }
765 if (errors) 774 if (errors)
766 exit(EXIT_FAILURE); 775 exit(EXIT_FAILURE);
767} 776}
768 777
769static void 778static void
770infile(const char *name) 779infile(const char *name)
771{ 780{
772 FILE * fp; 781 FILE * fp;
773 char ** fields; 782 char ** fields;
774 char * cp; 783 char * cp;
775 const struct lookup * lp; 784 const struct lookup * lp;
@@ -879,33 +888,33 @@ gethms(const char *string, const char *c @@ -879,33 +888,33 @@ gethms(const char *string, const char *c
879 return 0; 888 return 0;
880 if (!signable) 889 if (!signable)
881 sign = 1; 890 sign = 1;
882 else if (*string == '-') { 891 else if (*string == '-') {
883 sign = -1; 892 sign = -1;
884 ++string; 893 ++string;
885 } else sign = 1; 894 } else sign = 1;
886 if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1) 895 if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1)
887 mm = ss = 0; 896 mm = ss = 0;
888 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2) 897 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2)
889 ss = 0; 898 ss = 0;
890 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"), 899 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"),
891 &hh, &mm, &ss) != 3) { 900 &hh, &mm, &ss) != 3) {
892 error(errstring); 901 error("%s", errstring);
893 return 0; 902 return 0;
894 } 903 }
895 if (hh < 0 || 904 if (hh < 0 ||
896 mm < 0 || mm >= MINSPERHOUR || 905 mm < 0 || mm >= MINSPERHOUR ||
897 ss < 0 || ss > SECSPERMIN) { 906 ss < 0 || ss > SECSPERMIN) {
898 error(errstring); 907 error("%s", errstring);
899 return 0; 908 return 0;
900 } 909 }
901 if (ZIC_MAX / SECSPERHOUR < hh) { 910 if (ZIC_MAX / SECSPERHOUR < hh) {
902 error(_("time overflow")); 911 error(_("time overflow"));
903 return 0; 912 return 0;
904 } 913 }
905 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 914 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
906 warning(_("24:00 not handled by pre-1998 versions of zic")); 915 warning(_("24:00 not handled by pre-1998 versions of zic"));
907 if (noise && (hh > HOURSPERDAY || 916 if (noise && (hh > HOURSPERDAY ||
908 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 917 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
909warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 918warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
910 return oadd(sign * hh * SECSPERHOUR, 919 return oadd(sign * hh * SECSPERHOUR,
911 sign * (mm * SECSPERMIN + ss)); 920 sign * (mm * SECSPERMIN + ss));
@@ -931,60 +940,51 @@ inrule(char **const fields, const int nf @@ -931,60 +940,51 @@ inrule(char **const fields, const int nf
931 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 940 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
932 r.r_name = ecpyalloc(fields[RF_NAME]); 941 r.r_name = ecpyalloc(fields[RF_NAME]);
933 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 942 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
934 if (max_abbrvar_len < strlen(r.r_abbrvar)) 943 if (max_abbrvar_len < strlen(r.r_abbrvar))
935 max_abbrvar_len = strlen(r.r_abbrvar); 944 max_abbrvar_len = strlen(r.r_abbrvar);
936 rules = erealloc(rules, (nrules + 1) * sizeof *rules); 945 rules = erealloc(rules, (nrules + 1) * sizeof *rules);
937 rules[nrules++] = r; 946 rules[nrules++] = r;
938} 947}
939 948
940static int 949static int
941inzone(char **const fields, const int nfields) 950inzone(char **const fields, const int nfields)
942{ 951{
943 int i; 952 int i;
944 static char * buf; 
945 953
946 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 954 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
947 error(_("wrong number of fields on Zone line")); 955 error(_("wrong number of fields on Zone line"));
948 return FALSE; 956 return FALSE;
949 } 957 }
950 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 958 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
951 buf = erealloc(buf, 132 + strlen(TZDEFAULT)); 959 error(
952 (void)sprintf(buf, /* XXX: sprintf is safe */ 
953_("\"Zone %s\" line and -l option are mutually exclusive"), 960_("\"Zone %s\" line and -l option are mutually exclusive"),
954 TZDEFAULT); 961 TZDEFAULT);
955 error(buf); 
956 return FALSE; 962 return FALSE;
957 } 963 }
958 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 964 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
959 buf = erealloc(buf, 132 + strlen(TZDEFRULES)); 965 error(
960 (void)sprintf(buf, /* XXX: sprintf is safe */ 
961_("\"Zone %s\" line and -p option are mutually exclusive"), 966_("\"Zone %s\" line and -p option are mutually exclusive"),
962 TZDEFRULES); 967 TZDEFRULES);
963 error(buf); 
964 return FALSE; 968 return FALSE;
965 } 969 }
966 for (i = 0; i < nzones; ++i) 970 for (i = 0; i < nzones; ++i)
967 if (zones[i].z_name != NULL && 971 if (zones[i].z_name != NULL &&
968 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 972 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
969 buf = erealloc(buf, 132 + 973 error(
970 strlen(fields[ZF_NAME]) + 
971 strlen(zones[i].z_filename)); 
972 (void)sprintf(buf, /* XXX: sprintf is safe */ 
973_("duplicate zone name %s (file \"%s\", line %d)"), 974_("duplicate zone name %s (file \"%s\", line %d)"),
974 fields[ZF_NAME], 975 fields[ZF_NAME],
975 zones[i].z_filename, 976 zones[i].z_filename,
976 zones[i].z_linenum); 977 zones[i].z_linenum);
977 error(buf); 
978 return FALSE; 978 return FALSE;
979 } 979 }
980 return inzsub(fields, nfields, FALSE); 980 return inzsub(fields, nfields, FALSE);
981} 981}
982 982
983static int 983static int
984inzcont(char **const fields, const int nfields) 984inzcont(char **const fields, const int nfields)
985{ 985{
986 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 986 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
987 error(_("wrong number of fields on Zone continuation line")); 987 error(_("wrong number of fields on Zone continuation line"));
988 return FALSE; 988 return FALSE;
989 } 989 }
990 return inzsub(fields, nfields, TRUE); 990 return inzsub(fields, nfields, TRUE);
@@ -1011,27 +1011,27 @@ inzsub(char **const fields, const int nf @@ -1011,27 +1011,27 @@ inzsub(char **const fields, const int nf
1011 z.z_name = NULL; 1011 z.z_name = NULL;
1012 } else { 1012 } else {
1013 i_gmtoff = ZF_GMTOFF; 1013 i_gmtoff = ZF_GMTOFF;
1014 i_rule = ZF_RULE; 1014 i_rule = ZF_RULE;
1015 i_format = ZF_FORMAT; 1015 i_format = ZF_FORMAT;
1016 i_untilyear = ZF_TILYEAR; 1016 i_untilyear = ZF_TILYEAR;
1017 i_untilmonth = ZF_TILMONTH; 1017 i_untilmonth = ZF_TILMONTH;
1018 i_untilday = ZF_TILDAY; 1018 i_untilday = ZF_TILDAY;
1019 i_untiltime = ZF_TILTIME; 1019 i_untiltime = ZF_TILTIME;
1020 z.z_name = ecpyalloc(fields[ZF_NAME]); 1020 z.z_name = ecpyalloc(fields[ZF_NAME]);
1021 } 1021 }
1022 z.z_filename = filename; 1022 z.z_filename = filename;
1023 z.z_linenum = linenum; 1023 z.z_linenum = linenum;
1024 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); 1024 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), TRUE);
1025 if ((cp = strchr(fields[i_format], '%')) != 0) { 1025 if ((cp = strchr(fields[i_format], '%')) != 0) {
1026 if (*++cp != 's' || strchr(cp, '%') != 0) { 1026 if (*++cp != 's' || strchr(cp, '%') != 0) {
1027 error(_("invalid abbreviation format")); 1027 error(_("invalid abbreviation format"));
1028 return FALSE; 1028 return FALSE;
1029 } 1029 }
1030 } 1030 }
1031 z.z_rule = ecpyalloc(fields[i_rule]); 1031 z.z_rule = ecpyalloc(fields[i_rule]);
1032 z.z_format = ecpyalloc(fields[i_format]); 1032 z.z_format = ecpyalloc(fields[i_format]);
1033 if (max_format_len < strlen(z.z_format)) 1033 if (max_format_len < strlen(z.z_format))
1034 max_format_len = strlen(z.z_format); 1034 max_format_len = strlen(z.z_format);
1035 hasuntil = nfields > i_untilyear; 1035 hasuntil = nfields > i_untilyear;
1036 if (hasuntil) { 1036 if (hasuntil) {
1037 z.z_untilrule.r_filename = filename; 1037 z.z_untilrule.r_filename = filename;
@@ -1387,27 +1387,27 @@ atcomp(const void *avp, const void *bvp) @@ -1387,27 +1387,27 @@ atcomp(const void *avp, const void *bvp)
1387 const zic_t a = ((const struct attype *) avp)->at; 1387 const zic_t a = ((const struct attype *) avp)->at;
1388 const zic_t b = ((const struct attype *) bvp)->at; 1388 const zic_t b = ((const struct attype *) bvp)->at;
1389 1389
1390 return (a < b) ? -1 : (a > b); 1390 return (a < b) ? -1 : (a > b);
1391} 1391}
1392 1392
1393static int 1393static int
1394is32(const zic_t x) 1394is32(const zic_t x)
1395{ 1395{
1396 return INT32_MIN <= x && x <= INT32_MAX; 1396 return INT32_MIN <= x && x <= INT32_MAX;
1397} 1397}
1398 1398
1399static void 1399static void
1400writezone(const char *const name, const char *const string) 1400writezone(const char *const name, const char *const string, char version)
1401{ 1401{
1402 FILE * fp; 1402 FILE * fp;
1403 int i, j; 1403 int i, j;
1404 int leapcnt32, leapi32; 1404 int leapcnt32, leapi32;
1405 int timecnt32, timei32; 1405 int timecnt32, timei32;
1406 int pass; 1406 int pass;
1407 static char * fullname; 1407 static char * fullname;
1408 static const struct tzhead tzh0; 1408 static const struct tzhead tzh0;
1409 static struct tzhead tzh; 1409 static struct tzhead tzh;
1410 zic_t ats[TZ_MAX_TIMES]; 1410 zic_t ats[TZ_MAX_TIMES];
1411 unsigned char types[TZ_MAX_TIMES]; 1411 unsigned char types[TZ_MAX_TIMES];
1412 1412
1413 /* 1413 /*
@@ -1645,27 +1645,27 @@ writezone(const char *const name, const  @@ -1645,27 +1645,27 @@ writezone(const char *const name, const
1645 if (strcmp(&thischars[j], thisabbr) == 0) 1645 if (strcmp(&thischars[j], thisabbr) == 0)
1646 break; 1646 break;
1647 if (j == thischarcnt) { 1647 if (j == thischarcnt) {
1648 (void) strcpy(&thischars[(int) thischarcnt], 1648 (void) strcpy(&thischars[(int) thischarcnt],
1649 thisabbr); 1649 thisabbr);
1650 thischarcnt += strlen(thisabbr) + 1; 1650 thischarcnt += strlen(thisabbr) + 1;
1651 } 1651 }
1652 indmap[abbrinds[i]] = j; 1652 indmap[abbrinds[i]] = j;
1653 } 1653 }
1654#define DO(field) (void) fwrite(tzh.field, \ 1654#define DO(field) (void) fwrite(tzh.field, \
1655 sizeof tzh.field, (size_t) 1, fp) 1655 sizeof tzh.field, (size_t) 1, fp)
1656 tzh = tzh0; 1656 tzh = tzh0;
1657 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 1657 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1658 tzh.tzh_version[0] = ZIC_VERSION; 1658 tzh.tzh_version[0] = version;
1659 convert(thistypecnt, tzh.tzh_ttisgmtcnt); 1659 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1660 convert(thistypecnt, tzh.tzh_ttisstdcnt); 1660 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1661 convert(thisleapcnt, tzh.tzh_leapcnt); 1661 convert(thisleapcnt, tzh.tzh_leapcnt);
1662 convert(thistimecnt, tzh.tzh_timecnt); 1662 convert(thistimecnt, tzh.tzh_timecnt);
1663 convert(thistypecnt, tzh.tzh_typecnt); 1663 convert(thistypecnt, tzh.tzh_typecnt);
1664 convert(thischarcnt, tzh.tzh_charcnt); 1664 convert(thischarcnt, tzh.tzh_charcnt);
1665 DO(tzh_magic); 1665 DO(tzh_magic);
1666 DO(tzh_version); 1666 DO(tzh_version);
1667 DO(tzh_reserved); 1667 DO(tzh_reserved);
1668 DO(tzh_ttisgmtcnt); 1668 DO(tzh_ttisgmtcnt);
1669 DO(tzh_ttisstdcnt); 1669 DO(tzh_ttisstdcnt);
1670 DO(tzh_leapcnt); 1670 DO(tzh_leapcnt);
1671 DO(tzh_timecnt); 1671 DO(tzh_timecnt);
@@ -1783,196 +1783,261 @@ stringoffset(char *result, zic_t offset) @@ -1783,196 +1783,261 @@ stringoffset(char *result, zic_t offset)
1783 int minutes; 1783 int minutes;
1784 int seconds; 1784 int seconds;
1785 1785
1786 result[0] = '\0'; 1786 result[0] = '\0';
1787 if (offset < 0) { 1787 if (offset < 0) {
1788 (void) strcpy(result, "-"); 1788 (void) strcpy(result, "-");
1789 offset = -offset; 1789 offset = -offset;
1790 } 1790 }
1791 seconds = offset % SECSPERMIN; 1791 seconds = offset % SECSPERMIN;
1792 offset /= SECSPERMIN; 1792 offset /= SECSPERMIN;
1793 minutes = offset % MINSPERHOUR; 1793 minutes = offset % MINSPERHOUR;
1794 offset /= MINSPERHOUR; 1794 offset /= MINSPERHOUR;
1795 hours = offset; 1795 hours = offset;
1796 if (hours > HOURSPERDAY) { 1796 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
1797 result[0] = '\0'; 1797 result[0] = '\0';
1798 return -1; 1798 return -1;
1799 } 1799 }
1800 (void) sprintf(end(result), "%d", hours); 1800 (void) sprintf(end(result), "%d", hours);
1801 if (minutes != 0 || seconds != 0) { 1801 if (minutes != 0 || seconds != 0) {
1802 (void) sprintf(end(result), ":%02d", minutes); 1802 (void) sprintf(end(result), ":%02d", minutes);
1803 if (seconds != 0) 1803 if (seconds != 0)
1804 (void) sprintf(end(result), ":%02d", seconds); 1804 (void) sprintf(end(result), ":%02d", seconds);
1805 } 1805 }
1806 return 0; 1806 return 0;
1807} 1807}
1808 1808
1809static int 1809static int
1810stringrule(char *result, const struct rule *const rp, const zic_t dstoff, 1810stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
1811 const zic_t gmtoff) 1811 const zic_t gmtoff)
1812{ 1812{
1813 zic_t tod; 1813 zic_t tod = rp->r_tod;
 1814 int compat = 0;
1814 1815
1815 result = end(result); 1816 result = end(result);
1816 if (rp->r_dycode == DC_DOM) { 1817 if (rp->r_dycode == DC_DOM) {
1817 int month, total; 1818 int month, total;
1818 1819
1819 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 1820 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1820 return -1; 1821 return -1;
1821 total = 0; 1822 total = 0;
1822 for (month = 0; month < rp->r_month; ++month) 1823 for (month = 0; month < rp->r_month; ++month)
1823 total += len_months[0][month]; 1824 total += len_months[0][month];
1824 (void) sprintf(result, "J%d", total + rp->r_dayofmonth); 1825 /* Omit the "J" in Jan and Feb, as that's shorter. */
 1826 if (rp->r_month <= 1)
 1827 (void) sprintf(result, "%d", total + rp->r_dayofmonth - 1);
 1828 else
 1829 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1825 } else { 1830 } else {
1826 int week; 1831 int week;
 1832 int wday = rp->r_wday;
 1833 int wdayoff;
1827 1834
1828 if (rp->r_dycode == DC_DOWGEQ) { 1835 if (rp->r_dycode == DC_DOWGEQ) {
1829 if ((rp->r_dayofmonth % DAYSPERWEEK) != 1) 1836 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
1830 return -1; 1837 if (wdayoff)
1831 week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1838 compat = 2013;
 1839 wday -= wdayoff;
 1840 tod += wdayoff * SECSPERDAY;
 1841 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
1832 } else if (rp->r_dycode == DC_DOWLEQ) { 1842 } else if (rp->r_dycode == DC_DOWLEQ) {
1833 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 1843 if (rp->r_dayofmonth == len_months[1][rp->r_month])
1834 week = 5; 1844 week = 5;
1835 else { 1845 else {
1836 if ((rp->r_dayofmonth % DAYSPERWEEK) != 0) 1846 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
1837 return -1; 1847 if (wdayoff)
 1848 compat = 2013;
 1849 wday -= wdayoff;
 1850 tod += wdayoff * SECSPERDAY;
1838 week = rp->r_dayofmonth / DAYSPERWEEK; 1851 week = rp->r_dayofmonth / DAYSPERWEEK;
1839 } 1852 }
1840 } else return -1; /* "cannot happen" */ 1853 } else return -1; /* "cannot happen" */
 1854 if (wday < 0)
 1855 wday += DAYSPERWEEK;
1841 (void) sprintf(result, "M%d.%d.%d", 1856 (void) sprintf(result, "M%d.%d.%d",
1842 rp->r_month + 1, week, rp->r_wday); 1857 rp->r_month + 1, week, wday);
1843 } 1858 }
1844 tod = rp->r_tod; 
1845 if (rp->r_todisgmt) 1859 if (rp->r_todisgmt)
1846 tod += gmtoff; 1860 tod += gmtoff;
1847 if (rp->r_todisstd && rp->r_stdoff == 0) 1861 if (rp->r_todisstd && rp->r_stdoff == 0)
1848 tod += dstoff; 1862 tod += dstoff;
1849 if (tod < 0) { 
1850 result[0] = '\0'; 
1851 return -1; 
1852 } 
1853 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 1863 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1854 (void) strcat(result, "/"); 1864 (void) strcat(result, "/");
1855 if (stringoffset(end(result), tod) != 0) 1865 if (stringoffset(end(result), tod) != 0)
1856 return -1; 1866 return -1;
 1867 if (tod < 0) {
 1868 if (compat < 2013)
 1869 compat = 2013;
 1870 } else if (SECSPERDAY <= tod) {
 1871 if (compat < 1994)
 1872 compat = 1994;
 1873 }
1857 } 1874 }
1858 return 0; 1875 return compat;
1859} 1876}
1860 1877
1861static void 1878static int
 1879rule_cmp(struct rule const *a, struct rule const *b)
 1880{
 1881 if (!a)
 1882 return -!!b;
 1883 if (!b)
 1884 return 1;
 1885 if (a->r_hiyear != b->r_hiyear)
 1886 return a->r_hiyear < b->r_hiyear ? -1 : 1;
 1887 if (a->r_month - b->r_month != 0)
 1888 return a->r_month - b->r_month;
 1889 return a->r_dayofmonth - b->r_dayofmonth;
 1890}
 1891
 1892enum { YEAR_BY_YEAR_ZONE = 1 };
 1893
 1894static int
1862stringzone(char *result, const int resultlen, const struct zone *const zpfirst, 1895stringzone(char *result, const int resultlen, const struct zone *const zpfirst,
1863 const int zonecount) 1896 const int zonecount)
1864{ 1897{
1865 const struct zone * zp; 1898 const struct zone * zp;
1866 struct rule * rp; 1899 struct rule * rp;
1867 struct rule * stdrp; 1900 struct rule * stdrp;
1868 struct rule * dstrp; 1901 struct rule * dstrp;
1869 int i; 1902 int i;
1870 const char * abbrvar; 1903 const char * abbrvar;
 1904 int compat = 0;
 1905 int c;
 1906 struct rule stdr, dstr;
1871 1907
1872 result[0] = '\0'; 1908 result[0] = '\0';
1873 zp = zpfirst + zonecount - 1; 1909 zp = zpfirst + zonecount - 1;
1874 stdrp = dstrp = NULL; 1910 stdrp = dstrp = NULL;
1875 for (i = 0; i < zp->z_nrules; ++i) { 1911 for (i = 0; i < zp->z_nrules; ++i) {
1876 rp = &zp->z_rules[i]; 1912 rp = &zp->z_rules[i];
1877 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX) 1913 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
1878 continue; 1914 continue;
1879 if (rp->r_yrtype != NULL) 1915 if (rp->r_yrtype != NULL)
1880 continue; 1916 continue;
1881 if (rp->r_stdoff == 0) { 1917 if (rp->r_stdoff == 0) {
1882 if (stdrp == NULL) 1918 if (stdrp == NULL)
1883 stdrp = rp; 1919 stdrp = rp;
1884 else return; 1920 else return -1;
1885 } else { 1921 } else {
1886 if (dstrp == NULL) 1922 if (dstrp == NULL)
1887 dstrp = rp; 1923 dstrp = rp;
1888 else return; 1924 else return -1;
1889 } 1925 }
1890 } 1926 }
1891 if (stdrp == NULL && dstrp == NULL) { 1927 if (stdrp == NULL && dstrp == NULL) {
1892 /* 1928 /*
1893 ** There are no rules running through "max". 1929 ** There are no rules running through "max".
1894 ** Let's find the latest rule. 1930 ** Find the latest std rule in stdabbrrp
 1931 ** and latest rule of any type in stdrp.
1895 */ 1932 */
 1933 struct rule *stdabbrrp = NULL;
1896 for (i = 0; i < zp->z_nrules; ++i) { 1934 for (i = 0; i < zp->z_nrules; ++i) {
1897 rp = &zp->z_rules[i]; 1935 rp = &zp->z_rules[i];
1898 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || 1936 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
1899 (rp->r_hiyear == stdrp->r_hiyear && 1937 stdabbrrp = rp;
1900 (rp->r_month > stdrp->r_month || 1938 if (rule_cmp(stdrp, rp) < 0)
1901 (rp->r_month == stdrp->r_month && 1939 stdrp = rp;
1902 rp->r_dayofmonth > stdrp->r_dayofmonth)))) 
1903 stdrp = rp; 
1904 } 1940 }
1905 if (stdrp != NULL && stdrp->r_stdoff != 0) 
1906 return; /* We end up in DST (a POSIX no-no). */ 
1907 /* 1941 /*
1908 ** Horrid special case: if year is 2037, 1942 ** Horrid special case: if year is 2037,
1909 ** presume this is a zone handled on a year-by-year basis; 1943 ** presume this is a zone handled on a year-by-year basis;
1910 ** do not try to apply a rule to the zone. 1944 ** do not try to apply a rule to the zone.
1911 */ 1945 */
1912 if (stdrp != NULL && stdrp->r_hiyear == 2037) 1946 if (stdrp != NULL && stdrp->r_hiyear == 2037)
1913 return; 1947 return YEAR_BY_YEAR_ZONE;
 1948
 1949 if (stdrp != NULL && stdrp->r_stdoff != 0) {
 1950 /* Perpetual DST. */
 1951 dstr.r_month = TM_JANUARY;
 1952 dstr.r_dycode = DC_DOM;
 1953 dstr.r_dayofmonth = 1;
 1954 dstr.r_tod = 0;
 1955 dstr.r_todisstd = dstr.r_todisgmt = FALSE;
 1956 dstr.r_stdoff = stdrp->r_stdoff;
 1957 dstr.r_abbrvar = stdrp->r_abbrvar;
 1958 stdr.r_month = TM_DECEMBER;
 1959 stdr.r_dycode = DC_DOM;
 1960 stdr.r_dayofmonth = 31;
 1961 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
 1962 stdr.r_todisstd = stdr.r_todisgmt = FALSE;
 1963 stdr.r_stdoff = 0;
 1964 stdr.r_abbrvar
 1965 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
 1966 dstrp = &dstr;
 1967 stdrp = &stdr;
 1968 }
1914 } 1969 }
1915 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) 1970 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1916 return; 1971 return -1;
1917 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 1972 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1918 doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE); 1973 doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE);
1919 if (stringoffset(end(result), -zp->z_gmtoff) != 0) { 1974 if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1920 result[0] = '\0'; 1975 result[0] = '\0';
1921 return; 1976 return -1;
1922 } 1977 }
1923 if (dstrp == NULL) 1978 if (dstrp == NULL)
1924 return; 1979 return compat;
1925 doabbr(end(result), resultlen - strlen(result), 1980 doabbr(end(result), resultlen - strlen(result),
1926 zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); 1981 zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
1927 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) 1982 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
1928 if (stringoffset(end(result), 1983 if (stringoffset(end(result),
1929 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { 1984 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1930 result[0] = '\0'; 1985 result[0] = '\0';
1931 return; 1986 return -1;
1932 } 1987 }
1933 (void) strcat(result, ","); 1988 (void) strcat(result, ",");
1934 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1989 c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
 1990 if (c < 0) {
1935 result[0] = '\0'; 1991 result[0] = '\0';
1936 return; 1992 return -1;
1937 } 1993 }
 1994 if (compat < c)
 1995 compat = c;
1938 (void) strcat(result, ","); 1996 (void) strcat(result, ",");
1939 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1997 c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
 1998 if (c < 0) {
1940 result[0] = '\0'; 1999 result[0] = '\0';
1941 return; 2000 return -1;
1942 } 2001 }
 2002 if (compat < c)
 2003 compat = c;
 2004 return compat;
1943} 2005}
1944 2006
1945static void 2007static void
1946outzone(const struct zone *const zpfirst, const int zonecount) 2008outzone(const struct zone *const zpfirst, const int zonecount)
1947{ 2009{
1948 const struct zone * zp; 2010 const struct zone * zp;
1949 struct rule * rp; 2011 struct rule * rp;
1950 int i, j; 2012 int i, j;
1951 int usestart, useuntil; 2013 int usestart, useuntil;
1952 zic_t starttime, untiltime; 2014 zic_t starttime, untiltime;
1953 zic_t gmtoff; 2015 zic_t gmtoff;
1954 zic_t stdoff; 2016 zic_t stdoff;
1955 zic_t year; 2017 zic_t year;
1956 zic_t startoff; 2018 zic_t startoff;
1957 int startttisstd; 2019 int startttisstd;
1958 int startttisgmt; 2020 int startttisgmt;
1959 int type; 2021 int type;
1960 char * startbuf; 2022 char * startbuf;
1961 char * ab; 2023 char * ab;
1962 char * envvar; 2024 char * envvar;
1963 size_t max_abbr_len; 2025 size_t max_abbr_len;
1964 size_t max_envvar_len; 2026 size_t max_envvar_len;
1965 int prodstic; /* all rules are min to max */ 2027 int prodstic; /* all rules are min to max */
 2028 int compat;
 2029 int do_extend;
 2030 int version;
1966 2031
1967 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 2032 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
1968 max_envvar_len = 2 * max_abbr_len + 5 * 9; 2033 max_envvar_len = 2 * max_abbr_len + 5 * 9;
1969 startbuf = emalloc(max_abbr_len + 1); 2034 startbuf = emalloc(max_abbr_len + 1);
1970 ab = emalloc(max_abbr_len + 1); 2035 ab = emalloc(max_abbr_len + 1);
1971 envvar = emalloc(max_envvar_len + 1); 2036 envvar = emalloc(max_envvar_len + 1);
1972 INITIALIZE(untiltime); 2037 INITIALIZE(untiltime);
1973 INITIALIZE(starttime); 2038 INITIALIZE(starttime);
1974 /* 2039 /*
1975 ** Now. . .finally. . .generate some useful data! 2040 ** Now. . .finally. . .generate some useful data!
1976 */ 2041 */
1977 timecnt = 0; 2042 timecnt = 0;
1978 typecnt = 0; 2043 typecnt = 0;
@@ -2001,52 +2066,74 @@ outzone(const struct zone *const zpfirst @@ -2001,52 +2066,74 @@ outzone(const struct zone *const zpfirst
2001 for (j = 0; j < zp->z_nrules; ++j) { 2066 for (j = 0; j < zp->z_nrules; ++j) {
2002 rp = &zp->z_rules[j]; 2067 rp = &zp->z_rules[j];
2003 if (rp->r_lowasnum) 2068 if (rp->r_lowasnum)
2004 updateminmax(rp->r_loyear); 2069 updateminmax(rp->r_loyear);
2005 if (rp->r_hiwasnum) 2070 if (rp->r_hiwasnum)
2006 updateminmax(rp->r_hiyear); 2071 updateminmax(rp->r_hiyear);
2007 if (rp->r_lowasnum || rp->r_hiwasnum) 2072 if (rp->r_lowasnum || rp->r_hiwasnum)
2008 prodstic = FALSE; 2073 prodstic = FALSE;
2009 } 2074 }
2010 } 2075 }
2011 /* 2076 /*
2012 ** Generate lots of data if a rule can't cover all future times. 2077 ** Generate lots of data if a rule can't cover all future times.
2013 */ 2078 */
2014 stringzone(envvar, max_envvar_len+1, zpfirst, zonecount); 2079 compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
2015 if (noise && envvar[0] == '\0') { 2080 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2016 char * wp; 2081 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2017 2082 if (noise && compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2018 wp = ecpyalloc(_("no POSIX environment variable for zone")); 2083 if (compat < 0)
2019 wp = ecatalloc(wp, " "); 2084 warning("%s %s",
2020 wp = ecatalloc(wp, zpfirst->z_name); 2085 _("no POSIX environment variable for zone"),
2021 warning(wp); 2086 zpfirst->z_name);
2022 free(wp); 2087 else {
2023 } 2088 /* Circa-COMPAT clients, and earlier clients, might
2024 if (envvar[0] == '\0') { 2089 not work for this zone when given dates before
2025 if (min_year >= ZIC_MIN + YEARSPERREPEAT) 2090 1970 or after 2038. */
2026 min_year -= YEARSPERREPEAT; 2091 warning(_("%s: pre-%d clients may mishandle"
 2092 " distant timestamps"),
 2093 zpfirst->z_name, compat);
 2094 }
 2095 }
 2096 if (do_extend) {
 2097 /*
 2098 ** Search through a couple of extra years past the obvious
 2099 ** 400, to avoid edge cases. For example, suppose a non-POSIX
 2100 ** rule applies from 2012 onwards and has transitions in March
 2101 ** and September, plus some one-off transitions in November
 2102 ** 2013. If zic looked only at the last 400 years, it would
 2103 ** set max_year=2413, with the intent that the 400 years 2014
 2104 ** through 2413 will be repeated. The last transition listed
 2105 ** in the tzfile would be in 2413-09, less than 400 years
 2106 ** after the last one-off transition in 2013-11. Two years
 2107 ** might be overkill, but with the kind of edge cases
 2108 ** available we're not sure that one year would suffice.
 2109 */
 2110 enum { years_of_observations = YEARSPERREPEAT + 2 };
 2111
 2112 if (min_year >= ZIC_MIN + years_of_observations)
 2113 min_year -= years_of_observations;
2027 else min_year = ZIC_MIN; 2114 else min_year = ZIC_MIN;
2028 if (max_year <= ZIC_MAX - YEARSPERREPEAT) 2115 if (max_year <= ZIC_MAX - years_of_observations)
2029 max_year += YEARSPERREPEAT; 2116 max_year += years_of_observations;
2030 else max_year = ZIC_MAX; 2117 else max_year = ZIC_MAX;
2031 /* 2118 /*
2032 ** Regardless of any of the above, 2119 ** Regardless of any of the above,
2033 ** for a "proDSTic" zone which specifies that its rules 2120 ** for a "proDSTic" zone which specifies that its rules
2034 ** always have and always will be in effect, 2121 ** always have and always will be in effect,
2035 ** we only need one cycle to define the zone. 2122 ** we only need one cycle to define the zone.
2036 */ 2123 */
2037 if (prodstic) { 2124 if (prodstic) {
2038 min_year = 1900; 2125 min_year = 1900;
2039 max_year = min_year + YEARSPERREPEAT; 2126 max_year = min_year + years_of_observations;
2040 } 2127 }
2041 } 2128 }
2042 /* 2129 /*
2043 ** For the benefit of older systems, 2130 ** For the benefit of older systems,
2044 ** generate data from 1900 through 2037. 2131 ** generate data from 1900 through 2037.
2045 */ 2132 */
2046 if (min_year > 1900) 2133 if (min_year > 1900)
2047 min_year = 1900; 2134 min_year = 1900;
2048 if (max_year < 2037) 2135 if (max_year < 2037)
2049 max_year = 2037; 2136 max_year = 2037;
2050 for (i = 0; i < zonecount; ++i) { 2137 for (i = 0; i < zonecount; ++i) {
2051 /* 2138 /*
2052 ** A guess that may well be corrected later. 2139 ** A guess that may well be corrected later.
@@ -2088,27 +2175,27 @@ outzone(const struct zone *const zpfirst @@ -2088,27 +2175,27 @@ outzone(const struct zone *const zpfirst
2088 year <= rp->r_hiyear && 2175 year <= rp->r_hiyear &&
2089 yearistype(year, rp->r_yrtype); 2176 yearistype(year, rp->r_yrtype);
2090 if (rp->r_todo) 2177 if (rp->r_todo)
2091 rp->r_temp = rpytime(rp, year); 2178 rp->r_temp = rpytime(rp, year);
2092 } 2179 }
2093 for ( ; ; ) { 2180 for ( ; ; ) {
2094 int k; 2181 int k;
2095 zic_t jtime, ktime; 2182 zic_t jtime, ktime;
2096 zic_t offset; 2183 zic_t offset;
2097 2184
2098 INITIALIZE(ktime); 2185 INITIALIZE(ktime);
2099 if (useuntil) { 2186 if (useuntil) {
2100 /* 2187 /*
2101 ** Turn untiltime into UTC 2188 ** Turn untiltime into UT
2102 ** assuming the current gmtoff and 2189 ** assuming the current gmtoff and
2103 ** stdoff values. 2190 ** stdoff values.
2104 */ 2191 */
2105 untiltime = zp->z_untiltime; 2192 untiltime = zp->z_untiltime;
2106 if (!zp->z_untilrule.r_todisgmt) 2193 if (!zp->z_untilrule.r_todisgmt)
2107 untiltime = tadd(untiltime, 2194 untiltime = tadd(untiltime,
2108 -gmtoff); 2195 -gmtoff);
2109 if (!zp->z_untilrule.r_todisstd) 2196 if (!zp->z_untilrule.r_todisstd)
2110 untiltime = tadd(untiltime, 2197 untiltime = tadd(untiltime,
2111 -stdoff); 2198 -stdoff);
2112 } 2199 }
2113 /* 2200 /*
2114 ** Find the rule (of those to do, if any) 2201 ** Find the rule (of those to do, if any)
@@ -2196,27 +2283,65 @@ error(_("can't determine time zone abbre @@ -2196,27 +2283,65 @@ error(_("can't determine time zone abbre
2196 /* 2283 /*
2197 ** Now we may get to set starttime for the next zone line. 2284 ** Now we may get to set starttime for the next zone line.
2198 */ 2285 */
2199 if (useuntil) { 2286 if (useuntil) {
2200 startttisstd = zp->z_untilrule.r_todisstd; 2287 startttisstd = zp->z_untilrule.r_todisstd;
2201 startttisgmt = zp->z_untilrule.r_todisgmt; 2288 startttisgmt = zp->z_untilrule.r_todisgmt;
2202 starttime = zp->z_untiltime; 2289 starttime = zp->z_untiltime;
2203 if (!startttisstd) 2290 if (!startttisstd)
2204 starttime = tadd(starttime, -stdoff); 2291 starttime = tadd(starttime, -stdoff);
2205 if (!startttisgmt) 2292 if (!startttisgmt)
2206 starttime = tadd(starttime, -gmtoff); 2293 starttime = tadd(starttime, -gmtoff);
2207 } 2294 }
2208 } 2295 }
2209 writezone(zpfirst->z_name, envvar); 2296 if (do_extend) {
 2297 /*
 2298 ** If we're extending the explicitly listed observations
 2299 ** for 400 years because we can't fill the POSIX-TZ field,
 2300 ** check whether we actually ended up explicitly listing
 2301 ** observations through that period. If there aren't any
 2302 ** near the end of the 400-year period, add a redundant
 2303 ** one at the end of the final year, to make it clear
 2304 ** that we are claiming to have definite knowledge of
 2305 ** the lack of transitions up to that point.
 2306 */
 2307 struct rule xr;
 2308 struct attype *lastat;
 2309 xr.r_month = TM_JANUARY;
 2310 xr.r_dycode = DC_DOM;
 2311 xr.r_dayofmonth = 1;
 2312 xr.r_tod = 0;
 2313 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
 2314 if (attypes[i].at > lastat->at)
 2315 lastat = &attypes[i];
 2316 if (lastat->at < rpytime(&xr, max_year - 1)) {
 2317 /*
 2318 ** Create new type code for the redundant entry,
 2319 ** to prevent it being optimised away.
 2320 */
 2321 if (typecnt >= TZ_MAX_TYPES) {
 2322 error(_("too many local time types"));
 2323 exit(EXIT_FAILURE);
 2324 }
 2325 gmtoffs[typecnt] = gmtoffs[lastat->type];
 2326 isdsts[typecnt] = isdsts[lastat->type];
 2327 ttisstds[typecnt] = ttisstds[lastat->type];
 2328 ttisgmts[typecnt] = ttisgmts[lastat->type];
 2329 abbrinds[typecnt] = abbrinds[lastat->type];
 2330 ++typecnt;
 2331 addtt(rpytime(&xr, max_year + 1), typecnt-1);
 2332 }
 2333 }
 2334 writezone(zpfirst->z_name, envvar, version);
2210 free(startbuf); 2335 free(startbuf);
2211 free(ab); 2336 free(ab);
2212 free(envvar); 2337 free(envvar);
2213} 2338}
2214 2339
2215static void 2340static void
2216addtt(const zic_t starttime, int type) 2341addtt(const zic_t starttime, int type)
2217{ 2342{
2218 if (starttime <= min_time || 2343 if (starttime <= min_time ||
2219 (timecnt == 1 && attypes[0].at < min_time)) { 2344 (timecnt == 1 && attypes[0].at < min_time)) {
2220 gmtoffs[0] = gmtoffs[type]; 2345 gmtoffs[0] = gmtoffs[type];
2221 isdsts[0] = isdsts[type]; 2346 isdsts[0] = isdsts[type];
2222 ttisstds[0] = ttisstds[type]; 2347 ttisstds[0] = ttisstds[type];
@@ -2266,27 +2391,27 @@ addtype(const zic_t gmtoff, const char * @@ -2266,27 +2391,27 @@ addtype(const zic_t gmtoff, const char *
2266 ttisstd == ttisstds[i] && 2391 ttisstd == ttisstds[i] &&
2267 ttisgmt == ttisgmts[i]) 2392 ttisgmt == ttisgmts[i])
2268 return i; 2393 return i;
2269 } 2394 }
2270 /* 2395 /*
2271 ** There isn't one; add a new one, unless there are already too 2396 ** There isn't one; add a new one, unless there are already too
2272 ** many. 2397 ** many.
2273 */ 2398 */
2274 if (typecnt >= TZ_MAX_TYPES) { 2399 if (typecnt >= TZ_MAX_TYPES) {
2275 error(_("too many local time types")); 2400 error(_("too many local time types"));
2276 exit(EXIT_FAILURE); 2401 exit(EXIT_FAILURE);
2277 } 2402 }
2278 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 2403 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2279 error(_("UTC offset out of range")); 2404 error(_("UT offset out of range"));
2280 exit(EXIT_FAILURE); 2405 exit(EXIT_FAILURE);
2281 } 2406 }
2282 gmtoffs[i] = gmtoff; 2407 gmtoffs[i] = gmtoff;
2283 isdsts[i] = isdst; 2408 isdsts[i] = isdst;
2284 ttisstds[i] = ttisstd; 2409 ttisstds[i] = ttisstd;
2285 ttisgmts[i] = ttisgmt; 2410 ttisgmts[i] = ttisgmt;
2286 2411
2287 for (j = 0; j < charcnt; ++j) 2412 for (j = 0; j < charcnt; ++j)
2288 if (strcmp(&chars[j], abbr) == 0) 2413 if (strcmp(&chars[j], abbr) == 0)
2289 break; 2414 break;
2290 if (j == charcnt) 2415 if (j == charcnt)
2291 newabbr(abbr); 2416 newabbr(abbr);
2292 abbrinds[i] = j; 2417 abbrinds[i] = j;
@@ -2461,27 +2586,27 @@ getfields(char *cp) @@ -2461,27 +2586,27 @@ getfields(char *cp)
2461 return array; 2586 return array;
2462} 2587}
2463 2588
2464static ATTRIBUTE_PURE zic_t 2589static ATTRIBUTE_PURE zic_t
2465oadd(const zic_t t1, const zic_t t2) 2590oadd(const zic_t t1, const zic_t t2)
2466{ 2591{
2467 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) { 2592 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) {
2468 error(_("time overflow")); 2593 error(_("time overflow"));
2469 exit(EXIT_FAILURE); 2594 exit(EXIT_FAILURE);
2470 } 2595 }
2471 return t1 + t2; 2596 return t1 + t2;
2472} 2597}
2473 2598
2474static zic_t 2599static ATTRIBUTE_PURE zic_t
2475tadd(const zic_t t1, const zic_t t2) 2600tadd(const zic_t t1, const zic_t t2)
2476{ 2601{
2477 if (t1 == max_time && t2 > 0) 2602 if (t1 == max_time && t2 > 0)
2478 return max_time; 2603 return max_time;
2479 if (t1 == min_time && t2 < 0) 2604 if (t1 == min_time && t2 < 0)
2480 return min_time; 2605 return min_time;
2481 if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) { 2606 if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
2482 error(_("time overflow")); 2607 error(_("time overflow"));
2483 exit(EXIT_FAILURE); 2608 exit(EXIT_FAILURE);
2484 } 2609 }
2485 return t1 + t2; 2610 return t1 + t2;
2486} 2611}
2487 2612
@@ -2595,34 +2720,28 @@ mp = _("time zone abbreviation lacks alp @@ -2595,34 +2720,28 @@ mp = _("time zone abbreviation lacks alp
2595mp = _("time zone abbreviation has fewer than 3 alphabetics"); 2720mp = _("time zone abbreviation has fewer than 3 alphabetics");
2596 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2721 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2597mp = _("time zone abbreviation has too many alphabetics"); 2722mp = _("time zone abbreviation has too many alphabetics");
2598 if (mp == NULL && (*cp == '+' || *cp == '-')) { 2723 if (mp == NULL && (*cp == '+' || *cp == '-')) {
2599 ++cp; 2724 ++cp;
2600 if (isascii((unsigned char) *cp) && 2725 if (isascii((unsigned char) *cp) &&
2601 isdigit((unsigned char) *cp)) 2726 isdigit((unsigned char) *cp))
2602 if (*cp++ == '1' && 2727 if (*cp++ == '1' &&
2603 *cp >= '0' && *cp <= '4') 2728 *cp >= '0' && *cp <= '4')
2604 ++cp; 2729 ++cp;
2605 } 2730 }
2606 if (*cp != '\0') 2731 if (*cp != '\0')
2607mp = _("time zone abbreviation differs from POSIX standard"); 2732mp = _("time zone abbreviation differs from POSIX standard");
2608 if (mp != NULL) { 2733 if (mp != NULL)
2609 char *wp = ecpyalloc(mp); 2734 warning("%s (%s)", mp, string);
2610 wp = ecatalloc(wp, " ("); 
2611 wp = ecatalloc(wp, string); 
2612 wp = ecatalloc(wp, ")"); 
2613 warning(wp); 
2614 free(wp); 
2615 } 
2616 } 2735 }
2617 i = strlen(string) + 1; 2736 i = strlen(string) + 1;
2618 if (charcnt + i > TZ_MAX_CHARS) { 2737 if (charcnt + i > TZ_MAX_CHARS) {
2619 error(_("too many, or too long, time zone abbreviations")); 2738 error(_("too many, or too long, time zone abbreviations"));
2620 exit(EXIT_FAILURE); 2739 exit(EXIT_FAILURE);
2621 } 2740 }
2622 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 2741 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
2623 charcnt += i; 2742 charcnt += i;
2624} 2743}
2625 2744
2626static int 2745static int
2627mkdirs(char *argname) 2746mkdirs(char *argname)
2628{ 2747{