summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore37
-rw-r--r--.travis.yml13
-rw-r--r--Makefile1288
-rw-r--r--README.txt14
-rw-r--r--conf.py182
-rw-r--r--deps.txt18
-rw-r--r--gen_pot.py38
-rw-r--r--gen_tests.py49
-rw-r--r--gen_tzinfo.py156
-rw-r--r--src/LICENSE.txt19
-rw-r--r--src/MANIFEST.in5
-rw-r--r--src/README.txt582
-rw-r--r--src/pytz/__init__.py503
-rw-r--r--src/pytz/exceptions.py48
-rw-r--r--src/pytz/lazy.py172
-rw-r--r--src/pytz/locales/pytz.pot2
-rw-r--r--src/pytz/reference.py140
-rw-r--r--src/pytz/tests/test_docs.py34
-rw-r--r--src/pytz/tests/test_lazy.py315
-rw-r--r--src/pytz/tests/test_tzinfo.py863
-rw-r--r--src/pytz/tzfile.py134
-rw-r--r--src/pytz/tzinfo.py577
l---------src/pytz/zoneinfo1
-rw-r--r--src/setup.cfg2
-rw-r--r--src/setup.py66
-rw-r--r--test_zdump.py138
-rw-r--r--tz/.gitignore26
-rw-r--r--tz/CONTRIBUTING (renamed from CONTRIBUTING)0
-rw-r--r--tz/LICENSE (renamed from LICENSE)0
-rw-r--r--tz/Makefile1123
-rw-r--r--tz/NEWS (renamed from NEWS)0
-rw-r--r--tz/README (renamed from README)0
-rw-r--r--tz/africa (renamed from africa)0
-rw-r--r--tz/antarctica (renamed from antarctica)0
-rw-r--r--tz/asctime.c (renamed from asctime.c)0
-rw-r--r--tz/asia (renamed from asia)0
-rw-r--r--tz/australasia (renamed from australasia)0
-rw-r--r--tz/backward (renamed from backward)0
-rw-r--r--tz/backzone (renamed from backzone)0
-rw-r--r--tz/calendars (renamed from calendars)0
-rw-r--r--tz/checklinks.awk (renamed from checklinks.awk)0
-rw-r--r--tz/checktab.awk (renamed from checktab.awk)0
-rw-r--r--tz/date.1 (renamed from date.1)0
-rw-r--r--tz/date.c (renamed from date.c)0
-rw-r--r--tz/difftime.c (renamed from difftime.c)0
-rw-r--r--tz/etcetera (renamed from etcetera)0
-rw-r--r--tz/europe (renamed from europe)0
-rw-r--r--tz/factory (renamed from factory)0
-rw-r--r--tz/iso3166.tab (renamed from iso3166.tab)0
-rw-r--r--tz/leap-seconds.list (renamed from leap-seconds.list)0
-rw-r--r--tz/leapseconds.awk (renamed from leapseconds.awk)0
-rw-r--r--tz/localtime.c (renamed from localtime.c)0
-rw-r--r--tz/newctime.3 (renamed from newctime.3)0
-rw-r--r--tz/newstrftime.3 (renamed from newstrftime.3)0
-rw-r--r--tz/newtzset.3 (renamed from newtzset.3)0
-rw-r--r--tz/northamerica (renamed from northamerica)0
-rw-r--r--tz/pacificnew (renamed from pacificnew)0
-rw-r--r--tz/private.h (renamed from private.h)0
-rw-r--r--tz/southamerica (renamed from southamerica)0
-rw-r--r--tz/strftime.c (renamed from strftime.c)0
-rw-r--r--tz/systemv (renamed from systemv)0
-rw-r--r--tz/theory.html (renamed from theory.html)0
-rw-r--r--tz/time2posix.3 (renamed from time2posix.3)0
-rw-r--r--tz/tz-art.html (renamed from tz-art.html)0
-rw-r--r--tz/tz-how-to.html (renamed from tz-how-to.html)0
-rw-r--r--tz/tz-link.html (renamed from tz-link.html)0
-rw-r--r--tz/tzfile.5 (renamed from tzfile.5)0
-rw-r--r--tz/tzfile.h (renamed from tzfile.h)0
-rw-r--r--tz/tzselect.8 (renamed from tzselect.8)0
-rw-r--r--tz/tzselect.ksh (renamed from tzselect.ksh)0
-rw-r--r--tz/workman.sh (renamed from workman.sh)0
-rw-r--r--tz/yearistype.sh (renamed from yearistype.sh)0
-rw-r--r--tz/zdump.8 (renamed from zdump.8)0
-rw-r--r--tz/zdump.c (renamed from zdump.c)0
-rw-r--r--tz/zic.8 (renamed from zic.8)0
-rw-r--r--tz/zic.c (renamed from zic.c)0
-rw-r--r--tz/ziguard.awk (renamed from ziguard.awk)0
-rw-r--r--tz/zishrink.awk (renamed from zishrink.awk)0
-rw-r--r--tz/zone.tab (renamed from zone.tab)0
-rw-r--r--tz/zone1970.tab (renamed from zone1970.tab)0
-rwxr-xr-xtz/zoneinfo2tdf.pl (renamed from zoneinfo2tdf.pl)0
81 files changed, 5404 insertions, 1141 deletions
diff --git a/.gitignore b/.gitignore
index cf3b825..725ae92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,26 +1,13 @@
-# Files intentionally not tracked by Git.
-# This file is in the public domain.
-*.a
-*.asc
-*.diff
-*.i
-*.o
-*.orig
-*.patch
-*.rej
-*.tar
-*.tar.*
-*.txt
-*.tzs
-*.zi
*~
-ChangeLog
-check_*
-date
-leapseconds
-tzselect
-version
-version.h
-yearistype
-zdump
-zic
+*.py[co]
+
+# Build-related files
+.stamp-dist
+.stamp-tzinfo
+.stamp-zoneinfo
+# For whatever reason, build/ is versioned, so the * is necessary.
+build/*
+tz/version
+
+# Generated datafile for test_zdump.py
+zdump.out
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..7ccf00f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+# vim: set filetype=yaml sw=2:
+sudo: required
+dist: trusty
+before_install:
+ - sudo locale-gen
+ - sudo add-apt-repository -y ppa:deadsnakes/ppa
+ - sudo apt-get update -y -qq
+ - sudo apt-get install -y python-all python-all-dev python3-all python3-all-dev build-essential python-setuptools python3-setuptools python-wheel python3-wheel python3-docutils python3-sphinx python3-flake8 python-flake8 python2.4-complete python2.5-complete python2.6-complete python3.1-complete python3.2-complete python3.3-complete python3.5-complete python2.4-gdbm python2.4-gdbm-dbg python3.6 wget python-pip python3-pip python3.7 python3.7-dev python3.7-distutils
+ - sudo pip install wheel
+ - sudo pip3 install wheel
+
+install: true
+script: make test TESTARGS=
diff --git a/Makefile b/Makefile
index fec0a4f..e723267 100644
--- a/Makefile
+++ b/Makefile
@@ -1,1123 +1,179 @@
-# Make and install tzdb code and data.
-
-# This file is in the public domain, so clarified as of
-# 2009-05-17 by Arthur David Olson.
-
-# Package name for the code distribution.
-PACKAGE= tzcode
-
-# Version number for the distribution, overridden in the 'tarballs' rule below.
-VERSION= unknown
-
-# Email address for bug reports.
-BUGEMAIL= tz@iana.org
-
-# DATAFORM selects the data format.
-# Available formats represent essentially the same data, albeit
-# possibly with minor discrepancies that users are not likely to notice.
-# To get new features and the best data right away, use:
-# DATAFORM= vanguard
-# To wait a while before using new features, to give downstream users
-# time to upgrade zic (the default), use:
-# DATAFORM= main
-# To wait even longer for new features, use:
-# DATAFORM= rearguard
-DATAFORM= main
-
-# Change the line below for your timezone (after finding the one you want in
-# one of the $(TDATA) source files, or adding it to a source file).
-# Alternatively, if you discover you've got the wrong timezone, you can just
-# zic -l rightzone
-# to correct things.
-# Use the command
-# make zonenames
-# to get a list of the values you can use for LOCALTIME.
-
-LOCALTIME= GMT
-
-# The POSIXRULES macro controls interpretation of nonstandard and obsolete
-# POSIX-like TZ settings like TZ='EET-2EEST' that lack DST transition rules.
-# In the reference implementation, if you want something other than Eastern
-# United States time as a template for handling these settings, you can
-# change the line below (after finding the timezone you want in the
-# one of the $(TDATA) source files, or adding it to a source file).
-# A setting like TZ='EET-2EEST' is supposed to use the rules in the
-# template file to determine "spring forward" and "fall back" days and
-# times; the environment variable itself specifies UT offsets of standard and
-# daylight saving time.
-# Alternatively, if you discover you've got the wrong timezone, you can just
-# zic -p rightzone
-# to correct things.
-# Use the command
-# make zonenames
-# to get a list of the values you can use for POSIXRULES.
-#
-# If POSIXRULES is empty, no template is installed; this is the intended
-# future default for POSIXRULES.
+# Build the pytz libraries
#
-# Nonempty POSIXRULES is obsolete and should not be relied on, because:
-# * It does not work correctly in popular implementations such as GNU/Linux.
-# * It does not work in the tzdb implementation for timestamps after 2037.
-# * It is incompatible with 'zic -b slim' if POSIXRULES specifies transitions
-# at standard time or UT rather than at local time.
-# In short, software should avoid ruleless settings like TZ='EET-2EEST'
-# and so should not depend on the value of POSIXRULES.
-
-POSIXRULES= America/New_York
-
-# Also see TZDEFRULESTRING below, which takes effect only
-# if the time zone files cannot be accessed.
-
-
-# Installation locations.
-#
-# The defaults are suitable for Debian, except that if REDO is
-# posix_right or right_posix then files that Debian puts under
-# /usr/share/zoneinfo/posix and /usr/share/zoneinfo/right are instead
-# put under /usr/share/zoneinfo-posix and /usr/share/zoneinfo-leaps,
-# respectively. Problems with the Debian approach are discussed in
-# the commentary for the right_posix rule (below).
-
-# Destination directory, which can be used for staging.
-# 'make DESTDIR=/stage install' installs under /stage (e.g., to
-# /stage/etc/localtime instead of to /etc/localtime). Files under
-# /stage are not intended to work as-is, but can be copied by hand to
-# the root directory later. If DESTDIR is empty, 'make install' does
-# not stage, but installs directly into production locations.
-DESTDIR =
-
-# Everything is installed into subdirectories of TOPDIR, and used there.
-# TOPDIR should be empty (meaning the root directory),
-# or a directory name that does not end in "/".
-# TOPDIR should be empty or an absolute name unless you're just testing.
-TOPDIR =
-
-# The default local timezone is taken from the file TZDEFAULT.
-TZDEFAULT = $(TOPDIR)/etc/localtime
-
-# The subdirectory containing installed program and data files, and
-# likewise for installed files that can be shared among architectures.
-# These should be relative file names.
-USRDIR = usr
-USRSHAREDIR = $(USRDIR)/share
-
-# "Compiled" timezone information is placed in the "TZDIR" directory
-# (and subdirectories).
-# TZDIR_BASENAME should not contain "/" and should not be ".", ".." or empty.
-TZDIR_BASENAME= zoneinfo
-TZDIR = $(TOPDIR)/$(USRSHAREDIR)/$(TZDIR_BASENAME)
-
-# The "tzselect" and (if you do "make INSTALL") "date" commands go in:
-BINDIR = $(TOPDIR)/$(USRDIR)/bin
-
-# The "zdump" command goes in:
-ZDUMPDIR = $(BINDIR)
-
-# The "zic" command goes in:
-ZICDIR = $(TOPDIR)/$(USRDIR)/sbin
-
-# Manual pages go in subdirectories of. . .
-MANDIR = $(TOPDIR)/$(USRSHAREDIR)/man
-
-# Library functions are put in an archive in LIBDIR.
-LIBDIR = $(TOPDIR)/$(USRDIR)/lib
-
-
-# Types to try, as an alternative to time_t.
-TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL)
-TIME_T_ALTERNATIVES_HEAD = int64_t
-TIME_T_ALTERNATIVES_TAIL = int32_t uint32_t uint64_t
-
-# What kind of TZif data files to generate. (TZif is the binary time
-# zone data format that zic generates; see Internet RFC 8536.)
-# If you want only POSIX time, with time values interpreted as
-# seconds since the epoch (not counting leap seconds), use
-# REDO= posix_only
-# below. If you want only "right" time, with values interpreted
-# as seconds since the epoch (counting leap seconds), use
-# REDO= right_only
-# below. If you want both sets of data available, with leap seconds not
-# counted normally, use
-# REDO= posix_right
-# below. If you want both sets of data available, with leap seconds counted
-# normally, use
-# REDO= right_posix
-# below. POSIX mandates that leap seconds not be counted; for compatibility
-# with it, use "posix_only" or "posix_right". Use POSIX time on systems with
-# leap smearing; this can work better than unsmeared "right" time with
-# applications that are not leap second aware, and is closer to unsmeared
-# "right" time than unsmeared POSIX time is (e.g., 0.5 vs 1.0 s max error).
-
-REDO= posix_right
-
-# To install data in text form that has all the information of the TZif data,
-# (optionally incorporating leap second information), use
-# TZDATA_TEXT= tzdata.zi leapseconds
-# To install text data without leap second information (e.g., because
-# REDO='posix_only'), use
-# TZDATA_TEXT= tzdata.zi
-# To avoid installing text data, use
-# TZDATA_TEXT=
-
-TZDATA_TEXT= leapseconds tzdata.zi
-
-# For backward-compatibility links for old zone names, use
-# BACKWARD= backward
-# If you also want the link US/Pacific-New, even though it is confusing
-# and is planned to be removed from the database eventually, use
-# BACKWARD= backward pacificnew
-# To omit these links, use
-# BACKWARD=
-
-BACKWARD= backward
-
-# If you want out-of-scope and often-wrong data from the file 'backzone', use
-# PACKRATDATA= backzone
-# To omit this data, use
-# PACKRATDATA=
-
-PACKRATDATA=
-
-# The name of a locale using the UTF-8 encoding, used during self-tests.
-# The tests are skipped if the name does not appear to work on this system.
-
-UTF8_LOCALE= en_US.utf8
-
-# Since "." may not be in PATH...
-
-YEARISTYPE= ./yearistype
-
-# Non-default libraries needed to link.
-LDLIBS=
-
-# Add the following to the end of the "CFLAGS=" line as needed to override
-# defaults specified in the source code. "-DFOO" is equivalent to "-DFOO=1".
-# -DDEPRECATE_TWO_DIGIT_YEARS for optional runtime warnings about strftime
-# formats that generate only the last two digits of year numbers
-# -DEPOCH_LOCAL if the 'time' function returns local time not UT
-# -DEPOCH_OFFSET=N if the 'time' function returns a value N greater
-# than what POSIX specifies, assuming local time is UT.
-# For example, N is 252460800 on AmigaOS.
-# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
-# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
-# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
-# -DHAVE_GENERIC=0 if _Generic does not work
-# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)
-# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
-# ctime_r and asctime_r incompatibly with the POSIX standard
-# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
-# -DHAVE_INTTYPES_H if you have a non-C99 compiler with <inttypes.h>
-# -DHAVE_LINK=0 if your system lacks a link function
-# -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function
-# -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
-# localtime_rz can make zdump significantly faster, but is nonstandard.
-# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
-# functions like 'link' or variables like 'tzname' required by POSIX
-# -DHAVE_SNPRINTF=0 if your system lacks the snprintf function
-# -DHAVE_STDBOOL_H if you have a non-C99 compiler with <stdbool.h>
-# -DHAVE_STDINT_H if you have a non-C99 compiler with <stdint.h>
-# -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l
-# -DHAVE_STRDUP=0 if your system lacks the strdup function
-# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
-# -DHAVE_SYMLINK=0 if your system lacks the symlink function
-# -DHAVE_SYS_STAT_H=0 if your compiler lacks a <sys/stat.h>
-# -DHAVE_SYS_WAIT_H=0 if your compiler lacks a <sys/wait.h>
-# -DHAVE_TZSET=0 if your system lacks a tzset function
-# -DHAVE_UNISTD_H=0 if your compiler lacks a <unistd.h>
-# -Dlocale_t=XXX if your system uses XXX instead of locale_t
-# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
-# with external linkage, e.g., applications cannot define 'localtime'.
-# -Dssize_t=long on hosts like MS-Windows that lack ssize_t
-# -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has
-# security implications and is not recommended for general use
-# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
-# not needed by the main-program tz code, which is single-threaded.
-# Append other compiler flags as needed, e.g., -pthread on GNU/Linux.
-# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
-# This is intended for internal use only; it mangles external names.
-# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
-# -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
-# the default is system-supplied, typically "/usr/lib/locale"
-# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
-# DST transitions if the time zone files cannot be accessed
-# -DUNINIT_TRAP if reading uninitialized storage can cause problems
-# other than simply getting garbage data
-# -DUSE_LTZ=0 to build zdump with the system time zone library
-# Also set TZDOBJS=zdump.o and CHECK_TIME_T_ALTERNATIVES= below.
-# -DZIC_BLOAT_DEFAULT=\"slim\" to default zic's -b option to "slim", and
-# similarly for "fat". Fat TZif files work around incompatibilities
-# and bugs in some TZif readers, notably readers that mishandle 64-bit
-# data in TZif files. Slim TZif files are more efficient and do not
-# work around these incompatibilities and bugs. If not given, the
-# current default is "fat" but this is intended to change as readers
-# requiring fat files often mishandle timestamps after 2037 anyway.
-# -DZIC_MAX_ABBR_LEN_WO_WARN=3
-# (or some other number) to set the maximum time zone abbreviation length
-# that zic will accept without a warning (the default is 6)
-# $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking
-# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
-GCC_INSTRUMENT = \
- -fsanitize=undefined -fsanitize-address-use-after-scope \
- -fsanitize-undefined-trap-on-error -fstack-protector
-GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
- $(GCC_INSTRUMENT) \
- -Wall -Wextra \
- -Walloc-size-larger-than=100000 -Warray-bounds=2 \
- -Wbad-function-cast -Wcast-align=strict -Wdate-time \
- -Wdeclaration-after-statement -Wdouble-promotion \
- -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
- -Winit-self -Wjump-misses-init -Wlogical-op \
- -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
- -Wold-style-definition -Woverlength-strings -Wpointer-arith \
- -Wshadow -Wshift-overflow=2 -Wstrict-prototypes -Wstringop-overflow=4 \
- -Wstringop-truncation -Wsuggest-attribute=cold \
- -Wsuggest-attribute=const -Wsuggest-attribute=format \
- -Wsuggest-attribute=malloc \
- -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
- -Wtrampolines -Wundef -Wuninitialized -Wunused \
- -Wvariadic-macros -Wvla -Wwrite-strings \
- -Wno-address -Wno-format-nonliteral -Wno-sign-compare \
- -Wno-type-limits -Wno-unused-parameter
-#
-# If your system has a "GMT offset" field in its "struct tm"s
-# (or if you decide to add such a field in your system's "time.h" file),
-# add the name to a define such as
-# -DTM_GMTOFF=tm_gmtoff
-# to the end of the "CFLAGS=" line. If not defined, the code attempts to
-# guess TM_GMTOFF from other macros; define NO_TM_GMTOFF to suppress this.
-# Similarly, if your system has a "zone abbreviation" field, define
-# -DTM_ZONE=tm_zone
-# and define NO_TM_ZONE to suppress any guessing. These two fields are not
-# required by POSIX, but are widely available on GNU/Linux and BSD systems.
-#
-# The next batch of options control support for external variables
-# exported by tzcode. In practice these variables are less useful
-# than TM_GMTOFF and TM_ZONE. However, most of them are standardized.
-# #
-# # To omit or support the external variable "tzname", add one of:
-# # -DHAVE_TZNAME=0
-# # -DHAVE_TZNAME=1
-# # to the "CFLAGS=" line. "tzname" is required by POSIX 1988 and later.
-# # If not defined, the code attempts to guess HAVE_TZNAME from other macros.
-# # Warning: unless time_tz is also defined, HAVE_TZNAME=1 can cause
-# # crashes when combined with some platforms' standard libraries,
-# # presumably due to memory allocation issues.
-# #
-# # To omit or support the external variables "timezone" and "daylight", add
-# # -DUSG_COMPAT=0
-# # -DUSG_COMPAT=1
-# # to the "CFLAGS=" line; "timezone" and "daylight" are inspired by
-# # Unix Systems Group code and are required by POSIX 2008 (with XSI) and later.
-# # If not defined, the code attempts to guess USG_COMPAT from other macros.
-# #
-# # To support the external variable "altzone", add
-# # -DALTZONE
-# # to the end of the "CFLAGS=" line; although "altzone" appeared in
-# # System V Release 3.1 it has not been standardized.
-#
-# If you want functions that were inspired by early versions of X3J11's work,
-# add
-# -DSTD_INSPIRED
-# to the end of the "CFLAGS=" line. This arranges for the functions
-# "tzsetwall", "offtime", "timelocal", "timegm", "timeoff",
-# "posix2time", and "time2posix" to be added to the time conversion library.
-# "tzsetwall" is like "tzset" except that it arranges for local wall clock
-# time (rather than the timezone specified in the TZ environment variable)
-# to be used.
-# "offtime" is like "gmtime" except that it accepts a second (long) argument
-# that gives an offset to add to the time_t when converting it.
-# "timelocal" is equivalent to "mktime".
-# "timegm" is like "timelocal" except that it turns a struct tm into
-# a time_t using UT (rather than local time as "timelocal" does).
-# "timeoff" is like "timegm" except that it accepts a second (long) argument
-# that gives an offset to use when converting to a time_t.
-# "posix2time" and "time2posix" are described in an included manual page.
-# X3J11's work does not describe any of these functions.
-# Sun has provided "tzsetwall", "timelocal", and "timegm" in SunOS 4.0.
-# These functions may well disappear in future releases of the time
-# conversion package.
-#
-# If you don't want functions that were inspired by NetBSD, add
-# -DNETBSD_INSPIRED=0
-# to the end of the "CFLAGS=" line. Otherwise, the functions
-# "localtime_rz", "mktime_z", "tzalloc", and "tzfree" are added to the
-# time library, and if STD_INSPIRED is also defined the functions
-# "posix2time_z" and "time2posix_z" are added as well.
-# The functions ending in "_z" (or "_rz") are like their unsuffixed
-# (or suffixed-by-"_r") counterparts, except with an extra first
-# argument of opaque type timezone_t that specifies the timezone.
-# "tzalloc" allocates a timezone_t value, and "tzfree" frees it.
-#
-# If you want to allocate state structures in localtime, add
-# -DALL_STATE
-# to the end of the "CFLAGS=" line. Storage is obtained by calling malloc.
-#
-# NIST-PCTS:151-2, Version 1.4, (1993-12-03) is a test suite put
-# out by the National Institute of Standards and Technology
-# which claims to test C and Posix conformance. If you want to pass PCTS, add
-# -DPCTS
-# to the end of the "CFLAGS=" line.
-#
-# If you want strict compliance with XPG4 as of 1994-04-09, add
-# -DXPG4_1994_04_09
-# to the end of the "CFLAGS=" line. This causes "strftime" to always return
-# 53 as a week number (rather than 52 or 53) for January days before
-# January's first Monday when a "%V" format is used and January 1
-# falls on a Friday, Saturday, or Sunday.
-
-CFLAGS=
-
-# Linker flags. Default to $(LFLAGS) for backwards compatibility
-# to release 2012h and earlier.
-
-LDFLAGS= $(LFLAGS)
-
-# For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in
-# submake command lines. The default is no leap seconds.
-
-LEAPSECONDS=
-
-# The zic command and its arguments.
-
-zic= ./zic
-ZIC= $(zic) $(ZFLAGS)
-
-# To shrink the size of installed TZif files,
-# append "-r @N" to omit data before N-seconds-after-the-Epoch.
-# You can also append "-b slim" if that is not already the default;
-# see ZIC_BLOAT_DEFAULT above.
-# See the zic man page for more about -b and -r.
-ZFLAGS=
-
-# How to use zic to install TZif files.
-
-ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS)
-
-# The name of a Posix-compliant 'awk' on your system.
-# Older 'mawk' versions, such as the 'mawk' in Ubuntu 16.04, might dump core;
-# on Ubuntu you can work around this with
-# AWK= gawk
-AWK= awk
-
-# The full path name of a Posix-compliant shell, preferably one that supports
-# the Korn shell's 'select' statement as an extension.
-# These days, Bash is the most popular.
-# It should be OK to set this to /bin/sh, on platforms where /bin/sh
-# lacks 'select' or doesn't completely conform to Posix, but /bin/bash
-# is typically nicer if it works.
-KSHELL= /bin/bash
-
-# Name of curl <https://curl.haxx.se/>, used for HTML validation.
-CURL= curl
-
-# Name of GNU Privacy Guard <https://gnupg.org/>, used to sign distributions.
-GPG= gpg
-
-# The path where SGML DTDs are kept and the catalog file(s) to use when
-# validating HTML 4.01. The default should work on both Debian and Red Hat.
-SGML_TOPDIR= /usr
-SGML_DTDDIR= $(SGML_TOPDIR)/share/xml/w3c-sgml-lib/schema/dtd
-SGML_SEARCH_PATH= $(SGML_DTDDIR)/REC-html401-19991224
-SGML_CATALOG_FILES= \
- $(SGML_TOPDIR)/share/doc/w3-recs/html/www.w3.org/TR/1999/REC-html401-19991224/HTML4.cat:$(SGML_TOPDIR)/share/sgml/html/4.01/HTML4.cat
-
-# The name, arguments and environment of a program to validate HTML 4.01.
-# See <http://openjade.sourceforge.net/doc/> for a validator, and
-# <https://validator.w3.org/source/> for a validation library.
-# Set VALIDATE=':' if you do not have such a program.
-VALIDATE = nsgmls
-VALIDATE_FLAGS = -s -B -wall -wno-unused-param
-VALIDATE_ENV = \
- SGML_CATALOG_FILES='$(SGML_CATALOG_FILES)' \
- SGML_SEARCH_PATH='$(SGML_SEARCH_PATH)' \
- SP_CHARSET_FIXED=YES \
- SP_ENCODING=UTF-8
-
-# This expensive test requires USE_LTZ.
-# To suppress it, define this macro to be empty.
-CHECK_TIME_T_ALTERNATIVES = check_time_t_alternatives
-
-# SAFE_CHAR is a regular expression that matches a safe character.
-# Some parts of this distribution are limited to safe characters;
-# others can use any UTF-8 character.
-# For now, the safe characters are a safe subset of ASCII.
-# The caller must set the shell variable 'sharp' to the character '#',
-# since Makefile macros cannot contain '#'.
-# TAB_CHAR is a single tab character, in single quotes.
-TAB_CHAR= ' '
-SAFE_CHARSET1= $(TAB_CHAR)' !\"'$$sharp'$$%&'\''()*+,./0123456789:;<=>?@'
-SAFE_CHARSET2= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\^_`'
-SAFE_CHARSET3= 'abcdefghijklmnopqrstuvwxyz{|}~'
-SAFE_CHARSET= $(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3)
-SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]'
-
-# These characters are Latin-1, and so are likely to be displayable
-# even in editors with limited character sets.
-UNUSUAL_OK_LATIN_1 = «°±»½¾×
-# This IPA symbol is represented in Unicode as the composition of
-# U+0075 and U+032F, and U+032F is not considered alphabetic by some
-# grep implementations that do not grok composition.
-UNUSUAL_OK_IPA = u̯
-# Non-ASCII non-letters that OK_CHAR allows, as these characters are
-# useful in commentary.
-UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1)$(UNUSUAL_OK_IPA)
-
-# OK_CHAR matches any character allowed in the distributed files.
-# This is the same as SAFE_CHAR, except that UNUSUAL_OK_CHARSET and
-# multibyte letters are also allowed so that commentary can contain a
-# few safe symbols and people's names and can quote non-English sources.
-# Other non-letters are limited to ASCII renderings for the
-# convenience of maintainers using XEmacs 21.5.34, which by default
-# mishandles Unicode characters U+0100 and greater.
-OK_CHAR= '[][:alpha:]$(UNUSUAL_OK_CHARSET)'$(SAFE_CHARSET)'-]'
-
-# SAFE_LINE matches a line of safe characters.
-# SAFE_SHARP_LINE is similar, except any OK character can follow '#';
-# this is so that comments can contain non-ASCII characters.
-# OK_LINE matches a line of OK characters.
-SAFE_LINE= '^'$(SAFE_CHAR)'*$$'
-SAFE_SHARP_LINE='^'$(SAFE_CHAR)'*('$$sharp$(OK_CHAR)'*)?$$'
-OK_LINE= '^'$(OK_CHAR)'*$$'
-
-# Flags to give 'tar' when making a distribution.
-# Try to use flags appropriate for GNU tar.
-GNUTARFLAGS= --numeric-owner --owner=0 --group=0 --mode=go+u,go-w --sort=name
-TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \
- then echo $(GNUTARFLAGS); \
- else :; \
- fi`
-# Flags to give 'gzip' when making a distribution.
-GZIPFLAGS= -9n
-
-###############################################################################
-
-#MAKE= make
-
-cc= cc
-CC= $(cc) -DTZDIR='"$(TZDIR)"'
-
-AR= ar
-
-# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib.
-RANLIB= :
-
-TZCOBJS= zic.o
-TZDOBJS= zdump.o localtime.o asctime.o strftime.o
-DATEOBJS= date.o localtime.o strftime.o asctime.o
-LIBSRCS= localtime.c asctime.c difftime.c
-LIBOBJS= localtime.o asctime.o difftime.o
-HEADERS= tzfile.h private.h
-NONLIBSRCS= zic.c zdump.c
-NEWUCBSRCS= date.c strftime.c
-SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \
- tzselect.ksh workman.sh
-MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \
- tzfile.5 tzselect.8 zic.8 zdump.8
-MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \
- time2posix.3.txt \
- tzfile.5.txt tzselect.8.txt zic.8.txt zdump.8.txt \
- date.1.txt
-COMMON= calendars CONTRIBUTING LICENSE Makefile \
- NEWS README theory.html version
-WEB_PAGES= tz-art.html tz-how-to.html tz-link.html
-CHECK_WEB_PAGES=check_theory.html check_tz-art.html \
- check_tz-how-to.html check_tz-link.html
-DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES)
-PRIMARY_YDATA= africa antarctica asia australasia \
- europe northamerica southamerica
-YDATA= $(PRIMARY_YDATA) etcetera
-NDATA= systemv factory
-TDATA_TO_CHECK= $(YDATA) $(NDATA) backward pacificnew
-TDATA= $(YDATA) $(NDATA) $(BACKWARD)
-ZONETABLES= zone1970.tab zone.tab
-TABDATA= iso3166.tab $(TZDATA_TEXT) $(ZONETABLES)
-LEAP_DEPS= leapseconds.awk leap-seconds.list
-TZDATA_ZI_DEPS= ziguard.awk zishrink.awk version $(TDATA) $(PACKRATDATA)
-DSTDATA_ZI_DEPS= ziguard.awk $(TDATA) $(PACKRATDATA)
-DATA= $(TDATA_TO_CHECK) backzone iso3166.tab leap-seconds.list \
- leapseconds yearistype.sh $(ZONETABLES)
-AWK_SCRIPTS= checklinks.awk checktab.awk leapseconds.awk \
- ziguard.awk zishrink.awk
-MISC= $(AWK_SCRIPTS) zoneinfo2tdf.pl
-TZS_YEAR= 2050
-TZS_CUTOFF_FLAG= -c $(TZS_YEAR)
-TZS= to$(TZS_YEAR).tzs
-TZS_NEW= to$(TZS_YEAR)new.tzs
-TZS_DEPS= $(PRIMARY_YDATA) asctime.c localtime.c \
- private.h tzfile.h zdump.c zic.c
-# EIGHT_YARDS is just a yard short of the whole ENCHILADA.
-EIGHT_YARDS = $(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC) tzdata.zi
-ENCHILADA = $(EIGHT_YARDS) $(TZS)
-
-# Consult these files when deciding whether to rebuild the 'version' file.
-# This list is not the same as the output of 'git ls-files', since
-# .gitignore is not distributed.
-VERSION_DEPS= \
- calendars CONTRIBUTING LICENSE Makefile NEWS README \
- africa antarctica asctime.c asia australasia \
- backward backzone \
- checklinks.awk checktab.awk \
- date.1 date.c difftime.c \
- etcetera europe factory iso3166.tab \
- leap-seconds.list leapseconds.awk localtime.c \
- newctime.3 newstrftime.3 newtzset.3 northamerica \
- pacificnew private.h \
- southamerica strftime.c systemv theory.html \
- time2posix.3 tz-art.html tz-how-to.html tz-link.html \
- tzfile.5 tzfile.h tzselect.8 tzselect.ksh \
- workman.sh yearistype.sh \
- zdump.8 zdump.c zic.8 zic.c \
- ziguard.awk zishrink.awk \
- zone.tab zone1970.tab zoneinfo2tdf.pl
-
-# And for the benefit of csh users on systems that assume the user
-# shell should be used to handle commands in Makefiles. . .
-
-SHELL= /bin/sh
-
-all: tzselect yearistype zic zdump libtz.a $(TABDATA) \
- vanguard.zi main.zi rearguard.zi
-
-ALL: all date $(ENCHILADA)
-
-install: all $(DATA) $(REDO) $(MANS)
- mkdir -p '$(DESTDIR)$(BINDIR)' \
- '$(DESTDIR)$(ZDUMPDIR)' '$(DESTDIR)$(ZICDIR)' \
- '$(DESTDIR)$(LIBDIR)' \
- '$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \
- '$(DESTDIR)$(MANDIR)/man8'
- $(ZIC_INSTALL) -l $(LOCALTIME) \
- `case '$(POSIXRULES)' in ?*) echo '-p';; esac \
- ` $(POSIXRULES) \
- -t '$(DESTDIR)$(TZDEFAULT)'
- cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.'
- cp tzselect '$(DESTDIR)$(BINDIR)/.'
- cp zdump '$(DESTDIR)$(ZDUMPDIR)/.'
- cp zic '$(DESTDIR)$(ZICDIR)/.'
- cp libtz.a '$(DESTDIR)$(LIBDIR)/.'
- $(RANLIB) '$(DESTDIR)$(LIBDIR)/libtz.a'
- cp -f newctime.3 newtzset.3 '$(DESTDIR)$(MANDIR)/man3/.'
- cp -f tzfile.5 '$(DESTDIR)$(MANDIR)/man5/.'
- cp -f tzselect.8 zdump.8 zic.8 '$(DESTDIR)$(MANDIR)/man8/.'
-
-INSTALL: ALL install date.1
- mkdir -p '$(DESTDIR)$(BINDIR)' '$(DESTDIR)$(MANDIR)/man1'
- cp date '$(DESTDIR)$(BINDIR)/.'
- cp -f date.1 '$(DESTDIR)$(MANDIR)/man1/.'
-
-version: $(VERSION_DEPS)
- { (type git) >/dev/null 2>&1 && \
- V=`git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \
- --abbrev=7 --dirty` || \
- V='$(VERSION)'; } && \
- printf '%s\n' "$$V" >$@.out
- mv $@.out $@
-
-# These files can be tailored by setting BACKWARD and PACKRATDATA.
-vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS)
- $(AWK) -v DATAFORM=`expr $@ : '\(.*\).zi'` -f ziguard.awk \
- $(TDATA) $(PACKRATDATA) >$@.out
- mv $@.out $@
-# This file has a version comment that attempts to capture any tailoring
-# via BACKWARD, DATAFORM, PACKRATDATA, and REDO.
-tzdata.zi: $(DATAFORM).zi version zishrink.awk
- version=`sed 1q version` && \
- LC_ALL=C $(AWK) \
- -v dataform='$(DATAFORM)' \
- -v deps='$(DSTDATA_ZI_DEPS) zishrink.awk' \
- -v redo='$(REDO)' \
- -v version="$$version" \
- -f zishrink.awk \
- $(DATAFORM).zi >$@.out
- mv $@.out $@
-
-version.h: version
- VERSION=`cat version` && printf '%s\n' \
- 'static char const PKGVERSION[]="($(PACKAGE)) ";' \
- "static char const TZVERSION[]=\"$$VERSION\";" \
- 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";' \
- >$@.out
- mv $@.out $@
-
-zdump: $(TZDOBJS)
- $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS)
-
-zic: $(TZCOBJS)
- $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS)
-
-yearistype: yearistype.sh
- cp yearistype.sh yearistype
- chmod +x yearistype
-
-leapseconds: $(LEAP_DEPS)
- $(AWK) -f leapseconds.awk leap-seconds.list >$@.out
- mv $@.out $@
-
-# Arguments to pass to submakes of install_data.
-# They can be overridden by later submake arguments.
-INSTALLARGS = \
- BACKWARD='$(BACKWARD)' \
- DESTDIR='$(DESTDIR)' \
- LEAPSECONDS='$(LEAPSECONDS)' \
- PACKRATDATA='$(PACKRATDATA)' \
- TZDEFAULT='$(TZDEFAULT)' \
- TZDIR='$(TZDIR)' \
- YEARISTYPE='$(YEARISTYPE)' \
- ZIC='$(ZIC)'
-
-INSTALL_DATA_DEPS = zic leapseconds yearistype tzdata.zi
-
-# 'make install_data' installs one set of TZif files.
-install_data: $(INSTALL_DATA_DEPS)
- $(ZIC_INSTALL) tzdata.zi
-
-posix_only: $(INSTALL_DATA_DEPS)
- $(MAKE) $(INSTALLARGS) LEAPSECONDS= install_data
-
-right_only: $(INSTALL_DATA_DEPS)
- $(MAKE) $(INSTALLARGS) LEAPSECONDS='-L leapseconds' \
- install_data
-
-# In earlier versions of this makefile, the other two directories were
-# subdirectories of $(TZDIR). However, this led to configuration errors.
-# For example, with posix_right under the earlier scheme,
-# TZ='right/Australia/Adelaide' got you localtime with leap seconds,
-# but gmtime without leap seconds, which led to problems with applications
-# like sendmail that subtract gmtime from localtime.
-# Therefore, the other two directories are now siblings of $(TZDIR).
-# You must replace all of $(TZDIR) to switch from not using leap seconds
-# to using them, or vice versa.
-right_posix: right_only
- rm -fr '$(DESTDIR)$(TZDIR)-leaps'
- ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-leaps' || \
- $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only
- $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only
-
-posix_right: posix_only
- rm -fr '$(DESTDIR)$(TZDIR)-posix'
- ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-posix' || \
- $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only
- $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only
-
-# This obsolescent rule is present for backwards compatibility with
-# tz releases 2014g through 2015g. It should go away eventually.
-posix_packrat: $(INSTALL_DATA_DEPS)
- $(MAKE) $(INSTALLARGS) PACKRATDATA=backzone posix_only
-
-zones: $(REDO)
-
-# dummy.zd is not a real file; it is mentioned here only so that the
-# top-level 'make' does not have a syntax error.
-ZDS = dummy.zd
-# Rule used only by submakes invoked by the $(TZS_NEW) rule.
-# It is separate so that GNU 'make -j' can run instances in parallel.
-$(ZDS): zdump
- ./zdump -i $(TZS_CUTOFF_FLAG) '$(wd)/'$$(expr $@ : '\(.*\).zd') \
- >$@
-
-TZS_NEW_DEPS = tzdata.zi zdump zic
-$(TZS_NEW): $(TZS_NEW_DEPS)
- rm -fr tzs$(TZS_YEAR).dir
- mkdir tzs$(TZS_YEAR).dir
- $(zic) -d tzs$(TZS_YEAR).dir tzdata.zi
- $(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \
- tzdata.zi | LC_ALL=C sort >$@.out
- wd=`pwd` && \
- x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \
- tzdata.zi \
- | LC_ALL=C sort -t . -k 2,2` && \
- set x $$x && \
- shift && \
- ZDS=$$* && \
- $(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \
- ZDS="$$ZDS" $$ZDS && \
- sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out
- rm -fr tzs$(TZS_YEAR).dir
- mv $@.out $@
-
-# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the
-# failed output and fix the inconsistency, perhaps by running 'make force_tzs'.
-$(TZS):
- touch $@
-
-force_tzs: $(TZS_NEW)
- cp $(TZS_NEW) $(TZS)
-
-libtz.a: $(LIBOBJS)
- rm -f $@
- $(AR) -rc $@ $(LIBOBJS)
- $(RANLIB) $@
-
-date: $(DATEOBJS)
- $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS)
-
-tzselect: tzselect.ksh version
- VERSION=`cat version` && sed \
- -e 's|#!/bin/bash|#!$(KSHELL)|g' \
- -e 's|AWK=[^}]*|AWK=$(AWK)|g' \
- -e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \
- -e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \
- -e 's|TZDIR=[^}]*|TZDIR=$(TZDIR)|' \
- -e 's|\(TZVERSION\)=.*|\1='"$$VERSION"'|' \
- <$@.ksh >$@.out
- chmod +x $@.out
- mv $@.out $@
-
-check: check_character_set check_white_space check_links \
- check_name_lengths check_sorted \
- check_tables check_web check_zishrink check_tzs
-
-check_character_set: $(ENCHILADA)
- test ! '$(UTF8_LOCALE)' || \
- ! printf 'A\304\200B\n' | \
- LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 || { \
- LC_ALL='$(UTF8_LOCALE)' && export LC_ALL && \
- sharp='#' && \
- ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \
- $(MISC) $(SOURCES) $(WEB_PAGES) \
- CONTRIBUTING LICENSE README \
- version tzdata.zi && \
- ! grep -Env $(SAFE_LINE)'|^UNUSUAL_OK_'$(OK_CHAR)'*$$' \
- Makefile && \
- ! grep -Env $(SAFE_SHARP_LINE) $(TDATA_TO_CHECK) backzone \
- leapseconds yearistype.sh zone.tab && \
- ! grep -Env $(OK_LINE) $(ENCHILADA); \
- }
+MAKE=make
+SHELL=/bin/bash
+PYTHON24=python2.4
+PYTHON25=python2.5
+PYTHON26=python2.6
+PYTHON27=python2.7
+PYTHON31=python3.1
+PYTHON32=python3.2
+PYTHON33=python3.3
+PYTHON34=python3.4
+PYTHON35=python3.5
+PYTHON36=python3.6
+PYTHON37=python3.7
+PYTHON=/usr/bin/python
+PYTHON3=/usr/bin/python3
+IANA=./tz
+IANA_GIT=https://github.com/eggert/tz.git
+
+TESTARGS=-vv
+TARGET=
+#TARGET=Europe/Amsterdam Europe/Moscow W-SU Etc/GMT+2 Atlantic/South_Georgia Europe/Warsaw Europe/Vilnius
+#Mideast/Riyadh87
+STYLESHEET=/usr/share/python-docutils/stylesheets/default.css
+
+all: dist
+
+check: test_tzinfo test_docs
+
+build: .stamp-tzinfo
+
+
+dist: build wheels
+ cd build/dist && mkdir -p ../tarballs && \
+ ${PYTHON} setup.py -q sdist --dist-dir ../tarballs \
+ --formats=bztar,gztar,zip
+
+wheels:
+ cd build/dist && mkdir -p ../tarballs
+ cd build/dist && ${PYTHON} setup.py -q bdist_wheel --universal --dist-dir=../tarballs
+ cd build/dist && ${PYTHON3} setup.py -q bdist_wheel --universal --dist-dir=../tarballs
+
+upload: sign
+ cd build/dist && ${PYTHON3} setup.py register
+ twine upload build/tarballs/*.{whl,gz,asc}
+
+sign:
+ rm -f build/tarballs/*.asc
+ for f in build/tarballs/*.{whl,zip,bz2,gz} ; do \
+ gpg --detach-sign -a $$f; \
+ done
+
+test: test_lazy test_tzinfo test_docs test_zdump
+
+lint: .stamp-tzinfo
+ flake8 --ignore=E402 build/dist gen_*.py test_zdump.py
+
+clean:
+ rm -f .stamp-*
+ rm -rf build/*/* zdump.out
+ make -C ${IANA} clean
+ find . -name \*.pyc | xargs rm -f
+
+test_lazy: .stamp-tzinfo
+ cd build/dist/pytz/tests \
+ && ${PYTHON24} test_lazy.py ${TESTARGS} \
+ && ${PYTHON25} test_lazy.py ${TESTARGS} \
+ && ${PYTHON26} test_lazy.py ${TESTARGS} \
+ && ${PYTHON27} test_lazy.py ${TESTARGS} \
+ && ${PYTHON31} test_lazy.py ${TESTARGS} \
+ && ${PYTHON32} test_lazy.py ${TESTARGS} \
+ && ${PYTHON33} test_lazy.py ${TESTARGS} \
+ && ${PYTHON34} test_lazy.py ${TESTARGS} \
+ && ${PYTHON35} test_lazy.py ${TESTARGS} \
+ && ${PYTHON36} test_lazy.py ${TESTARGS} \
+ && ${PYTHON37} test_lazy.py ${TESTARGS}
+
+test_tzinfo: .stamp-tzinfo
+ cd build/dist/pytz/tests \
+ && ${PYTHON24} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON25} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON26} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON27} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON31} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON32} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON33} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON34} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON35} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON36} test_tzinfo.py ${TESTARGS} \
+ && ${PYTHON37} test_tzinfo.py ${TESTARGS}
+
+test_docs: .stamp-tzinfo
+ cd build/dist/pytz/tests \
+ && ${PYTHON} test_docs.py ${TESTARGS} \
+ && ${PYTHON3} test_docs.py ${TESTARGS}
+
+test_zdump: dist
+ ${PYTHON} gen_tests.py ${TARGET} && \
+ ${PYTHON} test_zdump.py ${TESTARGS} && \
+ ${PYTHON3} test_zdump.py ${TESTARGS}
+
+build/dist/test_zdump.py: .stamp-zoneinfo
+
+doc: docs
+
+docs: dist
+ mkdir -p build/docs/source/.static
+ mkdir -p build/docs/built
+ cp src/README.txt build/docs/source/index.txt
+ cp conf.py build/docs/source/conf.py
+ sphinx-build build/docs/source build/docs/built
+ chmod -R og-w build/docs/built
+ chmod -R a+rX build/docs/built
+
+upload_docs: upload_docs_pythonhosted upload_docs_sf
+
+upload_docs_sf: docs
+ rsync -e ssh -ravP build/docs/built/ \
+ web.sourceforge.net:/home/project-web/pytz/htdocs/
+
+upload_docs_pythonhosted: docs
+ cd build/dist \
+ && ${PYTHON} setup.py upload_docs --upload-dir=../docs/built
+
+.stamp-tzinfo: .stamp-zoneinfo gen_tzinfo.py build/etc/zoneinfo/GMT
+ ${PYTHON} gen_tzinfo.py ${TARGET}
+ rm -rf build/dist/pytz/zoneinfo
+ cp -a build/etc/zoneinfo build/dist/pytz/zoneinfo
touch $@
-check_white_space: $(ENCHILADA)
- patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \
- ! grep -En "$$pat" \
- $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list)
- ! grep -n '[[:space:]]$$' \
- $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list)
- touch $@
-
-PRECEDES_FILE_NAME = ^(Zone|Link[[:space:]]+[^[:space:]]+)[[:space:]]+
-FILE_NAME_COMPONENT_TOO_LONG = \
- $(PRECEDES_FILE_NAME)[^[:space:]]*[^/[:space:]]{15}
-
-check_name_lengths: $(TDATA_TO_CHECK) backzone
- ! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \
- $(TDATA_TO_CHECK) backzone
- touch $@
-
-CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
-
-check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
- $(AWK) '/^Link/ {print $$3}' backward | LC_ALL=C sort -cu
- $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
- touch $@
-
-check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
- $(AWK) -f checklinks.awk $(TDATA_TO_CHECK)
- $(AWK) -f checklinks.awk tzdata.zi
- touch $@
-
-check_tables: checktab.awk $(PRIMARY_YDATA) $(ZONETABLES)
- for tab in $(ZONETABLES); do \
- $(AWK) -f checktab.awk -v zone_table=$$tab $(PRIMARY_YDATA) \
- || exit; \
- done
- touch $@
-
-check_tzs: $(TZS) $(TZS_NEW)
- if test -s $(TZS); then \
- diff -u $(TZS) $(TZS_NEW); \
- else \
- cp $(TZS_NEW) $(TZS); \
- fi
- touch $@
-
-check_web: $(CHECK_WEB_PAGES)
-check_theory.html: theory.html
-check_tz-art.html: tz-art.html
-check_tz-link.html: tz-link.html
-check_theory.html check_tz-art.html check_tz-link.html:
- $(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \
- -F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \
- test ! -s $@.out || { cat $@.out; exit 1; }
- mv $@.out $@
-check_tz-how-to.html: tz-how-to.html
- $(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) tz-how-to.html
- touch $@
-
-# Check that zishrink.awk does not alter the data, and that ziguard.awk
-# preserves main-format data.
-check_zishrink: check_zishrink_posix check_zishrink_right
-check_zishrink_posix check_zishrink_right: \
- zic leapseconds $(PACKRATDATA) $(TDATA) $(DATAFORM).zi tzdata.zi
- rm -fr $@.dir $@-t.dir $@-shrunk.dir
- mkdir $@.dir $@-t.dir $@-shrunk.dir
- case $@ in \
- *_right) leap='-L leapseconds';; \
- *) leap=;; \
- esac && \
- $(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \
- $(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \
- case $(DATAFORM) in \
- main) \
- $(ZIC) $$leap -d $@-t.dir $(TDATA) && \
- $(AWK) '/^Rule/' $(TDATA) | \
- $(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \
- diff -r $@.dir $@-t.dir;; \
- esac
- diff -r $@.dir $@-shrunk.dir
- rm -fr $@.dir $@-t.dir $@-shrunk.dir
- touch $@
-
-clean_misc:
- rm -fr check_*.dir
- rm -f *.o *.out $(TIME_T_ALTERNATIVES) \
- check_* core typecheck_* \
- date tzselect version.h zdump zic yearistype libtz.a
-clean: clean_misc
- rm -fr *.dir tzdb-*/
- rm -f *.zi $(TZS_NEW)
-
-maintainer-clean: clean
- @echo 'This command is intended for maintainers to use; it'
- @echo 'deletes files that may need special tools to rebuild.'
- rm -f leapseconds version $(MANTXTS) $(TZS) *.asc *.tar.*
-
-names:
- @echo $(ENCHILADA)
-
-public: check check_public $(CHECK_TIME_T_ALTERNATIVES) \
- tarballs signatures
-
-date.1.txt: date.1
-newctime.3.txt: newctime.3
-newstrftime.3.txt: newstrftime.3
-newtzset.3.txt: newtzset.3
-time2posix.3.txt: time2posix.3
-tzfile.5.txt: tzfile.5
-tzselect.8.txt: tzselect.8
-zdump.8.txt: zdump.8
-zic.8.txt: zic.8
-
-$(MANTXTS): workman.sh
- LC_ALL=C sh workman.sh `expr $@ : '\(.*\)\.txt$$'` >$@.out
- mv $@.out $@
-
-# Set the timestamps to those of the git repository, if available,
-# and if the files have not changed since then.
-# This uses GNU 'touch' syntax 'touch -d@N FILE',
-# where N is the number of seconds since 1970.
-# If git or GNU 'touch' is absent, don't bother to sync with git timestamps.
-# Also, set the timestamp of each prebuilt file like 'leapseconds'
-# to be the maximum of the files it depends on.
-set-timestamps.out: $(EIGHT_YARDS)
- rm -f $@
- if (type git) >/dev/null 2>&1 && \
- files=`git ls-files $(EIGHT_YARDS)` && \
- touch -md @1 test.out; then \
- rm -f test.out && \
- for file in $$files; do \
- if git diff --quiet $$file; then \
- time=`git log -1 --format='tformat:%ct' $$file` && \
- touch -cmd @$$time $$file; \
- else \
- echo >&2 "$$file: warning: does not match repository"; \
- fi || exit; \
- done; \
- fi
- touch -cmr `ls -t $(LEAP_DEPS) | sed 1q` leapseconds
- for file in `ls $(MANTXTS) | sed 's/\.txt$$//'`; do \
- touch -cmr `ls -t $$file workman.sh | sed 1q` $$file.txt || \
- exit; \
- done
- touch -cmr `ls -t $(TZDATA_ZI_DEPS) | sed 1q` tzdata.zi
- touch -cmr `ls -t $(VERSION_DEPS) | sed 1q` version
- touch $@
-set-tzs-timestamp.out: $(TZS)
- touch -cmr `ls -t $(TZS_DEPS) | sed 1q` $(TZS)
- touch $@
-
-# The zics below ensure that each data file can stand on its own.
-# We also do an all-files run to catch links to links.
-
-check_public: $(VERSION_DEPS)
- rm -fr public.dir
- mkdir public.dir
- ln $(VERSION_DEPS) public.dir
- cd public.dir && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' ALL
- for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi; do \
- public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \
- done
- public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK)
- rm -fr public.dir
- touch $@
-
-# Check that the code works under various alternative
-# implementations of time_t.
-check_time_t_alternatives: $(TIME_T_ALTERNATIVES)
-$(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD)
-$(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
- rm -fr $@.dir
- mkdir $@.dir
- ln $(VERSION_DEPS) $@.dir
- case $@ in \
- int32_t) range=-2147483648,2147483648;; \
- u*) range=0,4294967296;; \
- *) range=-4294967296,4294967296;; \
- esac && \
- wd=`pwd` && \
- zones=`$(AWK) '/^[^#]/ { print $$3 }' <zone1970.tab` && \
- if test $@ = $(TIME_T_ALTERNATIVES_HEAD); then \
- range_target=; \
- else \
- range_target=to$$range.tzs; \
- fi && \
- (cd $@.dir && \
- $(MAKE) TOPDIR="$$wd/$@.dir" \
- CFLAGS='$(CFLAGS) -Dtime_tz='"'$@'" \
- REDO='$(REDO)' \
- D=$$wd/$@.dir \
- TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
- install $$range_target) && \
- test $@ = $(TIME_T_ALTERNATIVES_HEAD) || { \
- (cd $(TIME_T_ALTERNATIVES_HEAD).dir && \
- $(MAKE) TOPDIR="$$wd/$@.dir" \
- TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
- D=$$wd/$@.dir \
- to$$range.tzs) && \
- diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
- $@.dir/to$$range.tzs && \
- if diff -q Makefile Makefile 2>/dev/null; then \
- quiet_option='-q'; \
- else \
- quiet_option=''; \
- fi && \
- diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \
- $@.dir/etc && \
- diff $$quiet_option -r \
- $(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \
- $@.dir/usr/share; \
- }
- touch $@
-
-TRADITIONAL_ASC = \
- tzcode$(VERSION).tar.gz.asc \
- tzdata$(VERSION).tar.gz.asc
-REARGUARD_ASC = \
- tzdata$(VERSION)-rearguard.tar.gz.asc
-ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \
- tzdb-$(VERSION).tar.lz.asc
-
-tarballs rearguard_tarballs traditional_tarballs \
-signatures rearguard_signatures traditional_signatures: \
- version set-timestamps.out rearguard.zi
- VERSION=`cat version` && \
- $(MAKE) VERSION="$$VERSION" $@_version
-
-# These *_version rules are intended for use if VERSION is set by some
-# other means. Ordinarily these rules are used only by the above
-# non-_version rules, which set VERSION on the 'make' command line.
-tarballs_version: traditional_tarballs_version rearguard_tarballs_version \
- tzdb-$(VERSION).tar.lz
-rearguard_tarballs_version: \
- tzdata$(VERSION)-rearguard.tar.gz
-traditional_tarballs_version: \
- tzcode$(VERSION).tar.gz tzdata$(VERSION).tar.gz
-signatures_version: $(ALL_ASC)
-rearguard_signatures_version: $(REARGUARD_ASC)
-traditional_signatures_version: $(TRADITIONAL_ASC)
-
-tzcode$(VERSION).tar.gz: set-timestamps.out
- LC_ALL=C && export LC_ALL && \
- tar $(TARFLAGS) -cf - \
- $(COMMON) $(DOCS) $(SOURCES) | \
- gzip $(GZIPFLAGS) >$@.out
- mv $@.out $@
-
-tzdata$(VERSION).tar.gz: set-timestamps.out
- LC_ALL=C && export LC_ALL && \
- tar $(TARFLAGS) -cf - $(COMMON) $(DATA) $(MISC) | \
- gzip $(GZIPFLAGS) >$@.out
- mv $@.out $@
-
-tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
- rm -fr tzdata$(VERSION)-rearguard.dir
- mkdir tzdata$(VERSION)-rearguard.dir
- ln $(COMMON) $(DATA) $(MISC) tzdata$(VERSION)-rearguard.dir
- cd tzdata$(VERSION)-rearguard.dir && \
- rm -f $(TDATA) $(PACKRATDATA) version
- for f in $(TDATA) $(PACKRATDATA); do \
- rearf=tzdata$(VERSION)-rearguard.dir/$$f; \
- $(AWK) -v DATAFORM=rearguard -f ziguard.awk $$f >$$rearf && \
- touch -cmr `ls -t ziguard.awk $$f` $$rearf || exit; \
- done
- sed '1s/$$/-rearguard/' \
- <version >tzdata$(VERSION)-rearguard.dir/version
- touch -cmr version tzdata$(VERSION)-rearguard.dir/version
- LC_ALL=C && export LC_ALL && \
- (cd tzdata$(VERSION)-rearguard.dir && \
- tar $(TARFLAGS) -cf - $(COMMON) $(DATA) $(MISC) | \
- gzip $(GZIPFLAGS)) >$@.out
- mv $@.out $@
-
-tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
- rm -fr tzdb-$(VERSION)
- mkdir tzdb-$(VERSION)
- ln $(ENCHILADA) tzdb-$(VERSION)
- touch -cmr `ls -t tzdb-$(VERSION)/* | sed 1q` tzdb-$(VERSION)
- LC_ALL=C && export LC_ALL && \
- tar $(TARFLAGS) -cf - tzdb-$(VERSION) | lzip -9 >$@.out
- mv $@.out $@
-
-tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz
-tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz
-tzdata$(VERSION)-rearguard.tar.gz.asc: tzdata$(VERSION)-rearguard.tar.gz
-tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz
-$(ALL_ASC):
- $(GPG) --armor --detach-sign $?
-
-TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T
-typecheck: typecheck_long_long typecheck_unsigned
-typecheck_long_long typecheck_unsigned: $(VERSION_DEPS)
- rm -fr $@.dir
- mkdir $@.dir
- ln $(VERSION_DEPS) $@.dir
- cd $@.dir && \
- case $@ in \
- *_long_long) i="long long";; \
- *_unsigned ) i="unsigned" ;; \
- esac && \
- typecheck_cflags='' && \
- $(MAKE) \
- CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \
- TOPDIR="`pwd`" \
- install
- $@.dir/zdump -i -c 1970,1971 Europe/Rome
- touch $@
-
-zonenames: tzdata.zi
- @$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi
+.stamp-zoneinfo:
+ ${MAKE} -C ${IANA} TOPDIR=`pwd`/build USRDIR= USRSHAREDIR=etc install
+ # Break hard links, working around http://bugs.python.org/issue8876.
+ for d in zoneinfo zoneinfo-leaps zoneinfo-posix; do \
+ rm -rf `pwd`/build/etc/$$d.tmp; \
+ rsync -a `pwd`/build/etc/$$d/ `pwd`/build/etc/$$d.tmp; \
+ rm -rf `pwd`/build/etc/$$d; \
+ mv `pwd`/build/etc/$$d.tmp `pwd`/build/etc/$$d; \
+ done
+ touch $@
-asctime.o: private.h tzfile.h
-date.o: private.h
-difftime.o: private.h
-localtime.o: private.h tzfile.h
-strftime.o: private.h tzfile.h
-zdump.o: version.h
-zic.o: private.h tzfile.h version.h
+build/dist/locales/pytz.pot: .stamp-tzinfo
+ @: #${PYTHON} gen_pot.py build/dist/pytz/locales/pytz.pot
-.KEEP_STATE:
+# cd build/dist; mkdir locales; \
+# pygettext --extract-all --no-location \
+# --default-domain=pytz --output-dir=locales
-.PHONY: ALL INSTALL all
-.PHONY: check check_time_t_alternatives
-.PHONY: check_web check_zishrink
-.PHONY: clean clean_misc dummy.zd force_tzs
-.PHONY: install install_data maintainer-clean names
-.PHONY: posix_only posix_packrat posix_right public
-.PHONY: rearguard_signatures rearguard_signatures_version
-.PHONY: rearguard_tarballs rearguard_tarballs_version
-.PHONY: right_only right_posix signatures signatures_version
-.PHONY: tarballs tarballs_version
-.PHONY: traditional_signatures traditional_signatures_version
-.PHONY: traditional_tarballs traditional_tarballs_version
-.PHONY: typecheck
-.PHONY: zonenames zones
-.PHONY: $(ZDS)
+# Switch to using a git subtree of https://github.com/eggert/tz
+#
+# IANA_URL=http://www.iana.org/time-zones/repository
+#
+# sync:
+# cd elsie.nci.nih.gov && \
+# rm -f tz{code,data}-latest.tar.gz{,.asc} && \
+# wget -S ${IANA_URL}/tzcode-latest.tar.gz && \
+# wget -S ${IANA_URL}/tzcode-latest.tar.gz.asc && \
+# gpg --verify tzcode-latest.tar.gz.asc tzcode-latest.tar.gz && \
+# wget -S ${IANA_URL}/tzdata-latest.tar.gz && \
+# wget -S ${IANA_URL}/tzdata-latest.tar.gz.asc && \
+# gpg --verify tzdata-latest.tar.gz.asc tzdata-latest.tar.gz && \
+# cd src && \
+# tar xzf ../tzcode-latest.tar.gz && \
+# tar xzf ../tzdata-latest.tar.gz && \
+# echo Done
+
+sync: _sync clean
+
+_sync:
+ if [ -n "$(TAG)" ]; then \
+ git subtree pull --prefix=tz --squash $(IANA_GIT) $(TAG) \
+ -m "IANA $(TAG)"; \
+ else \
+ echo "Usage: make sync TAG=2016f"; \
+ fi
+
+.PHONY: all check dist test test_tzinfo test_docs test_zdump wheels build clean sync _sync
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..f63a900
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,14 @@
+
+Brings the IANA tz database into Python. This library allows accurate and
+cross platform timezone calculations.
+
+More information in src/README.txt
+
+Release process;
+
+ 1) Untar upstream tarballs into elsie/src
+ 2) Update VERSION & OLSON_VERSION in src/pytz/__init__.py, and EXPECTED_VERSION in
+ src/pytz/tests/test_tzinfo.py
+ 3) make test
+ 4) make dist
+
diff --git a/conf.py b/conf.py
new file mode 100644
index 0000000..036b07e
--- /dev/null
+++ b/conf.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+#
+# pytz documentation build configuration file, created by
+# sphinx-quickstart on Sat Oct 11 19:39:58 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os.path
+sys.path.insert(0, os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, 'dist'))
+import pytz
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.txt'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = u'pytz'
+copyright = u'2008, Stuart Bishop'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = pytz.__version__
+# The full version, including alpha/beta/rc tags.
+release = pytz.__version__
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+exclude_trees = ['.build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+html_file_suffix = '.html'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pytzdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'pytz.tex', u'pytz Documentation',
+ u'Stuart Bishop', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/deps.txt b/deps.txt
new file mode 100644
index 0000000..ecd457a
--- /dev/null
+++ b/deps.txt
@@ -0,0 +1,18 @@
+dev container setup cheat sheet
+-------------------------------
+
+locale-gen
+add-apt-repository ppa:deadsnakes/ppa
+
+apt update
+apt install tox bzr build-essential twine python-all python-all-dev python3-all python3-all-dev python3-docutils python3-sphinx python3-flake8 python-flake8 python2.4-complete python2.5-complete python2.6-complete python3.1-complete python3.2-complete python3.3-complete python3.4-complete python3.5 python3.5-dev python3.7 python3.7-dev python-wheel python3-wheel python-pip python3-pip
+
+
+wget https://raw.githubusercontent.com/pypa/setuptools/bootstrap-py24/ez_setup.py -O - | python2.4
+wget https://raw.githubusercontent.com/pypa/setuptools/bootstrap-py24/ez_setup.py -O - | python2.5
+wget https://bootstrap.pypa.io/ez_setup.py -O - | python2.6
+wget https://bootstrap.pypa.io/ez_setup.py -O - | python3.1
+wget https://bootstrap.pypa.io/ez_setup.py -O - | python3.2
+wget https://bootstrap.pypa.io/ez_setup.py -O - | python3.3
+wget https://bootstrap.pypa.io/ez_setup.py -O - | python3.4
+
diff --git a/gen_pot.py b/gen_pot.py
new file mode 100644
index 0000000..a2358d0
--- /dev/null
+++ b/gen_pot.py
@@ -0,0 +1,38 @@
+import sys
+import os.path
+import time
+from gen_tzinfo import allzones
+
+from pytz import __version__
+
+boilerplate = r"""msgid ""
+msgstr ""
+"Project-Id-Version: pytz %s\n"
+"POT-Creation-Date: %s\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+
+""" % (
+ __version__,
+ time.strftime('%Y-%m-%d %H:%M+UTC', time.gmtime(time.time()))
+)
+
+
+def main():
+ assert len(sys.argv) == 2, 'Output file not specified on command line'
+ pot_file_name = sys.argv[1]
+
+ if not os.path.exists(os.path.dirname(pot_file_name)):
+ os.makedirs(os.path.dirname(pot_file_name))
+
+ pot = open(pot_file_name, 'wb')
+
+ print >> pot, boilerplate
+
+ for zone in allzones():
+ print >> pot, 'msgid "%s"' % zone
+ print >> pot, 'msgstr ""'
+ print >> pot
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gen_tests.py b/gen_tests.py
new file mode 100644
index 0000000..cff1204
--- /dev/null
+++ b/gen_tests.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# -*- coding: ascii -*-
+'''
+$Id: gen_tests.py,v 1.15 2005/01/07 04:51:30 zenzen Exp $
+'''
+
+import os
+import os.path
+import subprocess
+import sys
+from gen_tzinfo import allzones
+import gen_tzinfo
+
+zdump = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), 'build', 'bin', 'zdump'
+))
+
+
+def main():
+ dest_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
+
+ datf = open(os.path.join(dest_dir, 'zdump.out'), 'w')
+
+ for zone in allzones():
+ print('Collecting zdump(1) output for %s in zdump.out' % (zone,))
+ # We don't yet support v2 format tzfile(5) files, so limit
+ # the daterange we test against - zdump understands v2 format
+ # files and will output historical records we can't cope with
+ # otherwise.
+ command = [zdump, '-v', '-c', '1902,2038', zone]
+ zd_out = subprocess.check_output(command)
+ # Skip bogus output on 64bit architectures, per Bug #213816
+ lines = [
+ line.strip() for line in zd_out.splitlines()
+ if not line.decode('utf-8').strip().endswith('NULL')]
+
+ for line in lines:
+ print >> datf, line
+ datf.flush()
+ datf.close()
+
+if __name__ == '__main__':
+ try:
+ gen_tzinfo.target = sys.argv[1:]
+ except IndexError:
+ gen_tzinfo.target = None
+ main()
+
+# vim: set filetype=python ts=4 sw=4 et
diff --git a/gen_tzinfo.py b/gen_tzinfo.py
new file mode 100644
index 0000000..d06fa0e
--- /dev/null
+++ b/gen_tzinfo.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+'''
+$Id: gen_tzinfo.py,v 1.21 2005/02/15 20:21:38 zenzen Exp $
+'''
+import sys
+import os
+import os.path
+import shutil
+
+from glob import glob
+from pprint import pprint
+import re
+
+zoneinfo = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), 'build', 'etc', 'zoneinfo'
+))
+
+
+def allzones():
+ ''' Return all available tzfile(5) files in the zoneinfo database '''
+ zones = []
+ for dirpath, dirnames, filenames in os.walk(zoneinfo):
+ for f in filenames:
+ p = os.path.join(dirpath, f)
+ if open(p, 'rb').read(4) == 'TZif':
+ zones.append(p)
+ stripnum = len(os.path.commonprefix(zones))
+ zones = [z[stripnum:] for z in zones]
+
+ if target:
+ wanted = target + ['US/Eastern', 'UTC']
+ zones = [z for z in zones if z in wanted]
+ # Does not cope with Riyadh87-89 - it appears this region went
+ # on solar time during this period and their DST offset changed
+ # minute to minute (the Olson database could only capture a precision
+ # of 5 seconds because of way too many zone changes, so the data isn't
+ # 100% accurate anyway).
+ # 'Factory' and 'localtime' appear to be Olson reference code specific
+ # and are skipped
+ zones = [z for z in zones if 'Riyadh8' not in z and z not in [
+ 'Factory', 'localtime', 'posixrules']]
+ zones.sort()
+ return zones
+
+
+def links():
+ '''Mapping of alias -> canonical name'''
+ l = {}
+ olson_src_files = glob('tz/*')
+ assert olson_src_files, 'No src files'
+ for filename in olson_src_files:
+ # Filenames containing a '.' are not data files.
+ if '.' in os.path.basename(filename):
+ continue
+ for line in open(filename):
+ if line.strip().startswith('#') or not line.strip():
+ continue
+ match = re.search(r'^\s*Link\s+([\w/\-]+)\s+([\w/\-]+)', line)
+ if match is not None:
+ new_name = match.group(1)
+ old_name = match.group(2)
+ l[old_name] = new_name
+ else:
+ assert not line.startswith('Link'), line
+ assert 'US/Pacific-New' in l, 'US/Pacific-New should be in links()'
+ return l
+
+
+def dupe_src(destdir):
+ ''' Copy ./src to our dest directory '''
+ if not os.path.isdir(destdir):
+ os.makedirs(destdir)
+ for f in glob(os.path.join('src', '*')):
+ if not os.path.isdir(f):
+ shutil.copy(f, destdir)
+
+ destdir = os.path.join(destdir, 'pytz')
+ if not os.path.isdir(destdir):
+ os.makedirs(destdir)
+ for f in glob(os.path.join('src', 'pytz', '*')):
+ if not os.path.isdir(f):
+ shutil.copy(f, destdir)
+
+ destdir = os.path.join(destdir, 'tests')
+ if not os.path.isdir(destdir):
+ os.makedirs(destdir)
+ for f in glob(os.path.join('src', 'pytz', 'tests', '*')):
+ if not os.path.isdir(f):
+ shutil.copy(f, destdir)
+
+
+def add_allzones(filename):
+ ''' Append a list of all know timezones to the end of the file '''
+ outf = open(filename, 'a')
+
+ obsolete_zones = links().keys()
+
+ # Calculate 'common' timezones as best we can. We start with all
+ # timezones, strip out the legacy noise, and any name linked to
+ # a more canonical name (eg. Asia/Singapore is preferred to just
+ # Singapore)
+ cz = [
+ z for z in allzones()
+ if (z not in obsolete_zones and
+ '/' in z and
+ not z.startswith('SystemV/') and
+ not z.startswith('Etc/'))]
+ # And extend our list manually with stuff we think deserves to be
+ # labelled 'common'.
+ cz.extend([
+ 'UTC', 'GMT', 'US/Eastern', 'US/Pacific', 'US/Mountain',
+ 'US/Central', 'US/Arizona', 'US/Hawaii', 'US/Alaska',
+ # Canadian timezones per Bug #506341
+ 'Canada/Newfoundland', 'Canada/Atlantic', 'Canada/Eastern',
+ 'Canada/Central', 'Canada/Mountain', 'Canada/Pacific'])
+ # And extend out list with all preferred country timezones.
+ zone_tab = open(os.path.join(zoneinfo, 'zone.tab'), 'r')
+ for line in zone_tab:
+ if line.startswith('#'):
+ continue
+ code, coordinates, zone = line.split(None, 4)[:3]
+ if zone not in cz:
+ cz.append(zone)
+ cz.sort()
+
+ print >> outf, 'all_timezones = \\'
+ pprint(sorted(allzones()), outf)
+ print >> outf, '''all_timezones = LazyList(
+ tz for tz in all_timezones if resource_exists(tz))
+ '''
+ print >> outf, 'all_timezones_set = LazySet(all_timezones)'
+ print >> outf, '_all_timezones_lower_to_standard = dict((tz.lower(), tz) for tz in all_timezones)'
+
+ print >> outf, 'common_timezones = \\'
+ pprint(cz, outf)
+ print >> outf, '''common_timezones = LazyList(
+ tz for tz in common_timezones if tz in all_timezones)
+ '''
+ print >> outf, 'common_timezones_set = LazySet(common_timezones)'
+
+ outf.close()
+
+
+def main(destdir):
+ _destdir = os.path.join(os.path.abspath(destdir), 'dist')
+
+ dupe_src(_destdir)
+ add_allzones(os.path.join(_destdir, 'pytz', '__init__.py'))
+
+target = None
+if __name__ == '__main__':
+ try:
+ target = sys.argv[1:]
+ except IndexError:
+ target = None
+ main('build')
diff --git a/src/LICENSE.txt b/src/LICENSE.txt
new file mode 100644
index 0000000..7c901fd
--- /dev/null
+++ b/src/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2003-2018 Stuart Bishop <stuart@stuartbishop.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/MANIFEST.in b/src/MANIFEST.in
new file mode 100644
index 0000000..fda34e2
--- /dev/null
+++ b/src/MANIFEST.in
@@ -0,0 +1,5 @@
+include *.txt setup.py
+recursive-include pytz *.py
+#recursive-include pytz *.pot
+graft pytz/zoneinfo
+#exclude test_zdump.py
diff --git a/src/README.txt b/src/README.txt
new file mode 100644
index 0000000..b37acf0
--- /dev/null
+++ b/src/README.txt
@@ -0,0 +1,582 @@
+pytz - World Timezone Definitions for Python
+============================================
+
+:Author: Stuart Bishop <stuart@stuartbishop.net>
+
+Introduction
+~~~~~~~~~~~~
+
+pytz brings the Olson tz database into Python. This library allows
+accurate and cross platform timezone calculations using Python 2.4
+or higher. It also solves the issue of ambiguous times at the end
+of daylight saving time, which you can read more about in the Python
+Library Reference (``datetime.tzinfo``).
+
+Almost all of the Olson timezones are supported.
+
+.. note::
+
+ This library differs from the documented Python API for
+ tzinfo implementations; if you want to create local wallclock
+ times you need to use the ``localize()`` method documented in this
+ document. In addition, if you perform date arithmetic on local
+ times that cross DST boundaries, the result may be in an incorrect
+ timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get
+ 2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A
+ ``normalize()`` method is provided to correct this. Unfortunately these
+ issues cannot be resolved without modifying the Python datetime
+ implementation (see PEP-431).
+
+
+Installation
+~~~~~~~~~~~~
+
+This package can either be installed using ``pip`` or from a tarball using the
+standard Python distutils.
+
+If you are installing using ``pip``, you don't need to download anything as the
+latest version will be downloaded for you from PyPI::
+
+ pip install pytz
+
+If you are installing from a tarball, run the following command as an
+administrative user::
+
+ python setup.py install
+
+
+Example & Usage
+~~~~~~~~~~~~~~~
+
+Localized times and date arithmetic
+-----------------------------------
+
+>>> from datetime import datetime, timedelta
+>>> from pytz import timezone
+>>> import pytz
+>>> utc = pytz.utc
+>>> utc.zone
+'UTC'
+>>> eastern = timezone('US/Eastern')
+>>> eastern.zone
+'US/Eastern'
+>>> amsterdam = timezone('Europe/Amsterdam')
+>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z'
+
+This library only supports two ways of building a localized time. The
+first is to use the ``localize()`` method provided by the pytz library.
+This is used to localize a naive datetime (datetime with no timezone
+information):
+
+>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
+>>> print(loc_dt.strftime(fmt))
+2002-10-27 06:00:00 EST-0500
+
+The second way of building a localized time is by converting an existing
+localized time using the standard ``astimezone()`` method:
+
+>>> ams_dt = loc_dt.astimezone(amsterdam)
+>>> ams_dt.strftime(fmt)
+'2002-10-27 12:00:00 CET+0100'
+
+Unfortunately using the tzinfo argument of the standard datetime
+constructors ''does not work'' with pytz for many timezones.
+
+>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) # /!\ Does not work this way!
+'2002-10-27 12:00:00 LMT+0020'
+
+It is safe for timezones without daylight saving transitions though, such
+as UTC:
+
+>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) # /!\ Not recommended except for UTC
+'2002-10-27 12:00:00 UTC+0000'
+
+The preferred way of dealing with times is to always work in UTC,
+converting to localtime only when generating output to be read
+by humans.
+
+>>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
+>>> loc_dt = utc_dt.astimezone(eastern)
+>>> loc_dt.strftime(fmt)
+'2002-10-27 01:00:00 EST-0500'
+
+This library also allows you to do date arithmetic using local
+times, although it is more complicated than working in UTC as you
+need to use the ``normalize()`` method to handle daylight saving time
+and other timezone transitions. In this example, ``loc_dt`` is set
+to the instant when daylight saving time ends in the US/Eastern
+timezone.
+
+>>> before = loc_dt - timedelta(minutes=10)
+>>> before.strftime(fmt)
+'2002-10-27 00:50:00 EST-0500'
+>>> eastern.normalize(before).strftime(fmt)
+'2002-10-27 01:50:00 EDT-0400'
+>>> after = eastern.normalize(before + timedelta(minutes=20))
+>>> after.strftime(fmt)
+'2002-10-27 01:10:00 EST-0500'
+
+Creating local times is also tricky, and the reason why working with
+local times is not recommended. Unfortunately, you cannot just pass
+a ``tzinfo`` argument when constructing a datetime (see the next
+section for more details)
+
+>>> dt = datetime(2002, 10, 27, 1, 30, 0)
+>>> dt1 = eastern.localize(dt, is_dst=True)
+>>> dt1.strftime(fmt)
+'2002-10-27 01:30:00 EDT-0400'
+>>> dt2 = eastern.localize(dt, is_dst=False)
+>>> dt2.strftime(fmt)
+'2002-10-27 01:30:00 EST-0500'
+
+Converting between timezones is more easily done, using the
+standard astimezone method.
+
+>>> utc_dt = utc.localize(datetime.utcfromtimestamp(1143408899))
+>>> utc_dt.strftime(fmt)
+'2006-03-26 21:34:59 UTC+0000'
+>>> au_tz = timezone('Australia/Sydney')
+>>> au_dt = utc_dt.astimezone(au_tz)
+>>> au_dt.strftime(fmt)
+'2006-03-27 08:34:59 AEDT+1100'
+>>> utc_dt2 = au_dt.astimezone(utc)
+>>> utc_dt2.strftime(fmt)
+'2006-03-26 21:34:59 UTC+0000'
+>>> utc_dt == utc_dt2
+True
+
+You can take shortcuts when dealing with the UTC side of timezone
+conversions. ``normalize()`` and ``localize()`` are not really
+necessary when there are no daylight saving time transitions to
+deal with.
+
+>>> utc_dt = datetime.utcfromtimestamp(1143408899).replace(tzinfo=utc)
+>>> utc_dt.strftime(fmt)
+'2006-03-26 21:34:59 UTC+0000'
+>>> au_tz = timezone('Australia/Sydney')
+>>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz))
+>>> au_dt.strftime(fmt)
+'2006-03-27 08:34:59 AEDT+1100'
+>>> utc_dt2 = au_dt.astimezone(utc)
+>>> utc_dt2.strftime(fmt)
+'2006-03-26 21:34:59 UTC+0000'
+
+
+``tzinfo`` API
+--------------
+
+The ``tzinfo`` instances returned by the ``timezone()`` function have
+been extended to cope with ambiguous times by adding an ``is_dst``
+parameter to the ``utcoffset()``, ``dst()`` && ``tzname()`` methods.
+
+>>> tz = timezone('America/St_Johns')
+
+>>> normal = datetime(2009, 9, 1)
+>>> ambiguous = datetime(2009, 10, 31, 23, 30)
+
+The ``is_dst`` parameter is ignored for most timestamps. It is only used
+during DST transition ambiguous periods to resolve that ambiguity.
+
+>>> tz.utcoffset(normal, is_dst=True)
+datetime.timedelta(-1, 77400)
+>>> tz.dst(normal, is_dst=True)
+datetime.timedelta(0, 3600)
+>>> tz.tzname(normal, is_dst=True)
+'NDT'
+
+>>> tz.utcoffset(ambiguous, is_dst=True)
+datetime.timedelta(-1, 77400)
+>>> tz.dst(ambiguous, is_dst=True)
+datetime.timedelta(0, 3600)
+>>> tz.tzname(ambiguous, is_dst=True)
+'NDT'
+
+>>> tz.utcoffset(normal, is_dst=False)
+datetime.timedelta(-1, 77400)
+>>> tz.dst(normal, is_dst=False)
+datetime.timedelta(0, 3600)
+>>> tz.tzname(normal, is_dst=False)
+'NDT'
+
+>>> tz.utcoffset(ambiguous, is_dst=False)
+datetime.timedelta(-1, 73800)
+>>> tz.dst(ambiguous, is_dst=False)
+datetime.timedelta(0)
+>>> tz.tzname(ambiguous, is_dst=False)
+'NST'
+
+If ``is_dst`` is not specified, ambiguous timestamps will raise
+an ``pytz.exceptions.AmbiguousTimeError`` exception.
+
+>>> tz.utcoffset(normal)
+datetime.timedelta(-1, 77400)
+>>> tz.dst(normal)
+datetime.timedelta(0, 3600)
+>>> tz.tzname(normal)
+'NDT'
+
+>>> import pytz.exceptions
+>>> try:
+... tz.utcoffset(ambiguous)
+... except pytz.exceptions.AmbiguousTimeError:
+... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
+pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
+>>> try:
+... tz.dst(ambiguous)
+... except pytz.exceptions.AmbiguousTimeError:
+... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
+pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
+>>> try:
+... tz.tzname(ambiguous)
+... except pytz.exceptions.AmbiguousTimeError:
+... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
+pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
+
+
+Problems with Localtime
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The major problem we have to deal with is that certain datetimes
+may occur twice in a year. For example, in the US/Eastern timezone
+on the last Sunday morning in October, the following sequence
+happens:
+
+ - 01:00 EDT occurs
+ - 1 hour later, instead of 2:00am the clock is turned back 1 hour
+ and 01:00 happens again (this time 01:00 EST)
+
+In fact, every instant between 01:00 and 02:00 occurs twice. This means
+that if you try and create a time in the 'US/Eastern' timezone
+the standard datetime syntax, there is no way to specify if you meant
+before of after the end-of-daylight-saving-time transition. Using the
+pytz custom syntax, the best you can do is make an educated guess:
+
+>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 1, 30, 00))
+>>> loc_dt.strftime(fmt)
+'2002-10-27 01:30:00 EST-0500'
+
+As you can see, the system has chosen one for you and there is a 50%
+chance of it being out by one hour. For some applications, this does
+not matter. However, if you are trying to schedule meetings with people
+in different timezones or analyze log files it is not acceptable.
+
+The best and simplest solution is to stick with using UTC. The pytz
+package encourages using UTC for internal timezone representation by
+including a special UTC implementation based on the standard Python
+reference implementation in the Python documentation.
+
+The UTC timezone unpickles to be the same instance, and pickles to a
+smaller size than other pytz tzinfo instances. The UTC implementation
+can be obtained as pytz.utc, pytz.UTC, or pytz.timezone('UTC').
+
+>>> import pickle, pytz
+>>> dt = datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc)
+>>> naive = dt.replace(tzinfo=None)
+>>> p = pickle.dumps(dt, 1)
+>>> naive_p = pickle.dumps(naive, 1)
+>>> len(p) - len(naive_p)
+17
+>>> new = pickle.loads(p)
+>>> new == dt
+True
+>>> new is dt
+False
+>>> new.tzinfo is dt.tzinfo
+True
+>>> pytz.utc is pytz.UTC is pytz.timezone('UTC')
+True
+
+Note that some other timezones are commonly thought of as the same (GMT,
+Greenwich, Universal, etc.). The definition of UTC is distinct from these
+other timezones, and they are not equivalent. For this reason, they will
+not compare the same in Python.
+
+>>> utc == pytz.timezone('GMT')
+False
+
+See the section `What is UTC`_, below.
+
+If you insist on working with local times, this library provides a
+facility for constructing them unambiguously:
+
+>>> loc_dt = datetime(2002, 10, 27, 1, 30, 00)
+>>> est_dt = eastern.localize(loc_dt, is_dst=True)
+>>> edt_dt = eastern.localize(loc_dt, is_dst=False)
+>>> print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt))
+2002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500
+
+If you pass None as the is_dst flag to localize(), pytz will refuse to
+guess and raise exceptions if you try to build ambiguous or non-existent
+times.
+
+For example, 1:30am on 27th Oct 2002 happened twice in the US/Eastern
+timezone when the clocks where put back at the end of Daylight Saving
+Time:
+
+>>> dt = datetime(2002, 10, 27, 1, 30, 00)
+>>> try:
+... eastern.localize(dt, is_dst=None)
+... except pytz.exceptions.AmbiguousTimeError:
+... print('pytz.exceptions.AmbiguousTimeError: %s' % dt)
+pytz.exceptions.AmbiguousTimeError: 2002-10-27 01:30:00
+
+Similarly, 2:30am on 7th April 2002 never happened at all in the
+US/Eastern timezone, as the clocks where put forward at 2:00am skipping
+the entire hour:
+
+>>> dt = datetime(2002, 4, 7, 2, 30, 00)
+>>> try:
+... eastern.localize(dt, is_dst=None)
+... except pytz.exceptions.NonExistentTimeError:
+... print('pytz.exceptions.NonExistentTimeError: %s' % dt)
+pytz.exceptions.NonExistentTimeError: 2002-04-07 02:30:00
+
+Both of these exceptions share a common base class to make error handling
+easier:
+
+>>> isinstance(pytz.AmbiguousTimeError(), pytz.InvalidTimeError)
+True
+>>> isinstance(pytz.NonExistentTimeError(), pytz.InvalidTimeError)
+True
+
+
+A special case is where countries change their timezone definitions
+with no daylight savings time switch. For example, in 1915 Warsaw
+switched from Warsaw time to Central European time with no daylight savings
+transition. So at the stroke of midnight on August 5th 1915 the clocks
+were wound back 24 minutes creating an ambiguous time period that cannot
+be specified without referring to the timezone abbreviation or the
+actual UTC offset. In this case midnight happened twice, neither time
+during a daylight saving time period. pytz handles this transition by
+treating the ambiguous period before the switch as daylight savings
+time, and the ambiguous period after as standard time.
+
+
+>>> warsaw = pytz.timezone('Europe/Warsaw')
+>>> amb_dt1 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=True)
+>>> amb_dt1.strftime(fmt)
+'1915-08-04 23:59:59 WMT+0124'
+>>> amb_dt2 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=False)
+>>> amb_dt2.strftime(fmt)
+'1915-08-04 23:59:59 CET+0100'
+>>> switch_dt = warsaw.localize(datetime(1915, 8, 5, 00, 00, 00), is_dst=False)
+>>> switch_dt.strftime(fmt)
+'1915-08-05 00:00:00 CET+0100'
+>>> str(switch_dt - amb_dt1)
+'0:24:01'
+>>> str(switch_dt - amb_dt2)
+'0:00:01'
+
+The best way of creating a time during an ambiguous time period is
+by converting from another timezone such as UTC:
+
+>>> utc_dt = datetime(1915, 8, 4, 22, 36, tzinfo=pytz.utc)
+>>> utc_dt.astimezone(warsaw).strftime(fmt)
+'1915-08-04 23:36:00 CET+0100'
+
+The standard Python way of handling all these ambiguities is not to
+handle them, such as demonstrated in this example using the US/Eastern
+timezone definition from the Python documentation (Note that this
+implementation only works for dates between 1987 and 2006 - it is
+included for tests only!):
+
+>>> from pytz.reference import Eastern # pytz.reference only for tests
+>>> dt = datetime(2002, 10, 27, 0, 30, tzinfo=Eastern)
+>>> str(dt)
+'2002-10-27 00:30:00-04:00'
+>>> str(dt + timedelta(hours=1))
+'2002-10-27 01:30:00-05:00'
+>>> str(dt + timedelta(hours=2))
+'2002-10-27 02:30:00-05:00'
+>>> str(dt + timedelta(hours=3))
+'2002-10-27 03:30:00-05:00'
+
+Notice the first two results? At first glance you might think they are
+correct, but taking the UTC offset into account you find that they are
+actually two hours appart instead of the 1 hour we asked for.
+
+>>> from pytz.reference import UTC # pytz.reference only for tests
+>>> str(dt.astimezone(UTC))
+'2002-10-27 04:30:00+00:00'
+>>> str((dt + timedelta(hours=1)).astimezone(UTC))
+'2002-10-27 06:30:00+00:00'
+
+
+Country Information
+~~~~~~~~~~~~~~~~~~~
+
+A mechanism is provided to access the timezones commonly in use
+for a particular country, looked up using the ISO 3166 country code.
+It returns a list of strings that can be used to retrieve the relevant
+tzinfo instance using ``pytz.timezone()``:
+
+>>> print(' '.join(pytz.country_timezones['nz']))
+Pacific/Auckland Pacific/Chatham
+
+The Olson database comes with a ISO 3166 country code to English country
+name mapping that pytz exposes as a dictionary:
+
+>>> print(pytz.country_names['nz'])
+New Zealand
+
+
+What is UTC
+~~~~~~~~~~~
+
+'UTC' is `Coordinated Universal Time`_. It is a successor to, but distinct
+from, Greenwich Mean Time (GMT) and the various definitions of Universal
+Time. UTC is now the worldwide standard for regulating clocks and time
+measurement.
+
+All other timezones are defined relative to UTC, and include offsets like
+UTC+0800 - hours to add or subtract from UTC to derive the local time. No
+daylight saving time occurs in UTC, making it a useful timezone to perform
+date arithmetic without worrying about the confusion and ambiguities caused
+by daylight saving time transitions, your country changing its timezone, or
+mobile computers that roam through multiple timezones.
+
+.. _Coordinated Universal Time: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
+
+
+Helpers
+~~~~~~~
+
+There are two lists of timezones provided.
+
+``all_timezones`` is the exhaustive list of the timezone names that can
+be used.
+
+>>> from pytz import all_timezones
+>>> len(all_timezones) >= 500
+True
+>>> 'Etc/Greenwich' in all_timezones
+True
+
+``common_timezones`` is a list of useful, current timezones. It doesn't
+contain deprecated zones or historical zones, except for a few I've
+deemed in common usage, such as US/Eastern (open a bug report if you
+think other timezones are deserving of being included here). It is also
+a sequence of strings.
+
+>>> from pytz import common_timezones
+>>> len(common_timezones) < len(all_timezones)
+True
+>>> 'Etc/Greenwich' in common_timezones
+False
+>>> 'Australia/Melbourne' in common_timezones
+True
+>>> 'US/Eastern' in common_timezones
+True
+>>> 'Canada/Eastern' in common_timezones
+True
+>>> 'Australia/Yancowinna' in all_timezones
+True
+>>> 'Australia/Yancowinna' in common_timezones
+False
+
+Both ``common_timezones`` and ``all_timezones`` are alphabetically
+sorted:
+
+>>> common_timezones_dupe = common_timezones[:]
+>>> common_timezones_dupe.sort()
+>>> common_timezones == common_timezones_dupe
+True
+>>> all_timezones_dupe = all_timezones[:]
+>>> all_timezones_dupe.sort()
+>>> all_timezones == all_timezones_dupe
+True
+
+``all_timezones`` and ``common_timezones`` are also available as sets.
+
+>>> from pytz import all_timezones_set, common_timezones_set
+>>> 'US/Eastern' in all_timezones_set
+True
+>>> 'US/Eastern' in common_timezones_set
+True
+>>> 'Australia/Victoria' in common_timezones_set
+False
+
+You can also retrieve lists of timezones used by particular countries
+using the ``country_timezones()`` function. It requires an ISO-3166
+two letter country code.
+
+>>> from pytz import country_timezones
+>>> print(' '.join(country_timezones('ch')))
+Europe/Zurich
+>>> print(' '.join(country_timezones('CH')))
+Europe/Zurich
+
+
+Internationalization - i18n/l10n
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pytz is an interface to the IANA database, which uses ASCII names. The `Unicode Consortium's Unicode Locales (CLDR) <http://cldr.unicode.org>`_
+project provides translations. Thomas Khyn's
+`l18n <https://pypi.org/project/l18n/>`_ package can be used to access
+these translations from Python.
+
+
+License
+~~~~~~~
+
+MIT license.
+
+This code is also available as part of Zope 3 under the Zope Public
+License, Version 2.1 (ZPL).
+
+I'm happy to relicense this code if necessary for inclusion in other
+open source projects.
+
+
+Latest Versions
+~~~~~~~~~~~~~~~
+
+This package will be updated after releases of the Olson timezone
+database. The latest version can be downloaded from the `Python Package
+Index <https://pypi.org/project/pytz/>`_. The code that is used
+to generate this distribution is hosted on launchpad.net and available
+using git::
+
+ git clone https://git.launchpad.net/pytz
+
+A mirror on github is also available at https://github.com/stub42/pytz
+
+Announcements of new releases are made on
+`Launchpad <https://launchpad.net/pytz>`_, and the
+`Atom feed <http://feeds.launchpad.net/pytz/announcements.atom>`_
+hosted there.
+
+
+Bugs, Feature Requests & Patches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Bugs can be reported using `Launchpad <https://bugs.launchpad.net/pytz>`__.
+
+
+Issues & Limitations
+~~~~~~~~~~~~~~~~~~~~
+
+- Offsets from UTC are rounded to the nearest whole minute, so timezones
+ such as Europe/Amsterdam pre 1937 will be up to 30 seconds out. This
+ is a limitation of the Python datetime library.
+
+- If you think a timezone definition is incorrect, I probably can't fix
+ it. pytz is a direct translation of the Olson timezone database, and
+ changes to the timezone definitions need to be made to this source.
+ If you find errors they should be reported to the time zone mailing
+ list, linked from http://www.iana.org/time-zones.
+
+
+Further Reading
+~~~~~~~~~~~~~~~
+
+More info than you want to know about timezones:
+http://www.twinsun.com/tz/tz-link.htm
+
+
+Contact
+~~~~~~~
+
+Stuart Bishop <stuart@stuartbishop.net>
+
+
diff --git a/src/pytz/__init__.py b/src/pytz/__init__.py
new file mode 100644
index 0000000..5c05066
--- /dev/null
+++ b/src/pytz/__init__.py
@@ -0,0 +1,503 @@
+'''
+datetime.tzinfo timezone definitions generated from the
+Olson timezone database:
+
+ ftp://elsie.nci.nih.gov/pub/tz*.tar.gz
+
+See the datetime section of the Python Library Reference for information
+on how to use these modules.
+'''
+
+import sys
+import datetime
+import os.path
+
+from pytz.exceptions import AmbiguousTimeError
+from pytz.exceptions import InvalidTimeError
+from pytz.exceptions import NonExistentTimeError
+from pytz.exceptions import UnknownTimeZoneError
+from pytz.lazy import LazyDict, LazyList, LazySet # noqa
+from pytz.tzinfo import unpickler, BaseTzInfo
+from pytz.tzfile import build_tzinfo
+
+
+# The IANA (nee Olson) database is updated several times a year.
+OLSON_VERSION = '2019a'
+VERSION = '2019.1' # pip compatible version number.
+__version__ = VERSION
+
+OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling
+
+__all__ = [
+ 'timezone', 'utc', 'country_timezones', 'country_names',
+ 'AmbiguousTimeError', 'InvalidTimeError',
+ 'NonExistentTimeError', 'UnknownTimeZoneError',
+ 'all_timezones', 'all_timezones_set',
+ 'common_timezones', 'common_timezones_set',
+ 'BaseTzInfo',
+]
+
+
+if sys.version_info[0] > 2: # Python 3.x
+
+ # Python 3.x doesn't have unicode(), making writing code
+ # for Python 2.3 and Python 3.x a pain.
+ unicode = str
+
+ def ascii(s):
+ r"""
+ >>> ascii('Hello')
+ 'Hello'
+ >>> ascii('\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
+ ...
+ UnicodeEncodeError: ...
+ """
+ if type(s) == bytes:
+ s = s.decode('ASCII')
+ else:
+ s.encode('ASCII') # Raise an exception if not ASCII
+ return s # But the string - not a byte string.
+
+else: # Python 2.x
+
+ def ascii(s):
+ r"""
+ >>> ascii('Hello')
+ 'Hello'
+ >>> ascii(u'Hello')
+ 'Hello'
+ >>> ascii(u'\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
+ ...
+ UnicodeEncodeError: ...
+ """
+ return s.encode('ASCII')
+
+
+def open_resource(name):
+ """Open a resource from the zoneinfo subdir for reading.
+
+ Uses the pkg_resources module if available and no standard file
+ found at the calculated location.
+
+ It is possible to specify different location for zoneinfo
+ subdir by using the PYTZ_TZDATADIR environment variable.
+ """
+ name_parts = name.lstrip('/').split('/')
+ for part in name_parts:
+ if part == os.path.pardir or os.path.sep in part:
+ raise ValueError('Bad path segment: %r' % part)
+ zoneinfo_dir = os.environ.get('PYTZ_TZDATADIR', None)
+ if zoneinfo_dir is not None:
+ filename = os.path.join(zoneinfo_dir, *name_parts)
+ else:
+ filename = os.path.join(os.path.dirname(__file__),
+ 'zoneinfo', *name_parts)
+ if not os.path.exists(filename):
+ # http://bugs.launchpad.net/bugs/383171 - we avoid using this
+ # unless absolutely necessary to help when a broken version of
+ # pkg_resources is installed.
+ try:
+ from pkg_resources import resource_stream
+ except ImportError:
+ resource_stream = None
+
+ if resource_stream is not None:
+ return resource_stream(__name__, 'zoneinfo/' + name)
+ return open(filename, 'rb')
+
+
+def resource_exists(name):
+ """Return true if the given resource exists"""
+ try:
+ open_resource(name).close()
+ return True
+ except IOError:
+ return False
+
+
+_tzinfo_cache = {}
+
+
+def timezone(zone):
+ r''' Return a datetime.tzinfo implementation for the given timezone
+
+ >>> from datetime import datetime, timedelta
+ >>> utc = timezone('UTC')
+ >>> eastern = timezone('US/Eastern')
+ >>> eastern.zone
+ 'US/Eastern'
+ >>> timezone(unicode('US/Eastern')) is eastern
+ True
+ >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
+ >>> loc_dt = utc_dt.astimezone(eastern)
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+ >>> loc_dt.strftime(fmt)
+ '2002-10-27 01:00:00 EST (-0500)'
+ >>> (loc_dt - timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 00:50:00 EST (-0500)'
+ >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 01:50:00 EDT (-0400)'
+ >>> (loc_dt + timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 01:10:00 EST (-0500)'
+
+ Raises UnknownTimeZoneError if passed an unknown zone.
+
+ >>> try:
+ ... timezone('Asia/Shangri-La')
+ ... except UnknownTimeZoneError:
+ ... print('Unknown')
+ Unknown
+
+ >>> try:
+ ... timezone(unicode('\N{TRADE MARK SIGN}'))
+ ... except UnknownTimeZoneError:
+ ... print('Unknown')
+ Unknown
+
+ '''
+ if zone is None:
+ raise UnknownTimeZoneError(None)
+
+ if zone.upper() == 'UTC':
+ return utc
+
+ try:
+ zone = ascii(zone)
+ except UnicodeEncodeError:
+ # All valid timezones are ASCII
+ raise UnknownTimeZoneError(zone)
+
+ zone = _case_insensitive_zone_lookup(_unmunge_zone(zone))
+ if zone not in _tzinfo_cache:
+ if zone in all_timezones_set: # noqa
+ fp = open_resource(zone)
+ try:
+ _tzinfo_cache[zone] = build_tzinfo(zone, fp)
+ finally:
+ fp.close()
+ else:
+ raise UnknownTimeZoneError(zone)
+
+ return _tzinfo_cache[zone]
+
+
+def _unmunge_zone(zone):
+ """Undo the time zone name munging done by older versions of pytz."""
+ return zone.replace('_plus_', '+').replace('_minus_', '-')
+
+
+def _case_insensitive_zone_lookup(zone):
+ """case-insensitively matching timezone, else return zone unchanged"""
+ return _all_timezones_lower_to_standard.get(zone.lower()) or zone # noqa
+
+
+ZERO = datetime.timedelta(0)
+HOUR = datetime.timedelta(hours=1)
+
+
+class UTC(BaseTzInfo):
+ """UTC
+
+ Optimized UTC implementation. It unpickles using the single module global
+ instance defined beneath this class declaration.
+ """
+ zone = "UTC"
+
+ _utcoffset = ZERO
+ _dst = ZERO
+ _tzname = zone
+
+ def fromutc(self, dt):
+ if dt.tzinfo is None:
+ return self.localize(dt)
+ return super(utc.__class__, self).fromutc(dt)
+
+ def utcoffset(self, dt):
+ return ZERO
+
+ def tzname(self, dt):
+ return "UTC"
+
+ def dst(self, dt):
+ return ZERO
+
+ def __reduce__(self):
+ return _UTC, ()
+
+ def localize(self, dt, is_dst=False):
+ '''Convert naive time to local time'''
+ if dt.tzinfo is not None:
+ raise ValueError('Not naive datetime (tzinfo is already set)')
+ return dt.replace(tzinfo=self)
+
+ def normalize(self, dt, is_dst=False):
+ '''Correct the timezone information on the given datetime'''
+ if dt.tzinfo is self:
+ return dt
+ if dt.tzinfo is None:
+ raise ValueError('Naive time - no tzinfo set')
+ return dt.astimezone(self)
+
+ def __repr__(self):
+ return "<UTC>"
+
+ def __str__(self):
+ return "UTC"
+
+
+UTC = utc = UTC() # UTC is a singleton
+
+
+def _UTC():
+ """Factory function for utc unpickling.
+
+ Makes sure that unpickling a utc instance always returns the same
+ module global.
+
+ These examples belong in the UTC class above, but it is obscured; or in
+ the README.txt, but we are not depending on Python 2.4 so integrating
+ the README.txt examples with the unit tests is not trivial.
+
+ >>> import datetime, pickle
+ >>> dt = datetime.datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc)
+ >>> naive = dt.replace(tzinfo=None)
+ >>> p = pickle.dumps(dt, 1)
+ >>> naive_p = pickle.dumps(naive, 1)
+ >>> len(p) - len(naive_p)
+ 17
+ >>> new = pickle.loads(p)
+ >>> new == dt
+ True
+ >>> new is dt
+ False
+ >>> new.tzinfo is dt.tzinfo
+ True
+ >>> utc is UTC is timezone('UTC')
+ True
+ >>> utc is timezone('GMT')
+ False
+ """
+ return utc
+
+
+_UTC.__safe_for_unpickling__ = True
+
+
+def _p(*args):
+ """Factory function for unpickling pytz tzinfo instances.
+
+ Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle
+ by shortening the path.
+ """
+ return unpickler(*args)
+
+
+_p.__safe_for_unpickling__ = True
+
+
+class _CountryTimezoneDict(LazyDict):
+ """Map ISO 3166 country code to a list of timezone names commonly used
+ in that country.
+
+ iso3166_code is the two letter code used to identify the country.
+
+ >>> def print_list(list_of_strings):
+ ... 'We use a helper so doctests work under Python 2.3 -> 3.x'
+ ... for s in list_of_strings:
+ ... print(s)
+
+ >>> print_list(country_timezones['nz'])
+ Pacific/Auckland
+ Pacific/Chatham
+ >>> print_list(country_timezones['ch'])
+ Europe/Zurich
+ >>> print_list(country_timezones['CH'])
+ Europe/Zurich
+ >>> print_list(country_timezones[unicode('ch')])
+ Europe/Zurich
+ >>> print_list(country_timezones['XXX'])
+ Traceback (most recent call last):
+ ...
+ KeyError: 'XXX'
+
+ Previously, this information was exposed as a function rather than a
+ dictionary. This is still supported::
+
+ >>> print_list(country_timezones('nz'))
+ Pacific/Auckland
+ Pacific/Chatham
+ """
+ def __call__(self, iso3166_code):
+ """Backwards compatibility."""
+ return self[iso3166_code]
+
+ def _fill(self):
+ data = {}
+ zone_tab = open_resource('zone.tab')
+ try:
+ for line in zone_tab:
+ line = line.decode('UTF-8')
+ if line.startswith('#'):
+ continue
+ code, coordinates, zone = line.split(None, 4)[:3]
+ if zone not in all_timezones_set: # noqa
+ continue
+ try:
+ data[code].append(zone)
+ except KeyError:
+ data[code] = [zone]
+ self.data = data
+ finally:
+ zone_tab.close()
+
+
+country_timezones = _CountryTimezoneDict()
+
+
+class _CountryNameDict(LazyDict):
+ '''Dictionary proving ISO3166 code -> English name.
+
+ >>> print(country_names['au'])
+ Australia
+ '''
+ def _fill(self):
+ data = {}
+ zone_tab = open_resource('iso3166.tab')
+ try:
+ for line in zone_tab.readlines():
+ line = line.decode('UTF-8')
+ if line.startswith('#'):
+ continue
+ code, name = line.split(None, 1)
+ data[code] = name.strip()
+ self.data = data
+ finally:
+ zone_tab.close()
+
+
+country_names = _CountryNameDict()
+
+
+# Time-zone info based solely on fixed offsets
+
+class _FixedOffset(datetime.tzinfo):
+
+ zone = None # to match the standard pytz API
+
+ def __init__(self, minutes):
+ if abs(minutes) >= 1440:
+ raise ValueError("absolute offset is too large", minutes)
+ self._minutes = minutes
+ self._offset = datetime.timedelta(minutes=minutes)
+
+ def utcoffset(self, dt):
+ return self._offset
+
+ def __reduce__(self):
+ return FixedOffset, (self._minutes, )
+
+ def dst(self, dt):
+ return ZERO
+
+ def tzname(self, dt):
+ return None
+
+ def __repr__(self):
+ return 'pytz.FixedOffset(%d)' % self._minutes
+
+ def localize(self, dt, is_dst=False):
+ '''Convert naive time to local time'''
+ if dt.tzinfo is not None:
+ raise ValueError('Not naive datetime (tzinfo is already set)')
+ return dt.replace(tzinfo=self)
+
+ def normalize(self, dt, is_dst=False):
+ '''Correct the timezone information on the given datetime'''
+ if dt.tzinfo is self:
+ return dt
+ if dt.tzinfo is None:
+ raise ValueError('Naive time - no tzinfo set')
+ return dt.astimezone(self)
+
+
+def FixedOffset(offset, _tzinfos={}):
+ """return a fixed-offset timezone based off a number of minutes.
+
+ >>> one = FixedOffset(-330)
+ >>> one
+ pytz.FixedOffset(-330)
+ >>> str(one.utcoffset(datetime.datetime.now()))
+ '-1 day, 18:30:00'
+ >>> str(one.dst(datetime.datetime.now()))
+ '0:00:00'
+
+ >>> two = FixedOffset(1380)
+ >>> two
+ pytz.FixedOffset(1380)
+ >>> str(two.utcoffset(datetime.datetime.now()))
+ '23:00:00'
+ >>> str(two.dst(datetime.datetime.now()))
+ '0:00:00'
+
+ The datetime.timedelta must be between the range of -1 and 1 day,
+ non-inclusive.
+
+ >>> FixedOffset(1440)
+ Traceback (most recent call last):
+ ...
+ ValueError: ('absolute offset is too large', 1440)
+
+ >>> FixedOffset(-1440)
+ Traceback (most recent call last):
+ ...
+ ValueError: ('absolute offset is too large', -1440)
+
+ An offset of 0 is special-cased to return UTC.
+
+ >>> FixedOffset(0) is UTC
+ True
+
+ There should always be only one instance of a FixedOffset per timedelta.
+ This should be true for multiple creation calls.
+
+ >>> FixedOffset(-330) is one
+ True
+ >>> FixedOffset(1380) is two
+ True
+
+ It should also be true for pickling.
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(one)) is one
+ True
+ >>> pickle.loads(pickle.dumps(two)) is two
+ True
+ """
+ if offset == 0:
+ return UTC
+
+ info = _tzinfos.get(offset)
+ if info is None:
+ # We haven't seen this one before. we need to save it.
+
+ # Use setdefault to avoid a race condition and make sure we have
+ # only one
+ info = _tzinfos.setdefault(offset, _FixedOffset(offset))
+
+ return info
+
+
+FixedOffset.__safe_for_unpickling__ = True
+
+
+def _test():
+ import doctest
+ sys.path.insert(0, os.pardir)
+ import pytz
+ return doctest.testmod(pytz)
+
+
+if __name__ == '__main__':
+ _test()
diff --git a/src/pytz/exceptions.py b/src/pytz/exceptions.py
new file mode 100644
index 0000000..18df33e
--- /dev/null
+++ b/src/pytz/exceptions.py
@@ -0,0 +1,48 @@
+'''
+Custom exceptions raised by pytz.
+'''
+
+__all__ = [
+ 'UnknownTimeZoneError', 'InvalidTimeError', 'AmbiguousTimeError',
+ 'NonExistentTimeError',
+]
+
+
+class UnknownTimeZoneError(KeyError):
+ '''Exception raised when pytz is passed an unknown timezone.
+
+ >>> isinstance(UnknownTimeZoneError(), LookupError)
+ True
+
+ This class is actually a subclass of KeyError to provide backwards
+ compatibility with code relying on the undocumented behavior of earlier
+ pytz releases.
+
+ >>> isinstance(UnknownTimeZoneError(), KeyError)
+ True
+ '''
+ pass
+
+
+class InvalidTimeError(Exception):
+ '''Base class for invalid time exceptions.'''
+
+
+class AmbiguousTimeError(InvalidTimeError):
+ '''Exception raised when attempting to create an ambiguous wallclock time.
+
+ At the end of a DST transition period, a particular wallclock time will
+ occur twice (once before the clocks are set back, once after). Both
+ possibilities may be correct, unless further information is supplied.
+
+ See DstTzInfo.normalize() for more info
+ '''
+
+
+class NonExistentTimeError(InvalidTimeError):
+ '''Exception raised when attempting to create a wallclock time that
+ cannot exist.
+
+ At the start of a DST transition period, the wallclock time jumps forward.
+ The instants jumped over never occur.
+ '''
diff --git a/src/pytz/lazy.py b/src/pytz/lazy.py
new file mode 100644
index 0000000..39344fc
--- /dev/null
+++ b/src/pytz/lazy.py
@@ -0,0 +1,172 @@
+from threading import RLock
+try:
+ from collections.abc import Mapping as DictMixin
+except ImportError: # Python < 3.3
+ try:
+ from UserDict import DictMixin # Python 2
+ except ImportError: # Python 3.0-3.3
+ from collections import Mapping as DictMixin
+
+
+# With lazy loading, we might end up with multiple threads triggering
+# it at the same time. We need a lock.
+_fill_lock = RLock()
+
+
+class LazyDict(DictMixin):
+ """Dictionary populated on first use."""
+ data = None
+
+ def __getitem__(self, key):
+ if self.data is None:
+ _fill_lock.acquire()
+ try:
+ if self.data is None:
+ self._fill()
+ finally:
+ _fill_lock.release()
+ return self.data[key.upper()]
+
+ def __contains__(self, key):
+ if self.data is None:
+ _fill_lock.acquire()
+ try:
+ if self.data is None:
+ self._fill()
+ finally:
+ _fill_lock.release()
+ return key in self.data
+
+ def __iter__(self):
+ if self.data is None:
+ _fill_lock.acquire()
+ try:
+ if self.data is None:
+ self._fill()
+ finally:
+ _fill_lock.release()
+ return iter(self.data)
+
+ def __len__(self):
+ if self.data is None:
+ _fill_lock.acquire()
+ try:
+ if self.data is None:
+ self._fill()
+ finally:
+ _fill_lock.release()
+ return len(self.data)
+
+ def keys(self):
+ if self.data is None:
+ _fill_lock.acquire()
+ try:
+ if self.data is None:
+ self._fill()
+ finally:
+ _fill_lock.release()
+ return self.data.keys()
+
+
+class LazyList(list):
+ """List populated on first use."""
+
+ _props = [
+ '__str__', '__repr__', '__unicode__',
+ '__hash__', '__sizeof__', '__cmp__',
+ '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
+ 'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove',
+ 'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__',
+ '__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__',
+ '__getitem__', '__setitem__', '__delitem__', '__iter__',
+ '__reversed__', '__getslice__', '__setslice__', '__delslice__']
+
+ def __new__(cls, fill_iter=None):
+
+ if fill_iter is None:
+ return list()
+
+ # We need a new class as we will be dynamically messing with its
+ # methods.
+ class LazyList(list):
+ pass
+
+ fill_iter = [fill_iter]
+
+ def lazy(name):
+ def _lazy(self, *args, **kw):
+ _fill_lock.acquire()
+ try:
+ if len(fill_iter) > 0:
+ list.extend(self, fill_iter.pop())
+ for method_name in cls._props:
+ delattr(LazyList, method_name)
+ finally:
+ _fill_lock.release()
+ return getattr(list, name)(self, *args, **kw)
+ return _lazy
+
+ for name in cls._props:
+ setattr(LazyList, name, lazy(name))
+
+ new_list = LazyList()
+ return new_list
+
+# Not all versions of Python declare the same magic methods.
+# Filter out properties that don't exist in this version of Python
+# from the list.
+LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)]
+
+
+class LazySet(set):
+ """Set populated on first use."""
+
+ _props = (
+ '__str__', '__repr__', '__unicode__',
+ '__hash__', '__sizeof__', '__cmp__',
+ '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__',
+ '__contains__', '__len__', '__nonzero__',
+ '__getitem__', '__setitem__', '__delitem__', '__iter__',
+ '__sub__', '__and__', '__xor__', '__or__',
+ '__rsub__', '__rand__', '__rxor__', '__ror__',
+ '__isub__', '__iand__', '__ixor__', '__ior__',
+ 'add', 'clear', 'copy', 'difference', 'difference_update',
+ 'discard', 'intersection', 'intersection_update', 'isdisjoint',
+ 'issubset', 'issuperset', 'pop', 'remove',
+ 'symmetric_difference', 'symmetric_difference_update',
+ 'union', 'update')
+
+ def __new__(cls, fill_iter=None):
+
+ if fill_iter is None:
+ return set()
+
+ class LazySet(set):
+ pass
+
+ fill_iter = [fill_iter]
+
+ def lazy(name):
+ def _lazy(self, *args, **kw):
+ _fill_lock.acquire()
+ try:
+ if len(fill_iter) > 0:
+ for i in fill_iter.pop():
+ set.add(self, i)
+ for method_name in cls._props:
+ delattr(LazySet, method_name)
+ finally:
+ _fill_lock.release()
+ return getattr(set, name)(self, *args, **kw)
+ return _lazy
+
+ for name in cls._props:
+ setattr(LazySet, name, lazy(name))
+
+ new_set = LazySet()
+ return new_set
+
+# Not all versions of Python declare the same magic methods.
+# Filter out properties that don't exist in this version of Python
+# from the list.
+LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)]
diff --git a/src/pytz/locales/pytz.pot b/src/pytz/locales/pytz.pot
new file mode 100644
index 0000000..9c76c11
--- /dev/null
+++ b/src/pytz/locales/pytz.pot
@@ -0,0 +1,2 @@
+# This file will be generated by gen_pot.py. This is just a stub to keep
+# things working when this generated file is not available.
diff --git a/src/pytz/reference.py b/src/pytz/reference.py
new file mode 100644
index 0000000..f765ca0
--- /dev/null
+++ b/src/pytz/reference.py
@@ -0,0 +1,140 @@
+'''
+Reference tzinfo implementations from the Python docs.
+Used for testing against as they are only correct for the years
+1987 to 2006. Do not use these for real code.
+'''
+
+from datetime import tzinfo, timedelta, datetime
+from pytz import HOUR, ZERO, UTC
+
+__all__ = [
+ 'FixedOffset',
+ 'LocalTimezone',
+ 'USTimeZone',
+ 'Eastern',
+ 'Central',
+ 'Mountain',
+ 'Pacific',
+ 'UTC'
+]
+
+
+# A class building tzinfo objects for fixed-offset time zones.
+# Note that FixedOffset(0, "UTC") is a different way to build a
+# UTC tzinfo object.
+class FixedOffset(tzinfo):
+ """Fixed offset in minutes east from UTC."""
+
+ def __init__(self, offset, name):
+ self.__offset = timedelta(minutes=offset)
+ self.__name = name
+
+ def utcoffset(self, dt):
+ return self.__offset
+
+ def tzname(self, dt):
+ return self.__name
+
+ def dst(self, dt):
+ return ZERO
+
+
+import time as _time
+
+STDOFFSET = timedelta(seconds=-_time.timezone)
+if _time.daylight:
+ DSTOFFSET = timedelta(seconds=-_time.altzone)
+else:
+ DSTOFFSET = STDOFFSET
+
+DSTDIFF = DSTOFFSET - STDOFFSET
+
+
+# A class capturing the platform's idea of local time.
+class LocalTimezone(tzinfo):
+
+ def utcoffset(self, dt):
+ if self._isdst(dt):
+ return DSTOFFSET
+ else:
+ return STDOFFSET
+
+ def dst(self, dt):
+ if self._isdst(dt):
+ return DSTDIFF
+ else:
+ return ZERO
+
+ def tzname(self, dt):
+ return _time.tzname[self._isdst(dt)]
+
+ def _isdst(self, dt):
+ tt = (dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second,
+ dt.weekday(), 0, -1)
+ stamp = _time.mktime(tt)
+ tt = _time.localtime(stamp)
+ return tt.tm_isdst > 0
+
+Local = LocalTimezone()
+
+
+def first_sunday_on_or_after(dt):
+ days_to_go = 6 - dt.weekday()
+ if days_to_go:
+ dt += timedelta(days_to_go)
+ return dt
+
+
+# In the US, DST starts at 2am (standard time) on the first Sunday in April.
+DSTSTART = datetime(1, 4, 1, 2)
+# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct.
+# which is the first Sunday on or after Oct 25.
+DSTEND = datetime(1, 10, 25, 1)
+
+
+# A complete implementation of current DST rules for major US time zones.
+class USTimeZone(tzinfo):
+
+ def __init__(self, hours, reprname, stdname, dstname):
+ self.stdoffset = timedelta(hours=hours)
+ self.reprname = reprname
+ self.stdname = stdname
+ self.dstname = dstname
+
+ def __repr__(self):
+ return self.reprname
+
+ def tzname(self, dt):
+ if self.dst(dt):
+ return self.dstname
+ else:
+ return self.stdname
+
+ def utcoffset(self, dt):
+ return self.stdoffset + self.dst(dt)
+
+ def dst(self, dt):
+ if dt is None or dt.tzinfo is None:
+ # An exception may be sensible here, in one or both cases.
+ # It depends on how you want to treat them. The default
+ # fromutc() implementation (called by the default astimezone()
+ # implementation) passes a datetime with dt.tzinfo is self.
+ return ZERO
+ assert dt.tzinfo is self
+
+ # Find first Sunday in April & the last in October.
+ start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
+ end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
+
+ # Can't compare naive to aware objects, so strip the timezone from
+ # dt first.
+ if start <= dt.replace(tzinfo=None) < end:
+ return HOUR
+ else:
+ return ZERO
+
+Eastern = USTimeZone(-5, "Eastern", "EST", "EDT")
+Central = USTimeZone(-6, "Central", "CST", "CDT")
+Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
+Pacific = USTimeZone(-8, "Pacific", "PST", "PDT")
diff --git a/src/pytz/tests/test_docs.py b/src/pytz/tests/test_docs.py
new file mode 100644
index 0000000..c4ed4a3
--- /dev/null
+++ b/src/pytz/tests/test_docs.py
@@ -0,0 +1,34 @@
+# -*- coding: ascii -*-
+
+from doctest import DocFileSuite
+import unittest
+import os.path
+import sys
+
+THIS_DIR = os.path.dirname(__file__)
+
+README = os.path.join(THIS_DIR, os.pardir, os.pardir, 'README.txt')
+
+
+class DocumentationTestCase(unittest.TestCase):
+ def test_readme_encoding(self):
+ '''Confirm the README.txt is pure ASCII.'''
+ f = open(README, 'rb')
+ try:
+ f.read().decode('ASCII')
+ finally:
+ f.close()
+
+
+def test_suite():
+ "For the Z3 test runner"
+ return unittest.TestSuite((
+ DocumentationTestCase('test_readme_encoding'),
+ DocFileSuite(os.path.join(os.pardir, os.pardir, 'README.txt'))))
+
+
+if __name__ == '__main__':
+ sys.path.insert(
+ 0, os.path.abspath(os.path.join(THIS_DIR, os.pardir, os.pardir))
+ )
+ unittest.main(defaultTest='test_suite')
diff --git a/src/pytz/tests/test_lazy.py b/src/pytz/tests/test_lazy.py
new file mode 100644
index 0000000..3709703
--- /dev/null
+++ b/src/pytz/tests/test_lazy.py
@@ -0,0 +1,315 @@
+from operator import (
+ eq, ge, gt, le, lt, ne, add, concat, not_, sub, and_, or_, xor
+)
+import os.path
+import sys
+import unittest
+import warnings
+
+
+if __name__ == '__main__':
+ # Only munge path if invoked as a script. Testrunners should have setup
+ # the paths already
+ sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir)))
+
+
+from pytz.lazy import LazyList, LazySet
+
+
+class LazyListTestCase(unittest.TestCase):
+ initial_data = [3, 2, 1]
+
+ def setUp(self):
+ self.base = [3, 2, 1]
+ self.lesser = [2, 1, 0]
+ self.greater = [4, 3, 2]
+
+ self.lazy = LazyList(iter(list(self.base)))
+
+ def test_unary_ops(self):
+ unary_ops = [str, repr, len, bool, not_]
+ try:
+ unary_ops.append(unicode)
+ except NameError:
+ pass # unicode no longer exists in Python 3.
+
+ for op in unary_ops:
+ self.assertEqual(
+ op(self.lazy),
+ op(self.base), str(op))
+
+ def test_binary_ops(self):
+ binary_ops = [eq, ge, gt, le, lt, ne, add, concat]
+ try:
+ binary_ops.append(cmp)
+ except NameError:
+ pass # cmp no longer exists in Python 3.
+
+ for op in binary_ops:
+ self.assertEqual(
+ op(self.lazy, self.lazy),
+ op(self.base, self.base), str(op))
+ for other in [self.base, self.lesser, self.greater]:
+ self.assertEqual(
+ op(self.lazy, other),
+ op(self.base, other), '%s %s' % (op, other))
+ self.assertEqual(
+ op(other, self.lazy),
+ op(other, self.base), '%s %s' % (op, other))
+
+ # Multiplication
+ self.assertEqual(self.lazy * 3, self.base * 3)
+ self.assertEqual(3 * self.lazy, 3 * self.base)
+
+ # Contains
+ self.assertTrue(2 in self.lazy)
+ self.assertFalse(42 in self.lazy)
+
+ def test_iadd(self):
+ self.lazy += [1]
+ self.base += [1]
+ self.assertEqual(self.lazy, self.base)
+
+ def test_bool(self):
+ self.assertTrue(bool(self.lazy))
+ self.assertFalse(bool(LazyList()))
+ self.assertFalse(bool(LazyList(iter([]))))
+
+ def test_hash(self):
+ self.assertRaises(TypeError, hash, self.lazy)
+
+ def test_isinstance(self):
+ self.assertTrue(isinstance(self.lazy, list))
+ self.assertFalse(isinstance(self.lazy, tuple))
+
+ def test_callable(self):
+ try:
+ callable
+ except NameError:
+ return # No longer exists with Python 3.
+ self.assertFalse(callable(self.lazy))
+
+ def test_append(self):
+ self.base.append('extra')
+ self.lazy.append('extra')
+ self.assertEqual(self.lazy, self.base)
+
+ def test_count(self):
+ self.assertEqual(self.lazy.count(2), 1)
+
+ def test_index(self):
+ self.assertEqual(self.lazy.index(2), 1)
+
+ def test_extend(self):
+ self.base.extend([6, 7])
+ self.lazy.extend([6, 7])
+ self.assertEqual(self.lazy, self.base)
+
+ def test_insert(self):
+ self.base.insert(0, 'ping')
+ self.lazy.insert(0, 'ping')
+ self.assertEqual(self.lazy, self.base)
+
+ def test_pop(self):
+ self.assertEqual(self.lazy.pop(), self.base.pop())
+ self.assertEqual(self.lazy, self.base)
+
+ def test_remove(self):
+ self.base.remove(2)
+ self.lazy.remove(2)
+ self.assertEqual(self.lazy, self.base)
+
+ def test_reverse(self):
+ self.base.reverse()
+ self.lazy.reverse()
+ self.assertEqual(self.lazy, self.base)
+
+ def test_reversed(self):
+ self.assertEqual(list(reversed(self.lazy)), list(reversed(self.base)))
+
+ def test_sort(self):
+ self.base.sort()
+ self.assertNotEqual(self.lazy, self.base, 'Test data already sorted')
+ self.lazy.sort()
+ self.assertEqual(self.lazy, self.base)
+
+ def test_sorted(self):
+ self.assertEqual(sorted(self.lazy), sorted(self.base))
+
+ def test_getitem(self):
+ for idx in range(-len(self.base), len(self.base)):
+ self.assertEqual(self.lazy[idx], self.base[idx])
+
+ def test_setitem(self):
+ for idx in range(-len(self.base), len(self.base)):
+ self.base[idx] = idx + 1000
+ self.assertNotEqual(self.lazy, self.base)
+ self.lazy[idx] = idx + 1000
+ self.assertEqual(self.lazy, self.base)
+
+ def test_delitem(self):
+ del self.base[0]
+ self.assertNotEqual(self.lazy, self.base)
+ del self.lazy[0]
+ self.assertEqual(self.lazy, self.base)
+
+ del self.base[-2]
+ self.assertNotEqual(self.lazy, self.base)
+ del self.lazy[-2]
+ self.assertEqual(self.lazy, self.base)
+
+ def test_iter(self):
+ self.assertEqual(list(iter(self.lazy)), list(iter(self.base)))
+
+ def test_getslice(self):
+ for i in range(-len(self.base), len(self.base)):
+ for j in range(-len(self.base), len(self.base)):
+ for step in [-1, 1]:
+ self.assertEqual(self.lazy[i:j:step], self.base[i:j:step])
+
+ def test_setslice(self):
+ for i in range(-len(self.base), len(self.base)):
+ for j in range(-len(self.base), len(self.base)):
+ for step in [-1, 1]:
+ replacement = range(0, len(self.base[i:j:step]))
+ self.base[i:j:step] = replacement
+ self.lazy[i:j:step] = replacement
+ self.assertEqual(self.lazy, self.base)
+
+ def test_delslice(self):
+ del self.base[0:1]
+ del self.lazy[0:1]
+ self.assertEqual(self.lazy, self.base)
+
+ del self.base[-1:1:-1]
+ del self.lazy[-1:1:-1]
+ self.assertEqual(self.lazy, self.base)
+
+
+class LazySetTestCase(unittest.TestCase):
+ initial_data = set([3, 2, 1])
+
+ def setUp(self):
+ self.base = set([3, 2, 1])
+ self.lazy = LazySet(iter(set(self.base)))
+
+ def test_unary_ops(self):
+ # These ops just need to work.
+ unary_ops = [str, repr]
+ try:
+ unary_ops.append(unicode)
+ except NameError:
+ pass # unicode no longer exists in Python 3.
+
+ for op in unary_ops:
+ op(self.lazy) # These ops just need to work.
+
+ # These ops should return identical values as a real set.
+ unary_ops = [len, bool, not_]
+
+ for op in unary_ops:
+ self.assertEqual(
+ op(self.lazy),
+ op(self.base), '%s(lazy) == %r' % (op, op(self.lazy)))
+
+ def test_binary_ops(self):
+ binary_ops = [eq, ge, gt, le, lt, ne, sub, and_, or_, xor]
+ try:
+ binary_ops.append(cmp)
+ except NameError:
+ pass # cmp no longer exists in Python 3.
+
+ for op in binary_ops:
+ self.assertEqual(
+ op(self.lazy, self.lazy),
+ op(self.base, self.base), str(op))
+ self.assertEqual(
+ op(self.lazy, self.base),
+ op(self.base, self.base), str(op))
+ self.assertEqual(
+ op(self.base, self.lazy),
+ op(self.base, self.base), str(op))
+
+ # Contains
+ self.assertTrue(2 in self.lazy)
+ self.assertFalse(42 in self.lazy)
+
+ def test_iops(self):
+ try:
+ iops = [isub, iand, ior, ixor]
+ except NameError:
+ return # Don't exist in older Python versions.
+ for op in iops:
+ # Mutating operators, so make fresh copies.
+ lazy = LazySet(self.base)
+ base = self.base.copy()
+ op(lazy, set([1]))
+ op(base, set([1]))
+ self.assertEqual(lazy, base, str(op))
+
+ def test_bool(self):
+ self.assertTrue(bool(self.lazy))
+ self.assertFalse(bool(LazySet()))
+ self.assertFalse(bool(LazySet(iter([]))))
+
+ def test_hash(self):
+ self.assertRaises(TypeError, hash, self.lazy)
+
+ def test_isinstance(self):
+ self.assertTrue(isinstance(self.lazy, set))
+
+ def test_callable(self):
+ try:
+ callable
+ except NameError:
+ return # No longer exists with Python 3.
+ self.assertFalse(callable(self.lazy))
+
+ def test_add(self):
+ self.base.add('extra')
+ self.lazy.add('extra')
+ self.assertEqual(self.lazy, self.base)
+
+ def test_copy(self):
+ self.assertEqual(self.lazy.copy(), self.base)
+
+ def test_method_ops(self):
+ ops = [
+ 'difference', 'intersection', 'isdisjoint',
+ 'issubset', 'issuperset', 'symmetric_difference', 'union',
+ 'difference_update', 'intersection_update',
+ 'symmetric_difference_update', 'update']
+ for op in ops:
+ if not hasattr(set, op):
+ continue # Not in this version of Python.
+ # Make a copy, as some of the ops are mutating.
+ lazy = LazySet(set(self.base))
+ base = set(self.base)
+ self.assertEqual(
+ getattr(lazy, op)(set([1])),
+ getattr(base, op)(set([1])), op)
+ self.assertEqual(lazy, base, op)
+
+ def test_discard(self):
+ self.base.discard(1)
+ self.assertNotEqual(self.lazy, self.base)
+ self.lazy.discard(1)
+ self.assertEqual(self.lazy, self.base)
+
+ def test_pop(self):
+ self.assertEqual(self.lazy.pop(), self.base.pop())
+ self.assertEqual(self.lazy, self.base)
+
+ def test_remove(self):
+ self.base.remove(2)
+ self.lazy.remove(2)
+ self.assertEqual(self.lazy, self.base)
+
+ def test_clear(self):
+ self.lazy.clear()
+ self.assertEqual(self.lazy, set())
+
+
+if __name__ == '__main__':
+ warnings.simplefilter("error") # Warnings should be fatal in tests.
+ unittest.main()
diff --git a/src/pytz/tests/test_tzinfo.py b/src/pytz/tests/test_tzinfo.py
new file mode 100644
index 0000000..e56fef5
--- /dev/null
+++ b/src/pytz/tests/test_tzinfo.py
@@ -0,0 +1,863 @@
+# -*- coding: ascii -*-
+
+import doctest
+import sys
+import os
+import os.path
+import unittest
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+from datetime import (
+ datetime,
+ timedelta
+)
+import warnings
+
+if __name__ == '__main__':
+ # Only munge path if invoked as a script. Testrunners should have setup
+ # the paths already
+ sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir)))
+
+import pytz # noqa
+from pytz import reference # noqa
+from pytz.tzfile import _byte_string # noqa
+from pytz.tzinfo import DstTzInfo, StaticTzInfo # noqa
+
+# I test for expected version to ensure the correct version of pytz is
+# actually being tested.
+EXPECTED_VERSION = '2019.1'
+EXPECTED_OLSON_VERSION = '2019a'
+
+fmt = '%Y-%m-%d %H:%M:%S %Z%z'
+
+NOTIME = timedelta(0)
+
+# GMT is a tzinfo.StaticTzInfo--the class we primarily want to test--while
+# UTC is reference implementation. They both have the same timezone meaning.
+UTC = pytz.timezone('UTC')
+GMT = pytz.timezone('GMT')
+assert isinstance(GMT, StaticTzInfo), 'GMT is no longer a StaticTzInfo'
+
+
+def prettydt(dt):
+ """datetime as a string using a known format.
+
+ We don't use strftime as it doesn't handle years earlier than 1900
+ per http://bugs.python.org/issue1777412
+ """
+ if dt.utcoffset() >= timedelta(0):
+ offset = '+%s' % (dt.utcoffset(),)
+ else:
+ offset = '-%s' % (-1 * dt.utcoffset(),)
+ return '%04d-%02d-%02d %02d:%02d:%02d %s %s' % (
+ dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second,
+ dt.tzname(), offset)
+
+
+if sys.version_info[0] > 2:
+ # Python 3.x doesn't have unicode(), making writing code
+ # for Python 2.3 and Python 3.x a pain.
+ unicode = str
+
+
+class BasicTest(unittest.TestCase):
+
+ def testVersion(self):
+ # Ensuring the correct version of pytz has been loaded
+ self.assertEqual(
+ EXPECTED_VERSION, pytz.__version__,
+ 'Incorrect pytz version loaded. Import path is stuffed '
+ 'or this test needs updating. (Wanted %s, got %s)'
+ % (EXPECTED_VERSION, pytz.__version__)
+ )
+
+ self.assertEqual(
+ EXPECTED_OLSON_VERSION, pytz.OLSON_VERSION,
+ 'Incorrect pytz version loaded. Import path is stuffed '
+ 'or this test needs updating. (Wanted %s, got %s)'
+ % (EXPECTED_OLSON_VERSION, pytz.OLSON_VERSION)
+ )
+
+ def testGMT(self):
+ now = datetime.now(tz=GMT)
+ self.assertTrue(now.utcoffset() == NOTIME)
+ self.assertTrue(now.dst() == NOTIME)
+ self.assertTrue(now.timetuple() == now.utctimetuple())
+ self.assertTrue(now == now.replace(tzinfo=UTC))
+
+ def testReferenceUTC(self):
+ now = datetime.now(tz=UTC)
+ self.assertTrue(now.utcoffset() == NOTIME)
+ self.assertTrue(now.dst() == NOTIME)
+ self.assertTrue(now.timetuple() == now.utctimetuple())
+
+ def testUnknownOffsets(self):
+ # This tzinfo behavior is required to make
+ # datetime.time.{utcoffset, dst, tzname} work as documented.
+
+ dst_tz = pytz.timezone('US/Eastern')
+
+ # This information is not known when we don't have a date,
+ # so return None per API.
+ self.assertTrue(dst_tz.utcoffset(None) is None)
+ self.assertTrue(dst_tz.dst(None) is None)
+ # We don't know the abbreviation, but this is still a valid
+ # tzname per the Python documentation.
+ self.assertEqual(dst_tz.tzname(None), 'US/Eastern')
+
+ def clearCache(self):
+ pytz._tzinfo_cache.clear()
+
+ def testUnicodeTimezone(self):
+ # We need to ensure that cold lookups work for both Unicode
+ # and traditional strings, and that the desired singleton is
+ # returned.
+ self.clearCache()
+ eastern = pytz.timezone(unicode('US/Eastern'))
+ self.assertTrue(eastern is pytz.timezone('US/Eastern'))
+
+ self.clearCache()
+ eastern = pytz.timezone('US/Eastern')
+ self.assertTrue(eastern is pytz.timezone(unicode('US/Eastern')))
+
+ def testStaticTzInfo(self):
+ # Ensure that static timezones are correctly detected,
+ # per lp:1602807
+ static = pytz.timezone('Etc/GMT-4')
+ self.assertTrue(isinstance(static, StaticTzInfo))
+
+
+class PicklingTest(unittest.TestCase):
+
+ def _roundtrip_tzinfo(self, tz):
+ p = pickle.dumps(tz)
+ unpickled_tz = pickle.loads(p)
+ self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone)
+
+ def _roundtrip_datetime(self, dt):
+ # Ensure that the tzinfo attached to a datetime instance
+ # is identical to the one returned. This is important for
+ # DST timezones, as some state is stored in the tzinfo.
+ tz = dt.tzinfo
+ p = pickle.dumps(dt)
+ unpickled_dt = pickle.loads(p)
+ unpickled_tz = unpickled_dt.tzinfo
+ self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone)
+
+ def testDst(self):
+ tz = pytz.timezone('Europe/Amsterdam')
+ dt = datetime(2004, 2, 1, 0, 0, 0)
+
+ for localized_tz in tz._tzinfos.values():
+ self._roundtrip_tzinfo(localized_tz)
+ self._roundtrip_datetime(dt.replace(tzinfo=localized_tz))
+
+ def testRoundtrip(self):
+ for zone in pytz.all_timezones:
+ tz = pytz.timezone(zone)
+ self._roundtrip_tzinfo(tz)
+
+ def testDatabaseFixes(self):
+ # Hack the pickle to make it refer to a timezone abbreviation
+ # that does not match anything. The unpickler should be able
+ # to repair this case
+ tz = pytz.timezone('Australia/Melbourne')
+ p = pickle.dumps(tz)
+ tzname = tz._tzname
+ hacked_p = p.replace(
+ _byte_string(tzname),
+ _byte_string('?' * len(tzname))
+ )
+ self.assertNotEqual(p, hacked_p)
+ unpickled_tz = pickle.loads(hacked_p)
+ self.assertTrue(tz is unpickled_tz)
+
+ # Simulate a database correction. In this case, the incorrect
+ # data will continue to be used.
+ p = pickle.dumps(tz)
+ new_utcoffset = tz._utcoffset.seconds + 42
+
+ # Python 3 introduced a new pickle protocol where numbers are stored in
+ # hexadecimal representation. Here we extract the pickle
+ # representation of the number for the current Python version.
+ old_pickle_pattern = pickle.dumps(tz._utcoffset.seconds)[3:-1]
+ new_pickle_pattern = pickle.dumps(new_utcoffset)[3:-1]
+ hacked_p = p.replace(old_pickle_pattern, new_pickle_pattern)
+
+ self.assertNotEqual(p, hacked_p)
+ unpickled_tz = pickle.loads(hacked_p)
+ self.assertEqual(unpickled_tz._utcoffset.seconds, new_utcoffset)
+ self.assertTrue(tz is not unpickled_tz)
+
+ def testOldPickles(self):
+ # Ensure that applications serializing pytz instances as pickles
+ # have no troubles upgrading to a new pytz release. These pickles
+ # where created with pytz2006j
+ east1 = pickle.loads(
+ _byte_string(
+ "cpytz\n_p\np1\n(S'US/Eastern'\np2\nI-18000\n"
+ "I0\nS'EST'\np3\ntRp4\n."
+ )
+ )
+ east2 = pytz.timezone('US/Eastern').localize(
+ datetime(2006, 1, 1)).tzinfo
+ self.assertTrue(east1 is east2)
+
+ # Confirm changes in name munging between 2006j and 2007c cause
+ # no problems.
+ pap1 = pickle.loads(_byte_string(
+ "cpytz\n_p\np1\n(S'America/Port_minus_au_minus_Prince'"
+ "\np2\nI-17340\nI0\nS'PPMT'\np3\ntRp4\n."))
+ pap2 = pytz.timezone('America/Port-au-Prince').localize(
+ datetime(1910, 1, 1)).tzinfo
+ self.assertTrue(pap1 is pap2)
+
+ gmt1 = pickle.loads(_byte_string(
+ "cpytz\n_p\np1\n(S'Etc/GMT_plus_10'\np2\ntRp3\n."))
+ gmt2 = pytz.timezone('Etc/GMT+10')
+ self.assertTrue(gmt1 is gmt2)
+
+
+class USEasternDSTStartTestCase(unittest.TestCase):
+ tzinfo = pytz.timezone('US/Eastern')
+
+ # 24 hours before DST changeover
+ transition_time = datetime(2002, 4, 7, 7, 0, 0, tzinfo=UTC)
+
+ # Increase for 'flexible' DST transitions due to 1 minute granularity
+ # of Python's datetime library
+ instant = timedelta(seconds=1)
+
+ # before transition
+ before = {
+ 'tzname': 'EST',
+ 'utcoffset': timedelta(hours=-5),
+ 'dst': timedelta(hours=0),
+ }
+
+ # after transition
+ after = {
+ 'tzname': 'EDT',
+ 'utcoffset': timedelta(hours=-4),
+ 'dst': timedelta(hours=1),
+ }
+
+ def _test_tzname(self, utc_dt, wanted):
+ tzname = wanted['tzname']
+ dt = utc_dt.astimezone(self.tzinfo)
+ self.assertEqual(
+ dt.tzname(), tzname,
+ 'Expected %s as tzname for %s. Got %s' % (
+ tzname, str(utc_dt), dt.tzname()
+ )
+ )
+
+ def _test_utcoffset(self, utc_dt, wanted):
+ utcoffset = wanted['utcoffset']
+ dt = utc_dt.astimezone(self.tzinfo)
+ self.assertEqual(
+ dt.utcoffset(), wanted['utcoffset'],
+ 'Expected %s as utcoffset for %s. Got %s' % (
+ utcoffset, utc_dt, dt.utcoffset()
+ )
+ )
+
+ def _test_dst(self, utc_dt, wanted):
+ dst = wanted['dst']
+ dt = utc_dt.astimezone(self.tzinfo)
+ self.assertEqual(
+ dt.dst(), dst,
+ 'Expected %s as dst for %s. Got %s' % (dst, utc_dt, dt.dst())
+ )
+
+ def test_arithmetic(self):
+ utc_dt = self.transition_time
+
+ for days in range(-420, 720, 20):
+ delta = timedelta(days=days)
+
+ # Make sure we can get back where we started
+ dt = utc_dt.astimezone(self.tzinfo)
+ dt2 = dt + delta
+ dt2 = dt2 - delta
+ self.assertEqual(dt, dt2)
+
+ # Make sure arithmetic crossing DST boundaries ends
+ # up in the correct timezone after normalization
+ utc_plus_delta = (utc_dt + delta).astimezone(self.tzinfo)
+ local_plus_delta = self.tzinfo.normalize(dt + delta)
+ self.assertEqual(
+ prettydt(utc_plus_delta), prettydt(local_plus_delta),
+ 'Incorrect result for delta==%d days. Wanted %r. Got %r' % (
+ days, prettydt(utc_plus_delta), prettydt(local_plus_delta),
+ )
+ )
+
+ def _test_all(self, utc_dt, wanted):
+ self._test_utcoffset(utc_dt, wanted)
+ self._test_tzname(utc_dt, wanted)
+ self._test_dst(utc_dt, wanted)
+
+ def testDayBefore(self):
+ self._test_all(
+ self.transition_time - timedelta(days=1), self.before
+ )
+
+ def testTwoHoursBefore(self):
+ self._test_all(
+ self.transition_time - timedelta(hours=2), self.before
+ )
+
+ def testHourBefore(self):
+ self._test_all(
+ self.transition_time - timedelta(hours=1), self.before
+ )
+
+ def testInstantBefore(self):
+ self._test_all(
+ self.transition_time - self.instant, self.before
+ )
+
+ def testTransition(self):
+ self._test_all(
+ self.transition_time, self.after
+ )
+
+ def testInstantAfter(self):
+ self._test_all(
+ self.transition_time + self.instant, self.after
+ )
+
+ def testHourAfter(self):
+ self._test_all(
+ self.transition_time + timedelta(hours=1), self.after
+ )
+
+ def testTwoHoursAfter(self):
+ self._test_all(
+ self.transition_time + timedelta(hours=1), self.after
+ )
+
+ def testDayAfter(self):
+ self._test_all(
+ self.transition_time + timedelta(days=1), self.after
+ )
+
+
+class USEasternDSTEndTestCase(USEasternDSTStartTestCase):
+ tzinfo = pytz.timezone('US/Eastern')
+ transition_time = datetime(2002, 10, 27, 6, 0, 0, tzinfo=UTC)
+ before = {
+ 'tzname': 'EDT',
+ 'utcoffset': timedelta(hours=-4),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': 'EST',
+ 'utcoffset': timedelta(hours=-5),
+ 'dst': timedelta(hours=0),
+ }
+
+
+class USEasternEPTStartTestCase(USEasternDSTStartTestCase):
+ transition_time = datetime(1945, 8, 14, 23, 0, 0, tzinfo=UTC)
+ before = {
+ 'tzname': 'EWT',
+ 'utcoffset': timedelta(hours=-4),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': 'EPT',
+ 'utcoffset': timedelta(hours=-4),
+ 'dst': timedelta(hours=1),
+ }
+
+
+class USEasternEPTEndTestCase(USEasternDSTStartTestCase):
+ transition_time = datetime(1945, 9, 30, 6, 0, 0, tzinfo=UTC)
+ before = {
+ 'tzname': 'EPT',
+ 'utcoffset': timedelta(hours=-4),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': 'EST',
+ 'utcoffset': timedelta(hours=-5),
+ 'dst': timedelta(hours=0),
+ }
+
+
+class WarsawWMTEndTestCase(USEasternDSTStartTestCase):
+ # In 1915, Warsaw changed from Warsaw to Central European time.
+ # This involved the clocks being set backwards, causing a end-of-DST
+ # like situation without DST being involved.
+ tzinfo = pytz.timezone('Europe/Warsaw')
+ transition_time = datetime(1915, 8, 4, 22, 36, 0, tzinfo=UTC)
+ before = {
+ 'tzname': 'WMT',
+ 'utcoffset': timedelta(hours=1, minutes=24),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': 'CET',
+ 'utcoffset': timedelta(hours=1),
+ 'dst': timedelta(0),
+ }
+
+
+class VilniusWMTEndTestCase(USEasternDSTStartTestCase):
+ # At the end of 1916, Vilnius changed timezones putting its clock
+ # forward by 11 minutes 35 seconds. Neither timezone was in DST mode.
+ tzinfo = pytz.timezone('Europe/Vilnius')
+ instant = timedelta(seconds=31)
+ transition_time = datetime(1916, 12, 31, 22, 36, 00, tzinfo=UTC)
+ before = {
+ 'tzname': 'WMT',
+ 'utcoffset': timedelta(hours=1, minutes=24),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': 'KMT',
+ 'utcoffset': timedelta(hours=1, minutes=36), # Really 1:35:36
+ 'dst': timedelta(0),
+ }
+
+
+class VilniusCESTStartTestCase(USEasternDSTStartTestCase):
+ # In 1941, Vilnius changed from MSG to CEST, switching to summer
+ # time while simultaneously reducing its UTC offset by two hours,
+ # causing the clocks to go backwards for this summer time
+ # switchover.
+ tzinfo = pytz.timezone('Europe/Vilnius')
+ transition_time = datetime(1941, 6, 23, 21, 00, 00, tzinfo=UTC)
+ before = {
+ 'tzname': 'MSK',
+ 'utcoffset': timedelta(hours=3),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': 'CEST',
+ 'utcoffset': timedelta(hours=2),
+ 'dst': timedelta(hours=1),
+ }
+
+
+class LondonHistoryStartTestCase(USEasternDSTStartTestCase):
+ # The first known timezone transition in London was in 1847 when
+ # clocks where synchronized to GMT. However, we currently only
+ # understand v1 format tzfile(5) files which does handle years
+ # this far in the past, so our earliest known transition is in
+ # 1916.
+ tzinfo = pytz.timezone('Europe/London')
+ # transition_time = datetime(1847, 12, 1, 1, 15, 00, tzinfo=UTC)
+ # before = {
+ # 'tzname': 'LMT',
+ # 'utcoffset': timedelta(minutes=-75),
+ # 'dst': timedelta(0),
+ # }
+ # after = {
+ # 'tzname': 'GMT',
+ # 'utcoffset': timedelta(0),
+ # 'dst': timedelta(0),
+ # }
+ transition_time = datetime(1916, 5, 21, 2, 00, 00, tzinfo=UTC)
+ before = {
+ 'tzname': 'GMT',
+ 'utcoffset': timedelta(0),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': 'BST',
+ 'utcoffset': timedelta(hours=1),
+ 'dst': timedelta(hours=1),
+ }
+
+
+class LondonHistoryEndTestCase(USEasternDSTStartTestCase):
+ # Timezone switchovers are projected into the future, even
+ # though no official statements exist or could be believed even
+ # if they did exist. We currently only check the last known
+ # transition in 2037, as we are still using v1 format tzfile(5)
+ # files.
+ tzinfo = pytz.timezone('Europe/London')
+ # transition_time = datetime(2499, 10, 25, 1, 0, 0, tzinfo=UTC)
+ transition_time = datetime(2037, 10, 25, 1, 0, 0, tzinfo=UTC)
+ before = {
+ 'tzname': 'BST',
+ 'utcoffset': timedelta(hours=1),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': 'GMT',
+ 'utcoffset': timedelta(0),
+ 'dst': timedelta(0),
+ }
+
+
+class NoumeaHistoryStartTestCase(USEasternDSTStartTestCase):
+ # Noumea adopted a whole hour offset in 1912. Previously
+ # it was 11 hours, 5 minutes and 48 seconds off UTC. However,
+ # due to limitations of the Python datetime library, we need
+ # to round that to 11 hours 6 minutes.
+ tzinfo = pytz.timezone('Pacific/Noumea')
+ transition_time = datetime(1912, 1, 12, 12, 54, 12, tzinfo=UTC)
+ before = {
+ 'tzname': 'LMT',
+ 'utcoffset': timedelta(hours=11, minutes=6),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': '+11', # pre-2017a, NCT
+ 'utcoffset': timedelta(hours=11),
+ 'dst': timedelta(0),
+ }
+
+
+class NoumeaDSTEndTestCase(USEasternDSTStartTestCase):
+ # Noumea dropped DST in 1997.
+ tzinfo = pytz.timezone('Pacific/Noumea')
+ transition_time = datetime(1997, 3, 1, 15, 00, 00, tzinfo=UTC)
+ before = {
+ 'tzname': '+12', # pre-2017a, NCST
+ 'utcoffset': timedelta(hours=12),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': '+11', # pre-2017a, NCT
+ 'utcoffset': timedelta(hours=11),
+ 'dst': timedelta(0),
+ }
+
+
+class NoumeaNoMoreDSTTestCase(NoumeaDSTEndTestCase):
+ # Noumea dropped DST in 1997. Here we test that it stops occuring.
+ transition_time = (
+ NoumeaDSTEndTestCase.transition_time + timedelta(days=365 * 10))
+ before = NoumeaDSTEndTestCase.after
+ after = NoumeaDSTEndTestCase.after
+
+
+class TahitiTestCase(USEasternDSTStartTestCase):
+ # Tahiti has had a single transition in its history.
+ tzinfo = pytz.timezone('Pacific/Tahiti')
+ transition_time = datetime(1912, 10, 1, 9, 58, 16, tzinfo=UTC)
+ before = {
+ 'tzname': 'LMT',
+ 'utcoffset': timedelta(hours=-9, minutes=-58),
+ 'dst': timedelta(0),
+ }
+ after = {
+ 'tzname': '-10', # pre-2017a, TAHT
+ 'utcoffset': timedelta(hours=-10),
+ 'dst': timedelta(0),
+ }
+
+
+class SamoaInternationalDateLineChange(USEasternDSTStartTestCase):
+ # At the end of 2011, Samoa will switch from being east of the
+ # international dateline to the west. There will be no Dec 30th
+ # 2011 and it will switch from UTC-10 to UTC+14.
+ tzinfo = pytz.timezone('Pacific/Apia')
+ transition_time = datetime(2011, 12, 30, 10, 0, 0, tzinfo=UTC)
+ before = {
+ 'tzname': '-10', # pre-2017a, SDT
+ 'utcoffset': timedelta(hours=-10),
+ 'dst': timedelta(hours=1),
+ }
+ after = {
+ 'tzname': '+14', # pre-2017a, WSDT
+ 'utcoffset': timedelta(hours=14),
+ 'dst': timedelta(hours=1),
+ }
+
+
+class ReferenceUSEasternDSTStartTestCase(USEasternDSTStartTestCase):
+ tzinfo = reference.Eastern
+
+ def test_arithmetic(self):
+ # Reference implementation cannot handle this
+ pass
+
+
+class ReferenceUSEasternDSTEndTestCase(USEasternDSTEndTestCase):
+ tzinfo = reference.Eastern
+
+ def testHourBefore(self):
+ # Python's datetime library has a bug, where the hour before
+ # a daylight saving transition is one hour out. For example,
+ # at the end of US/Eastern daylight saving time, 01:00 EST
+ # occurs twice (once at 05:00 UTC and once at 06:00 UTC),
+ # whereas the first should actually be 01:00 EDT.
+ # Note that this bug is by design - by accepting this ambiguity
+ # for one hour one hour per year, an is_dst flag on datetime.time
+ # became unnecessary.
+ self._test_all(self.transition_time - timedelta(hours=1), self.after)
+
+ def testInstantBefore(self):
+ self._test_all(self.transition_time - timedelta(seconds=1), self.after)
+
+ def test_arithmetic(self):
+ # Reference implementation cannot handle this
+ pass
+
+
+class LocalTestCase(unittest.TestCase):
+ def testLocalize(self):
+ loc_tz = pytz.timezone('Europe/Amsterdam')
+
+ loc_time = loc_tz.localize(datetime(1930, 5, 10, 0, 0, 0))
+ # Actually +00:19:32, but Python datetime rounds this
+ self.assertEqual(loc_time.strftime('%Z%z'), 'AMT+0020')
+
+ loc_time = loc_tz.localize(datetime(1930, 5, 20, 0, 0, 0))
+ # Actually +00:19:32, but Python datetime rounds this
+ self.assertEqual(loc_time.strftime('%Z%z'), 'NST+0120')
+
+ loc_time = loc_tz.localize(datetime(1940, 5, 10, 0, 0, 0))
+ # pre-2017a, abbreviation was NCT
+ self.assertEqual(loc_time.strftime('%Z%z'), '+0020+0020')
+
+ loc_time = loc_tz.localize(datetime(1940, 5, 20, 0, 0, 0))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200')
+
+ loc_time = loc_tz.localize(datetime(2004, 2, 1, 0, 0, 0))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100')
+
+ loc_time = loc_tz.localize(datetime(2004, 4, 1, 0, 0, 0))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200')
+
+ loc_time = loc_tz.localize(datetime(1943, 3, 29, 1, 59, 59))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100')
+
+ # Switch to US
+ loc_tz = pytz.timezone('US/Eastern')
+
+ # End of DST ambiguity check
+ loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=1)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400')
+
+ loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=0)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500')
+
+ self.assertRaises(
+ pytz.AmbiguousTimeError,
+ loc_tz.localize, datetime(1918, 10, 27, 1, 59, 59), is_dst=None
+ )
+
+ # Start of DST non-existent times
+ loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=0)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500')
+
+ loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=1)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400')
+
+ self.assertRaises(
+ pytz.NonExistentTimeError,
+ loc_tz.localize, datetime(1918, 3, 31, 2, 0, 0), is_dst=None
+ )
+
+ # Weird changes - war time and peace time both is_dst==True
+
+ loc_time = loc_tz.localize(datetime(1942, 2, 9, 3, 0, 0))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EWT-0400')
+
+ loc_time = loc_tz.localize(datetime(1945, 8, 14, 19, 0, 0))
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400')
+
+ loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=1)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400')
+
+ loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=0)
+ self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500')
+
+ # Weird changes - ambiguous time (end-of-DST like) but is_dst==False
+ for zonename, ambiguous_naive, expected in [
+ ('Europe/Warsaw', datetime(1915, 8, 4, 23, 59, 59),
+ ['1915-08-04 23:59:59 WMT+0124',
+ '1915-08-04 23:59:59 CET+0100']),
+ ('Europe/Moscow', datetime(2014, 10, 26, 1, 30),
+ ['2014-10-26 01:30:00 MSK+0400',
+ '2014-10-26 01:30:00 MSK+0300'])]:
+ loc_tz = pytz.timezone(zonename)
+ self.assertRaises(
+ pytz.AmbiguousTimeError,
+ loc_tz.localize, ambiguous_naive, is_dst=None
+ )
+ # Also test non-boolean is_dst in the weird case
+ for dst in [True, timedelta(1), False, timedelta(0)]:
+ loc_time = loc_tz.localize(ambiguous_naive, is_dst=dst)
+ self.assertEqual(loc_time.strftime(fmt), expected[not dst])
+
+ def testNormalize(self):
+ tz = pytz.timezone('US/Eastern')
+ dt = datetime(2004, 4, 4, 7, 0, 0, tzinfo=UTC).astimezone(tz)
+ dt2 = dt - timedelta(minutes=10)
+ self.assertEqual(
+ dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
+ '2004-04-04 02:50:00 EDT-0400'
+ )
+
+ dt2 = tz.normalize(dt2)
+ self.assertEqual(
+ dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
+ '2004-04-04 01:50:00 EST-0500'
+ )
+
+ def testPartialMinuteOffsets(self):
+ # utcoffset in Amsterdam was not a whole minute until 1937
+ # However, we fudge this by rounding them, as the Python
+ # datetime library
+ tz = pytz.timezone('Europe/Amsterdam')
+ utc_dt = datetime(1914, 1, 1, 13, 40, 28, tzinfo=UTC) # correct
+ utc_dt = utc_dt.replace(second=0) # But we need to fudge it
+ loc_dt = utc_dt.astimezone(tz)
+ self.assertEqual(
+ loc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
+ '1914-01-01 14:00:00 AMT+0020'
+ )
+
+ # And get back...
+ utc_dt = loc_dt.astimezone(UTC)
+ self.assertEqual(
+ utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
+ '1914-01-01 13:40:00 UTC+0000'
+ )
+
+ def no_testCreateLocaltime(self):
+ # It would be nice if this worked, but it doesn't.
+ tz = pytz.timezone('Europe/Amsterdam')
+ dt = datetime(2004, 10, 31, 2, 0, 0, tzinfo=tz)
+ self.assertEqual(
+ dt.strftime(fmt),
+ '2004-10-31 02:00:00 CET+0100'
+ )
+
+
+class CommonTimezonesTestCase(unittest.TestCase):
+ def test_bratislava(self):
+ # Bratislava is the default timezone for Slovakia, but our
+ # heuristics where not adding it to common_timezones. Ideally,
+ # common_timezones should be populated from zone.tab at runtime,
+ # but I'm hesitant to pay the startup cost as loading the list
+ # on demand whilst remaining backwards compatible seems
+ # difficult.
+ self.assertTrue('Europe/Bratislava' in pytz.common_timezones)
+ self.assertTrue('Europe/Bratislava' in pytz.common_timezones_set)
+
+ def test_us_eastern(self):
+ self.assertTrue('US/Eastern' in pytz.common_timezones)
+ self.assertTrue('US/Eastern' in pytz.common_timezones_set)
+
+ def test_belfast(self):
+ # Belfast uses London time.
+ self.assertTrue('Europe/Belfast' in pytz.all_timezones_set)
+ self.assertFalse('Europe/Belfast' in pytz.common_timezones)
+ self.assertFalse('Europe/Belfast' in pytz.common_timezones_set)
+
+
+class ZoneCaseInsensitivityTestCase(unittest.TestCase):
+ def test_lower_case_timezone_constructor_arg(self):
+ for tz in pytz.all_timezones_set:
+ from_lower = pytz.timezone(tz.lower())
+ from_passed = pytz.timezone(tz)
+ self.assertEqual(from_lower,
+ from_passed,
+ "arg '%s' and arg '%s' produce different "
+ "timezone objects" % (
+ from_lower, from_passed))
+
+
+class BaseTzInfoTestCase:
+ '''Ensure UTC, StaticTzInfo and DstTzInfo work consistently.
+
+ These tests are run for each type of tzinfo.
+ '''
+ tz = None # override
+ tz_class = None # override
+
+ def test_expectedclass(self):
+ self.assertTrue(isinstance(self.tz, self.tz_class))
+
+ def test_fromutc(self):
+ # naive datetime.
+ dt1 = datetime(2011, 10, 31)
+
+ # localized datetime, same timezone.
+ dt2 = self.tz.localize(dt1)
+
+ # Both should give the same results. Note that the standard
+ # Python tzinfo.fromutc() only supports the second.
+ for dt in [dt1, dt2]:
+ loc_dt = self.tz.fromutc(dt)
+ loc_dt2 = pytz.utc.localize(dt1).astimezone(self.tz)
+ self.assertEqual(loc_dt, loc_dt2)
+
+ # localized datetime, different timezone.
+ new_tz = pytz.timezone('Europe/Paris')
+ self.assertTrue(self.tz is not new_tz)
+ dt3 = new_tz.localize(dt1)
+ self.assertRaises(ValueError, self.tz.fromutc, dt3)
+
+ def test_normalize(self):
+ other_tz = pytz.timezone('Europe/Paris')
+ self.assertTrue(self.tz is not other_tz)
+
+ dt = datetime(2012, 3, 26, 12, 0)
+ other_dt = other_tz.localize(dt)
+
+ local_dt = self.tz.normalize(other_dt)
+
+ self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo)
+ self.assertNotEqual(
+ local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None))
+
+ def test_astimezone(self):
+ other_tz = pytz.timezone('Europe/Paris')
+ self.assertTrue(self.tz is not other_tz)
+
+ dt = datetime(2012, 3, 26, 12, 0)
+ other_dt = other_tz.localize(dt)
+
+ local_dt = other_dt.astimezone(self.tz)
+
+ self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo)
+ self.assertNotEqual(
+ local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None))
+
+
+class OptimizedUTCTestCase(unittest.TestCase, BaseTzInfoTestCase):
+ tz = pytz.utc
+ tz_class = tz.__class__
+
+
+class LegacyUTCTestCase(unittest.TestCase, BaseTzInfoTestCase):
+ # Deprecated timezone, but useful for comparison tests.
+ tz = pytz.timezone('Etc/UTC')
+ tz_class = StaticTzInfo
+
+
+class StaticTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase):
+ tz = pytz.timezone('GMT')
+ tz_class = StaticTzInfo
+
+
+class DstTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase):
+ tz = pytz.timezone('Australia/Melbourne')
+ tz_class = DstTzInfo
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(doctest.DocTestSuite('pytz'))
+ suite.addTest(doctest.DocTestSuite('pytz.tzinfo'))
+ import test_tzinfo
+ suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_tzinfo))
+ return suite
+
+
+if __name__ == '__main__':
+ warnings.simplefilter("error") # Warnings should be fatal in tests.
+ unittest.main(defaultTest='test_suite')
diff --git a/src/pytz/tzfile.py b/src/pytz/tzfile.py
new file mode 100644
index 0000000..25117f3
--- /dev/null
+++ b/src/pytz/tzfile.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+'''
+$Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $
+'''
+
+from datetime import datetime
+from struct import unpack, calcsize
+
+from pytz.tzinfo import StaticTzInfo, DstTzInfo, memorized_ttinfo
+from pytz.tzinfo import memorized_datetime, memorized_timedelta
+
+
+def _byte_string(s):
+ """Cast a string or byte string to an ASCII byte string."""
+ return s.encode('ASCII')
+
+_NULL = _byte_string('\0')
+
+
+def _std_string(s):
+ """Cast a string or byte string to an ASCII string."""
+ return str(s.decode('ASCII'))
+
+
+def build_tzinfo(zone, fp):
+ head_fmt = '>4s c 15x 6l'
+ head_size = calcsize(head_fmt)
+ (magic, format, ttisgmtcnt, ttisstdcnt, leapcnt, timecnt,
+ typecnt, charcnt) = unpack(head_fmt, fp.read(head_size))
+
+ # Make sure it is a tzfile(5) file
+ assert magic == _byte_string('TZif'), 'Got magic %s' % repr(magic)
+
+ # Read out the transition times, localtime indices and ttinfo structures.
+ data_fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict(
+ timecnt=timecnt, ttinfo='lBB' * typecnt, charcnt=charcnt)
+ data_size = calcsize(data_fmt)
+ data = unpack(data_fmt, fp.read(data_size))
+
+ # make sure we unpacked the right number of values
+ assert len(data) == 2 * timecnt + 3 * typecnt + 1
+ transitions = [memorized_datetime(trans)
+ for trans in data[:timecnt]]
+ lindexes = list(data[timecnt:2 * timecnt])
+ ttinfo_raw = data[2 * timecnt:-1]
+ tznames_raw = data[-1]
+ del data
+
+ # Process ttinfo into separate structs
+ ttinfo = []
+ tznames = {}
+ i = 0
+ while i < len(ttinfo_raw):
+ # have we looked up this timezone name yet?
+ tzname_offset = ttinfo_raw[i + 2]
+ if tzname_offset not in tznames:
+ nul = tznames_raw.find(_NULL, tzname_offset)
+ if nul < 0:
+ nul = len(tznames_raw)
+ tznames[tzname_offset] = _std_string(
+ tznames_raw[tzname_offset:nul])
+ ttinfo.append((ttinfo_raw[i],
+ bool(ttinfo_raw[i + 1]),
+ tznames[tzname_offset]))
+ i += 3
+
+ # Now build the timezone object
+ if len(ttinfo) == 1 or len(transitions) == 0:
+ ttinfo[0][0], ttinfo[0][2]
+ cls = type(zone, (StaticTzInfo,), dict(
+ zone=zone,
+ _utcoffset=memorized_timedelta(ttinfo[0][0]),
+ _tzname=ttinfo[0][2]))
+ else:
+ # Early dates use the first standard time ttinfo
+ i = 0
+ while ttinfo[i][1]:
+ i += 1
+ if ttinfo[i] == ttinfo[lindexes[0]]:
+ transitions[0] = datetime.min
+ else:
+ transitions.insert(0, datetime.min)
+ lindexes.insert(0, i)
+
+ # calculate transition info
+ transition_info = []
+ for i in range(len(transitions)):
+ inf = ttinfo[lindexes[i]]
+ utcoffset = inf[0]
+ if not inf[1]:
+ dst = 0
+ else:
+ for j in range(i - 1, -1, -1):
+ prev_inf = ttinfo[lindexes[j]]
+ if not prev_inf[1]:
+ break
+ dst = inf[0] - prev_inf[0] # dst offset
+
+ # Bad dst? Look further. DST > 24 hours happens when
+ # a timzone has moved across the international dateline.
+ if dst <= 0 or dst > 3600 * 3:
+ for j in range(i + 1, len(transitions)):
+ stdinf = ttinfo[lindexes[j]]
+ if not stdinf[1]:
+ dst = inf[0] - stdinf[0]
+ if dst > 0:
+ break # Found a useful std time.
+
+ tzname = inf[2]
+
+ # Round utcoffset and dst to the nearest minute or the
+ # datetime library will complain. Conversions to these timezones
+ # might be up to plus or minus 30 seconds out, but it is
+ # the best we can do.
+ utcoffset = int((utcoffset + 30) // 60) * 60
+ dst = int((dst + 30) // 60) * 60
+ transition_info.append(memorized_ttinfo(utcoffset, dst, tzname))
+
+ cls = type(zone, (DstTzInfo,), dict(
+ zone=zone,
+ _utc_transition_times=transitions,
+ _transition_info=transition_info))
+
+ return cls()
+
+if __name__ == '__main__':
+ import os.path
+ from pprint import pprint
+ base = os.path.join(os.path.dirname(__file__), 'zoneinfo')
+ tz = build_tzinfo('Australia/Melbourne',
+ open(os.path.join(base, 'Australia', 'Melbourne'), 'rb'))
+ tz = build_tzinfo('US/Eastern',
+ open(os.path.join(base, 'US', 'Eastern'), 'rb'))
+ pprint(tz._utc_transition_times)
diff --git a/src/pytz/tzinfo.py b/src/pytz/tzinfo.py
new file mode 100644
index 0000000..725978d
--- /dev/null
+++ b/src/pytz/tzinfo.py
@@ -0,0 +1,577 @@
+'''Base classes and helpers for building zone specific tzinfo classes'''
+
+from datetime import datetime, timedelta, tzinfo
+from bisect import bisect_right
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+import pytz
+from pytz.exceptions import AmbiguousTimeError, NonExistentTimeError
+
+__all__ = []
+
+_timedelta_cache = {}
+
+
+def memorized_timedelta(seconds):
+ '''Create only one instance of each distinct timedelta'''
+ try:
+ return _timedelta_cache[seconds]
+ except KeyError:
+ delta = timedelta(seconds=seconds)
+ _timedelta_cache[seconds] = delta
+ return delta
+
+_epoch = datetime.utcfromtimestamp(0)
+_datetime_cache = {0: _epoch}
+
+
+def memorized_datetime(seconds):
+ '''Create only one instance of each distinct datetime'''
+ try:
+ return _datetime_cache[seconds]
+ except KeyError:
+ # NB. We can't just do datetime.utcfromtimestamp(seconds) as this
+ # fails with negative values under Windows (Bug #90096)
+ dt = _epoch + timedelta(seconds=seconds)
+ _datetime_cache[seconds] = dt
+ return dt
+
+_ttinfo_cache = {}
+
+
+def memorized_ttinfo(*args):
+ '''Create only one instance of each distinct tuple'''
+ try:
+ return _ttinfo_cache[args]
+ except KeyError:
+ ttinfo = (
+ memorized_timedelta(args[0]),
+ memorized_timedelta(args[1]),
+ args[2]
+ )
+ _ttinfo_cache[args] = ttinfo
+ return ttinfo
+
+_notime = memorized_timedelta(0)
+
+
+def _to_seconds(td):
+ '''Convert a timedelta to seconds'''
+ return td.seconds + td.days * 24 * 60 * 60
+
+
+class BaseTzInfo(tzinfo):
+ # Overridden in subclass
+ _utcoffset = None
+ _tzname = None
+ zone = None
+
+ def __str__(self):
+ return self.zone
+
+
+class StaticTzInfo(BaseTzInfo):
+ '''A timezone that has a constant offset from UTC
+
+ These timezones are rare, as most locations have changed their
+ offset at some point in their history
+ '''
+ def fromutc(self, dt):
+ '''See datetime.tzinfo.fromutc'''
+ if dt.tzinfo is not None and dt.tzinfo is not self:
+ raise ValueError('fromutc: dt.tzinfo is not self')
+ return (dt + self._utcoffset).replace(tzinfo=self)
+
+ def utcoffset(self, dt, is_dst=None):
+ '''See datetime.tzinfo.utcoffset
+
+ is_dst is ignored for StaticTzInfo, and exists only to
+ retain compatibility with DstTzInfo.
+ '''
+ return self._utcoffset
+
+ def dst(self, dt, is_dst=None):
+ '''See datetime.tzinfo.dst
+
+ is_dst is ignored for StaticTzInfo, and exists only to
+ retain compatibility with DstTzInfo.
+ '''
+ return _notime
+
+ def tzname(self, dt, is_dst=None):
+ '''See datetime.tzinfo.tzname
+
+ is_dst is ignored for StaticTzInfo, and exists only to
+ retain compatibility with DstTzInfo.
+ '''
+ return self._tzname
+
+ def localize(self, dt, is_dst=False):
+ '''Convert naive time to local time'''
+ if dt.tzinfo is not None:
+ raise ValueError('Not naive datetime (tzinfo is already set)')
+ return dt.replace(tzinfo=self)
+
+ def normalize(self, dt, is_dst=False):
+ '''Correct the timezone information on the given datetime.
+
+ This is normally a no-op, as StaticTzInfo timezones never have
+ ambiguous cases to correct:
+
+ >>> from pytz import timezone
+ >>> gmt = timezone('GMT')
+ >>> isinstance(gmt, StaticTzInfo)
+ True
+ >>> dt = datetime(2011, 5, 8, 1, 2, 3, tzinfo=gmt)
+ >>> gmt.normalize(dt) is dt
+ True
+
+ The supported method of converting between timezones is to use
+ datetime.astimezone(). Currently normalize() also works:
+
+ >>> la = timezone('America/Los_Angeles')
+ >>> dt = la.localize(datetime(2011, 5, 7, 1, 2, 3))
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+ >>> gmt.normalize(dt).strftime(fmt)
+ '2011-05-07 08:02:03 GMT (+0000)'
+ '''
+ if dt.tzinfo is self:
+ return dt
+ if dt.tzinfo is None:
+ raise ValueError('Naive time - no tzinfo set')
+ return dt.astimezone(self)
+
+ def __repr__(self):
+ return '<StaticTzInfo %r>' % (self.zone,)
+
+ def __reduce__(self):
+ # Special pickle to zone remains a singleton and to cope with
+ # database changes.
+ return pytz._p, (self.zone,)
+
+
+class DstTzInfo(BaseTzInfo):
+ '''A timezone that has a variable offset from UTC
+
+ The offset might change if daylight saving time comes into effect,
+ or at a point in history when the region decides to change their
+ timezone definition.
+ '''
+ # Overridden in subclass
+
+ # Sorted list of DST transition times, UTC
+ _utc_transition_times = None
+
+ # [(utcoffset, dstoffset, tzname)] corresponding to
+ # _utc_transition_times entries
+ _transition_info = None
+
+ zone = None
+
+ # Set in __init__
+
+ _tzinfos = None
+ _dst = None # DST offset
+
+ def __init__(self, _inf=None, _tzinfos=None):
+ if _inf:
+ self._tzinfos = _tzinfos
+ self._utcoffset, self._dst, self._tzname = _inf
+ else:
+ _tzinfos = {}
+ self._tzinfos = _tzinfos
+ self._utcoffset, self._dst, self._tzname = (
+ self._transition_info[0])
+ _tzinfos[self._transition_info[0]] = self
+ for inf in self._transition_info[1:]:
+ if inf not in _tzinfos:
+ _tzinfos[inf] = self.__class__(inf, _tzinfos)
+
+ def fromutc(self, dt):
+ '''See datetime.tzinfo.fromutc'''
+ if (dt.tzinfo is not None and
+ getattr(dt.tzinfo, '_tzinfos', None) is not self._tzinfos):
+ raise ValueError('fromutc: dt.tzinfo is not self')
+ dt = dt.replace(tzinfo=None)
+ idx = max(0, bisect_right(self._utc_transition_times, dt) - 1)
+ inf = self._transition_info[idx]
+ return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf])
+
+ def normalize(self, dt):
+ '''Correct the timezone information on the given datetime
+
+ If date arithmetic crosses DST boundaries, the tzinfo
+ is not magically adjusted. This method normalizes the
+ tzinfo to the correct one.
+
+ To test, first we need to do some setup
+
+ >>> from pytz import timezone
+ >>> utc = timezone('UTC')
+ >>> eastern = timezone('US/Eastern')
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+
+ We next create a datetime right on an end-of-DST transition point,
+ the instant when the wallclocks are wound back one hour.
+
+ >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
+ >>> loc_dt = utc_dt.astimezone(eastern)
+ >>> loc_dt.strftime(fmt)
+ '2002-10-27 01:00:00 EST (-0500)'
+
+ Now, if we subtract a few minutes from it, note that the timezone
+ information has not changed.
+
+ >>> before = loc_dt - timedelta(minutes=10)
+ >>> before.strftime(fmt)
+ '2002-10-27 00:50:00 EST (-0500)'
+
+ But we can fix that by calling the normalize method
+
+ >>> before = eastern.normalize(before)
+ >>> before.strftime(fmt)
+ '2002-10-27 01:50:00 EDT (-0400)'
+
+ The supported method of converting between timezones is to use
+ datetime.astimezone(). Currently, normalize() also works:
+
+ >>> th = timezone('Asia/Bangkok')
+ >>> am = timezone('Europe/Amsterdam')
+ >>> dt = th.localize(datetime(2011, 5, 7, 1, 2, 3))
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+ >>> am.normalize(dt).strftime(fmt)
+ '2011-05-06 20:02:03 CEST (+0200)'
+ '''
+ if dt.tzinfo is None:
+ raise ValueError('Naive time - no tzinfo set')
+
+ # Convert dt in localtime to UTC
+ offset = dt.tzinfo._utcoffset
+ dt = dt.replace(tzinfo=None)
+ dt = dt - offset
+ # convert it back, and return it
+ return self.fromutc(dt)
+
+ def localize(self, dt, is_dst=False):
+ '''Convert naive time to local time.
+
+ This method should be used to construct localtimes, rather
+ than passing a tzinfo argument to a datetime constructor.
+
+ is_dst is used to determine the correct timezone in the ambigous
+ period at the end of daylight saving time.
+
+ >>> from pytz import timezone
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+ >>> amdam = timezone('Europe/Amsterdam')
+ >>> dt = datetime(2004, 10, 31, 2, 0, 0)
+ >>> loc_dt1 = amdam.localize(dt, is_dst=True)
+ >>> loc_dt2 = amdam.localize(dt, is_dst=False)
+ >>> loc_dt1.strftime(fmt)
+ '2004-10-31 02:00:00 CEST (+0200)'
+ >>> loc_dt2.strftime(fmt)
+ '2004-10-31 02:00:00 CET (+0100)'
+ >>> str(loc_dt2 - loc_dt1)
+ '1:00:00'
+
+ Use is_dst=None to raise an AmbiguousTimeError for ambiguous
+ times at the end of daylight saving time
+
+ >>> try:
+ ... loc_dt1 = amdam.localize(dt, is_dst=None)
+ ... except AmbiguousTimeError:
+ ... print('Ambiguous')
+ Ambiguous
+
+ is_dst defaults to False
+
+ >>> amdam.localize(dt) == amdam.localize(dt, False)
+ True
+
+ is_dst is also used to determine the correct timezone in the
+ wallclock times jumped over at the start of daylight saving time.
+
+ >>> pacific = timezone('US/Pacific')
+ >>> dt = datetime(2008, 3, 9, 2, 0, 0)
+ >>> ploc_dt1 = pacific.localize(dt, is_dst=True)
+ >>> ploc_dt2 = pacific.localize(dt, is_dst=False)
+ >>> ploc_dt1.strftime(fmt)
+ '2008-03-09 02:00:00 PDT (-0700)'
+ >>> ploc_dt2.strftime(fmt)
+ '2008-03-09 02:00:00 PST (-0800)'
+ >>> str(ploc_dt2 - ploc_dt1)
+ '1:00:00'
+
+ Use is_dst=None to raise a NonExistentTimeError for these skipped
+ times.
+
+ >>> try:
+ ... loc_dt1 = pacific.localize(dt, is_dst=None)
+ ... except NonExistentTimeError:
+ ... print('Non-existent')
+ Non-existent
+ '''
+ if dt.tzinfo is not None:
+ raise ValueError('Not naive datetime (tzinfo is already set)')
+
+ # Find the two best possibilities.
+ possible_loc_dt = set()
+ for delta in [timedelta(days=-1), timedelta(days=1)]:
+ loc_dt = dt + delta
+ idx = max(0, bisect_right(
+ self._utc_transition_times, loc_dt) - 1)
+ inf = self._transition_info[idx]
+ tzinfo = self._tzinfos[inf]
+ loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo))
+ if loc_dt.replace(tzinfo=None) == dt:
+ possible_loc_dt.add(loc_dt)
+
+ if len(possible_loc_dt) == 1:
+ return possible_loc_dt.pop()
+
+ # If there are no possibly correct timezones, we are attempting
+ # to convert a time that never happened - the time period jumped
+ # during the start-of-DST transition period.
+ if len(possible_loc_dt) == 0:
+ # If we refuse to guess, raise an exception.
+ if is_dst is None:
+ raise NonExistentTimeError(dt)
+
+ # If we are forcing the pre-DST side of the DST transition, we
+ # obtain the correct timezone by winding the clock forward a few
+ # hours.
+ elif is_dst:
+ return self.localize(
+ dt + timedelta(hours=6), is_dst=True) - timedelta(hours=6)
+
+ # If we are forcing the post-DST side of the DST transition, we
+ # obtain the correct timezone by winding the clock back.
+ else:
+ return self.localize(
+ dt - timedelta(hours=6),
+ is_dst=False) + timedelta(hours=6)
+
+ # If we get this far, we have multiple possible timezones - this
+ # is an ambiguous case occuring during the end-of-DST transition.
+
+ # If told to be strict, raise an exception since we have an
+ # ambiguous case
+ if is_dst is None:
+ raise AmbiguousTimeError(dt)
+
+ # Filter out the possiblilities that don't match the requested
+ # is_dst
+ filtered_possible_loc_dt = [
+ p for p in possible_loc_dt if bool(p.tzinfo._dst) == is_dst
+ ]
+
+ # Hopefully we only have one possibility left. Return it.
+ if len(filtered_possible_loc_dt) == 1:
+ return filtered_possible_loc_dt[0]
+
+ if len(filtered_possible_loc_dt) == 0:
+ filtered_possible_loc_dt = list(possible_loc_dt)
+
+ # If we get this far, we have in a wierd timezone transition
+ # where the clocks have been wound back but is_dst is the same
+ # in both (eg. Europe/Warsaw 1915 when they switched to CET).
+ # At this point, we just have to guess unless we allow more
+ # hints to be passed in (such as the UTC offset or abbreviation),
+ # but that is just getting silly.
+ #
+ # Choose the earliest (by UTC) applicable timezone if is_dst=True
+ # Choose the latest (by UTC) applicable timezone if is_dst=False
+ # i.e., behave like end-of-DST transition
+ dates = {} # utc -> local
+ for local_dt in filtered_possible_loc_dt:
+ utc_time = (
+ local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset)
+ assert utc_time not in dates
+ dates[utc_time] = local_dt
+ return dates[[min, max][not is_dst](dates)]
+
+ def utcoffset(self, dt, is_dst=None):
+ '''See datetime.tzinfo.utcoffset
+
+ The is_dst parameter may be used to remove ambiguity during DST
+ transitions.
+
+ >>> from pytz import timezone
+ >>> tz = timezone('America/St_Johns')
+ >>> ambiguous = datetime(2009, 10, 31, 23, 30)
+
+ >>> str(tz.utcoffset(ambiguous, is_dst=False))
+ '-1 day, 20:30:00'
+
+ >>> str(tz.utcoffset(ambiguous, is_dst=True))
+ '-1 day, 21:30:00'
+
+ >>> try:
+ ... tz.utcoffset(ambiguous)
+ ... except AmbiguousTimeError:
+ ... print('Ambiguous')
+ Ambiguous
+
+ '''
+ if dt is None:
+ return None
+ elif dt.tzinfo is not self:
+ dt = self.localize(dt, is_dst)
+ return dt.tzinfo._utcoffset
+ else:
+ return self._utcoffset
+
+ def dst(self, dt, is_dst=None):
+ '''See datetime.tzinfo.dst
+
+ The is_dst parameter may be used to remove ambiguity during DST
+ transitions.
+
+ >>> from pytz import timezone
+ >>> tz = timezone('America/St_Johns')
+
+ >>> normal = datetime(2009, 9, 1)
+
+ >>> str(tz.dst(normal))
+ '1:00:00'
+ >>> str(tz.dst(normal, is_dst=False))
+ '1:00:00'
+ >>> str(tz.dst(normal, is_dst=True))
+ '1:00:00'
+
+ >>> ambiguous = datetime(2009, 10, 31, 23, 30)
+
+ >>> str(tz.dst(ambiguous, is_dst=False))
+ '0:00:00'
+ >>> str(tz.dst(ambiguous, is_dst=True))
+ '1:00:00'
+ >>> try:
+ ... tz.dst(ambiguous)
+ ... except AmbiguousTimeError:
+ ... print('Ambiguous')
+ Ambiguous
+
+ '''
+ if dt is None:
+ return None
+ elif dt.tzinfo is not self:
+ dt = self.localize(dt, is_dst)
+ return dt.tzinfo._dst
+ else:
+ return self._dst
+
+ def tzname(self, dt, is_dst=None):
+ '''See datetime.tzinfo.tzname
+
+ The is_dst parameter may be used to remove ambiguity during DST
+ transitions.
+
+ >>> from pytz import timezone
+ >>> tz = timezone('America/St_Johns')
+
+ >>> normal = datetime(2009, 9, 1)
+
+ >>> tz.tzname(normal)
+ 'NDT'
+ >>> tz.tzname(normal, is_dst=False)
+ 'NDT'
+ >>> tz.tzname(normal, is_dst=True)
+ 'NDT'
+
+ >>> ambiguous = datetime(2009, 10, 31, 23, 30)
+
+ >>> tz.tzname(ambiguous, is_dst=False)
+ 'NST'
+ >>> tz.tzname(ambiguous, is_dst=True)
+ 'NDT'
+ >>> try:
+ ... tz.tzname(ambiguous)
+ ... except AmbiguousTimeError:
+ ... print('Ambiguous')
+ Ambiguous
+ '''
+ if dt is None:
+ return self.zone
+ elif dt.tzinfo is not self:
+ dt = self.localize(dt, is_dst)
+ return dt.tzinfo._tzname
+ else:
+ return self._tzname
+
+ def __repr__(self):
+ if self._dst:
+ dst = 'DST'
+ else:
+ dst = 'STD'
+ if self._utcoffset > _notime:
+ return '<DstTzInfo %r %s+%s %s>' % (
+ self.zone, self._tzname, self._utcoffset, dst
+ )
+ else:
+ return '<DstTzInfo %r %s%s %s>' % (
+ self.zone, self._tzname, self._utcoffset, dst
+ )
+
+ def __reduce__(self):
+ # Special pickle to zone remains a singleton and to cope with
+ # database changes.
+ return pytz._p, (
+ self.zone,
+ _to_seconds(self._utcoffset),
+ _to_seconds(self._dst),
+ self._tzname
+ )
+
+
+def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None):
+ """Factory function for unpickling pytz tzinfo instances.
+
+ This is shared for both StaticTzInfo and DstTzInfo instances, because
+ database changes could cause a zones implementation to switch between
+ these two base classes and we can't break pickles on a pytz version
+ upgrade.
+ """
+ # Raises a KeyError if zone no longer exists, which should never happen
+ # and would be a bug.
+ tz = pytz.timezone(zone)
+
+ # A StaticTzInfo - just return it
+ if utcoffset is None:
+ return tz
+
+ # This pickle was created from a DstTzInfo. We need to
+ # determine which of the list of tzinfo instances for this zone
+ # to use in order to restore the state of any datetime instances using
+ # it correctly.
+ utcoffset = memorized_timedelta(utcoffset)
+ dstoffset = memorized_timedelta(dstoffset)
+ try:
+ return tz._tzinfos[(utcoffset, dstoffset, tzname)]
+ except KeyError:
+ # The particular state requested in this timezone no longer exists.
+ # This indicates a corrupt pickle, or the timezone database has been
+ # corrected violently enough to make this particular
+ # (utcoffset,dstoffset) no longer exist in the zone, or the
+ # abbreviation has been changed.
+ pass
+
+ # See if we can find an entry differing only by tzname. Abbreviations
+ # get changed from the initial guess by the database maintainers to
+ # match reality when this information is discovered.
+ for localized_tz in tz._tzinfos.values():
+ if (localized_tz._utcoffset == utcoffset and
+ localized_tz._dst == dstoffset):
+ return localized_tz
+
+ # This (utcoffset, dstoffset) information has been removed from the
+ # zone. Add it back. This might occur when the database maintainers have
+ # corrected incorrect information. datetime instances using this
+ # incorrect information will continue to do so, exactly as they were
+ # before being pickled. This is purely an overly paranoid safety net - I
+ # doubt this will ever been needed in real life.
+ inf = (utcoffset, dstoffset, tzname)
+ tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos)
+ return tz._tzinfos[inf]
diff --git a/src/pytz/zoneinfo b/src/pytz/zoneinfo
new file mode 120000
index 0000000..f169537
--- /dev/null
+++ b/src/pytz/zoneinfo
@@ -0,0 +1 @@
+../../build/etc/zoneinfo \ No newline at end of file
diff --git a/src/setup.cfg b/src/setup.cfg
new file mode 100644
index 0000000..498ec14
--- /dev/null
+++ b/src/setup.cfg
@@ -0,0 +1,2 @@
+[metadata]
+license_file = LICENSE.txt
diff --git a/src/setup.py b/src/setup.py
new file mode 100644
index 0000000..cc00a3f
--- /dev/null
+++ b/src/setup.py
@@ -0,0 +1,66 @@
+'''
+pytz setup script
+'''
+
+import pytz
+import os
+import os.path
+
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+
+me = 'Stuart Bishop'
+memail = 'stuart@stuartbishop.net'
+packages = ['pytz']
+resources = ['zone.tab', 'locales/pytz.pot']
+for dirpath, dirnames, filenames in os.walk(os.path.join('pytz', 'zoneinfo')):
+ # remove the 'pytz' part of the path
+ basepath = dirpath.split(os.path.sep, 1)[1]
+ resources.extend([os.path.join(basepath, filename)
+ for filename in filenames])
+package_data = {'pytz': resources}
+
+assert len(resources) > 10, 'zoneinfo files not found!'
+
+setup(
+ name='pytz',
+ version=pytz.VERSION,
+ zip_safe=True,
+ description='World timezone definitions, modern and historical',
+ long_description=open('README.txt', 'r').read(),
+ author=me,
+ author_email=memail,
+ maintainer=me,
+ maintainer_email=memail,
+ url='http://pythonhosted.org/pytz',
+ license='MIT',
+ keywords=['timezone', 'tzinfo', 'datetime', 'olson', 'time'],
+ packages=packages,
+ package_data=package_data,
+ download_url='https://pypi.org/project/pytz/',
+ platforms=['Independent'],
+ classifiers = [
+ 'Development Status :: 6 - Mature',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.0',
+ 'Programming Language :: Python :: 3.1',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ ],
+)
diff --git a/test_zdump.py b/test_zdump.py
new file mode 100644
index 0000000..3baedfc
--- /dev/null
+++ b/test_zdump.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python2.7
+
+import os.path
+import sys
+sys.path.insert(0, os.path.join('build', 'dist'))
+
+from datetime import datetime, timedelta
+import re
+from time import strptime
+import unittest
+import pytz
+
+
+class ZdumpTestCase(unittest.TestCase):
+ def utc_to_local_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
+ loc_tz = pytz.timezone(zone)
+ self.failUnlessEqual(
+ utc_dt.astimezone(loc_tz).replace(tzinfo=None),
+ loc_dt.replace(tzinfo=None))
+
+ def local_to_utc_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
+ self.failUnlessEqual(
+ loc_dt.astimezone(pytz.utc).replace(tzinfo=None),
+ utc_dt.replace(tzinfo=None))
+
+
+def test_suite():
+ testcases = []
+ raw_data = open(
+ os.path.join(os.path.dirname(__file__), 'zdump.out'), 'r').readlines()
+ last_zone = None
+ test_class = None
+ zdump_line_re = re.compile(r'''(?x)
+ ^([^\s]+) \s+ (.+) \s UT \s+ = \s+ (.+) \s ([^\s]+) \s+
+ isdst=(0|1) \s+ gmtoff=[\-\d]+ \s*$
+ ''')
+ for i in range(0, len(raw_data)):
+ line = raw_data[i]
+ m = zdump_line_re.search(line)
+ if m is None:
+ raise RuntimeError('Dud line %r' % (line,))
+ zone, utc_string, loc_string, tzname, is_dst = m.groups()
+ is_dst = bool(int(is_dst))
+
+ if zone != last_zone:
+ classname = zone.replace(
+ '+', '_plus_').replace('-', '_minus_').replace('/', '_')
+ test_class = type(classname, (ZdumpTestCase,), {})
+ testcases.append(test_class)
+ last_zone = zone
+ skip_next_local = False
+
+ utc_dt = datetime(
+ *strptime(utc_string, '%a %b %d %H:%M:%S %Y')[:6])
+ loc_dt = datetime(
+ *strptime(loc_string, '%a %b %d %H:%M:%S %Y')[:6])
+
+ def round_dt(loc_dt, utc_dt):
+ # Urgh - utcoffset() and dst() have to be rounded to the nearest
+ # minute, so we need to break our tests to match this limitation
+ real_offset = loc_dt - utc_dt
+ secs = real_offset.seconds + real_offset.days * 86400
+ fake_offset = timedelta(seconds=int((secs + 30) // 60) * 60)
+ return utc_dt + fake_offset
+
+ loc_dt = round_dt(loc_dt, utc_dt)
+
+ # If the naive time on the next line is less than on this
+ # line, and we aren't seeing an end-of-dst transition, then
+ # we can't do our local->utc tests for either this nor the
+ # next line since we are in an ambiguous time period (ie.
+ # we have wound back the clock but don't have differing
+ # is_dst flags to resolve the ambiguity)
+ skip_local = skip_next_local
+ skip_next_local = False
+ try:
+ m = zdump_line_re.match(raw_data[i + 1])
+ except IndexError:
+ m = None
+ if m is not None:
+ (next_zone, next_utc_string, next_loc_string,
+ next_tzname, next_is_dst) = m.groups()
+ next_is_dst = bool(int(next_is_dst))
+ if next_zone == zone and next_is_dst == is_dst:
+ next_utc_dt = datetime(
+ *strptime(next_utc_string, '%a %b %d %H:%M:%S %Y')[:6])
+ next_loc_dt = round_dt(
+ datetime(*strptime(
+ next_loc_string, '%a %b %d %H:%M:%S %Y')[:6]),
+ next_utc_dt)
+ if next_loc_dt <= loc_dt:
+ skip_local = True
+ skip_next_local = True
+
+ loc_tz = pytz.timezone(zone)
+ loc_dt = loc_tz.localize(loc_dt, is_dst)
+
+ utc_dt = pytz.utc.localize(utc_dt)
+
+ test_name = 'test_utc_to_local_%04d_%02d_%02d_%02d_%02d_%02d' % (
+ utc_dt.year, utc_dt.month, utc_dt.day,
+ utc_dt.hour, utc_dt.minute, utc_dt.second)
+
+ def test_utc_to_local(
+ self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt,
+ tzname=tzname, is_dst=is_dst):
+ self.utc_to_local_check(zone, utc_dt, loc_dt, tzname, is_dst)
+ test_utc_to_local.__name__ = test_name
+ setattr(test_class, test_name, test_utc_to_local)
+
+ if not skip_local:
+ test_name = 'test_local_to_utc_%04d_%02d_%02d_%02d_%02d_%02d' % (
+ loc_dt.year, loc_dt.month, loc_dt.day,
+ loc_dt.hour, loc_dt.minute, loc_dt.second)
+ if is_dst:
+ test_name += '_dst'
+ else:
+ test_name += '_nodst'
+
+ def test_local_to_utc(
+ self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt,
+ tzname=tzname, is_dst=is_dst):
+ self.local_to_utc_check(zone, utc_dt, loc_dt, tzname, is_dst)
+ test_local_to_utc.__name__ = test_name
+ setattr(test_class, test_name, test_local_to_utc)
+
+ classname = zone.replace(
+ '+', '_plus_').replace('-', '_minus_').replace('/', '_')
+ test_class = type(classname, (ZdumpTestCase,), {})
+ testcases.append(test_class)
+
+ suite = unittest.TestSuite()
+ while testcases:
+ suite.addTest(unittest.makeSuite(testcases.pop()))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
diff --git a/tz/.gitignore b/tz/.gitignore
new file mode 100644
index 0000000..cf3b825
--- /dev/null
+++ b/tz/.gitignore
@@ -0,0 +1,26 @@
+# Files intentionally not tracked by Git.
+# This file is in the public domain.
+*.a
+*.asc
+*.diff
+*.i
+*.o
+*.orig
+*.patch
+*.rej
+*.tar
+*.tar.*
+*.txt
+*.tzs
+*.zi
+*~
+ChangeLog
+check_*
+date
+leapseconds
+tzselect
+version
+version.h
+yearistype
+zdump
+zic
diff --git a/CONTRIBUTING b/tz/CONTRIBUTING
index 01336fc..01336fc 100644
--- a/CONTRIBUTING
+++ b/tz/CONTRIBUTING
diff --git a/LICENSE b/tz/LICENSE
index 8ba4399..8ba4399 100644
--- a/LICENSE
+++ b/tz/LICENSE
diff --git a/tz/Makefile b/tz/Makefile
new file mode 100644
index 0000000..fec0a4f
--- /dev/null
+++ b/tz/Makefile
@@ -0,0 +1,1123 @@
+# Make and install tzdb code and data.
+
+# This file is in the public domain, so clarified as of
+# 2009-05-17 by Arthur David Olson.
+
+# Package name for the code distribution.
+PACKAGE= tzcode
+
+# Version number for the distribution, overridden in the 'tarballs' rule below.
+VERSION= unknown
+
+# Email address for bug reports.
+BUGEMAIL= tz@iana.org
+
+# DATAFORM selects the data format.
+# Available formats represent essentially the same data, albeit
+# possibly with minor discrepancies that users are not likely to notice.
+# To get new features and the best data right away, use:
+# DATAFORM= vanguard
+# To wait a while before using new features, to give downstream users
+# time to upgrade zic (the default), use:
+# DATAFORM= main
+# To wait even longer for new features, use:
+# DATAFORM= rearguard
+DATAFORM= main
+
+# Change the line below for your timezone (after finding the one you want in
+# one of the $(TDATA) source files, or adding it to a source file).
+# Alternatively, if you discover you've got the wrong timezone, you can just
+# zic -l rightzone
+# to correct things.
+# Use the command
+# make zonenames
+# to get a list of the values you can use for LOCALTIME.
+
+LOCALTIME= GMT
+
+# The POSIXRULES macro controls interpretation of nonstandard and obsolete
+# POSIX-like TZ settings like TZ='EET-2EEST' that lack DST transition rules.
+# In the reference implementation, if you want something other than Eastern
+# United States time as a template for handling these settings, you can
+# change the line below (after finding the timezone you want in the
+# one of the $(TDATA) source files, or adding it to a source file).
+# A setting like TZ='EET-2EEST' is supposed to use the rules in the
+# template file to determine "spring forward" and "fall back" days and
+# times; the environment variable itself specifies UT offsets of standard and
+# daylight saving time.
+# Alternatively, if you discover you've got the wrong timezone, you can just
+# zic -p rightzone
+# to correct things.
+# Use the command
+# make zonenames
+# to get a list of the values you can use for POSIXRULES.
+#
+# If POSIXRULES is empty, no template is installed; this is the intended
+# future default for POSIXRULES.
+#
+# Nonempty POSIXRULES is obsolete and should not be relied on, because:
+# * It does not work correctly in popular implementations such as GNU/Linux.
+# * It does not work in the tzdb implementation for timestamps after 2037.
+# * It is incompatible with 'zic -b slim' if POSIXRULES specifies transitions
+# at standard time or UT rather than at local time.
+# In short, software should avoid ruleless settings like TZ='EET-2EEST'
+# and so should not depend on the value of POSIXRULES.
+
+POSIXRULES= America/New_York
+
+# Also see TZDEFRULESTRING below, which takes effect only
+# if the time zone files cannot be accessed.
+
+
+# Installation locations.
+#
+# The defaults are suitable for Debian, except that if REDO is
+# posix_right or right_posix then files that Debian puts under
+# /usr/share/zoneinfo/posix and /usr/share/zoneinfo/right are instead
+# put under /usr/share/zoneinfo-posix and /usr/share/zoneinfo-leaps,
+# respectively. Problems with the Debian approach are discussed in
+# the commentary for the right_posix rule (below).
+
+# Destination directory, which can be used for staging.
+# 'make DESTDIR=/stage install' installs under /stage (e.g., to
+# /stage/etc/localtime instead of to /etc/localtime). Files under
+# /stage are not intended to work as-is, but can be copied by hand to
+# the root directory later. If DESTDIR is empty, 'make install' does
+# not stage, but installs directly into production locations.
+DESTDIR =
+
+# Everything is installed into subdirectories of TOPDIR, and used there.
+# TOPDIR should be empty (meaning the root directory),
+# or a directory name that does not end in "/".
+# TOPDIR should be empty or an absolute name unless you're just testing.
+TOPDIR =
+
+# The default local timezone is taken from the file TZDEFAULT.
+TZDEFAULT = $(TOPDIR)/etc/localtime
+
+# The subdirectory containing installed program and data files, and
+# likewise for installed files that can be shared among architectures.
+# These should be relative file names.
+USRDIR = usr
+USRSHAREDIR = $(USRDIR)/share
+
+# "Compiled" timezone information is placed in the "TZDIR" directory
+# (and subdirectories).
+# TZDIR_BASENAME should not contain "/" and should not be ".", ".." or empty.
+TZDIR_BASENAME= zoneinfo
+TZDIR = $(TOPDIR)/$(USRSHAREDIR)/$(TZDIR_BASENAME)
+
+# The "tzselect" and (if you do "make INSTALL") "date" commands go in:
+BINDIR = $(TOPDIR)/$(USRDIR)/bin
+
+# The "zdump" command goes in:
+ZDUMPDIR = $(BINDIR)
+
+# The "zic" command goes in:
+ZICDIR = $(TOPDIR)/$(USRDIR)/sbin
+
+# Manual pages go in subdirectories of. . .
+MANDIR = $(TOPDIR)/$(USRSHAREDIR)/man
+
+# Library functions are put in an archive in LIBDIR.
+LIBDIR = $(TOPDIR)/$(USRDIR)/lib
+
+
+# Types to try, as an alternative to time_t.
+TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL)
+TIME_T_ALTERNATIVES_HEAD = int64_t
+TIME_T_ALTERNATIVES_TAIL = int32_t uint32_t uint64_t
+
+# What kind of TZif data files to generate. (TZif is the binary time
+# zone data format that zic generates; see Internet RFC 8536.)
+# If you want only POSIX time, with time values interpreted as
+# seconds since the epoch (not counting leap seconds), use
+# REDO= posix_only
+# below. If you want only "right" time, with values interpreted
+# as seconds since the epoch (counting leap seconds), use
+# REDO= right_only
+# below. If you want both sets of data available, with leap seconds not
+# counted normally, use
+# REDO= posix_right
+# below. If you want both sets of data available, with leap seconds counted
+# normally, use
+# REDO= right_posix
+# below. POSIX mandates that leap seconds not be counted; for compatibility
+# with it, use "posix_only" or "posix_right". Use POSIX time on systems with
+# leap smearing; this can work better than unsmeared "right" time with
+# applications that are not leap second aware, and is closer to unsmeared
+# "right" time than unsmeared POSIX time is (e.g., 0.5 vs 1.0 s max error).
+
+REDO= posix_right
+
+# To install data in text form that has all the information of the TZif data,
+# (optionally incorporating leap second information), use
+# TZDATA_TEXT= tzdata.zi leapseconds
+# To install text data without leap second information (e.g., because
+# REDO='posix_only'), use
+# TZDATA_TEXT= tzdata.zi
+# To avoid installing text data, use
+# TZDATA_TEXT=
+
+TZDATA_TEXT= leapseconds tzdata.zi
+
+# For backward-compatibility links for old zone names, use
+# BACKWARD= backward
+# If you also want the link US/Pacific-New, even though it is confusing
+# and is planned to be removed from the database eventually, use
+# BACKWARD= backward pacificnew
+# To omit these links, use
+# BACKWARD=
+
+BACKWARD= backward
+
+# If you want out-of-scope and often-wrong data from the file 'backzone', use
+# PACKRATDATA= backzone
+# To omit this data, use
+# PACKRATDATA=
+
+PACKRATDATA=
+
+# The name of a locale using the UTF-8 encoding, used during self-tests.
+# The tests are skipped if the name does not appear to work on this system.
+
+UTF8_LOCALE= en_US.utf8
+
+# Since "." may not be in PATH...
+
+YEARISTYPE= ./yearistype
+
+# Non-default libraries needed to link.
+LDLIBS=
+
+# Add the following to the end of the "CFLAGS=" line as needed to override
+# defaults specified in the source code. "-DFOO" is equivalent to "-DFOO=1".
+# -DDEPRECATE_TWO_DIGIT_YEARS for optional runtime warnings about strftime
+# formats that generate only the last two digits of year numbers
+# -DEPOCH_LOCAL if the 'time' function returns local time not UT
+# -DEPOCH_OFFSET=N if the 'time' function returns a value N greater
+# than what POSIX specifies, assuming local time is UT.
+# For example, N is 252460800 on AmigaOS.
+# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
+# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
+# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
+# -DHAVE_GENERIC=0 if _Generic does not work
+# -DHAVE_GETTEXT if 'gettext' works (e.g., GNU/Linux, FreeBSD, Solaris)
+# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
+# ctime_r and asctime_r incompatibly with the POSIX standard
+# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
+# -DHAVE_INTTYPES_H if you have a non-C99 compiler with <inttypes.h>
+# -DHAVE_LINK=0 if your system lacks a link function
+# -DHAVE_LOCALTIME_R=0 if your system lacks a localtime_r function
+# -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
+# localtime_rz can make zdump significantly faster, but is nonstandard.
+# -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
+# functions like 'link' or variables like 'tzname' required by POSIX
+# -DHAVE_SNPRINTF=0 if your system lacks the snprintf function
+# -DHAVE_STDBOOL_H if you have a non-C99 compiler with <stdbool.h>
+# -DHAVE_STDINT_H if you have a non-C99 compiler with <stdint.h>
+# -DHAVE_STRFTIME_L if <time.h> declares locale_t and strftime_l
+# -DHAVE_STRDUP=0 if your system lacks the strdup function
+# -DHAVE_STRTOLL=0 if your system lacks the strtoll function
+# -DHAVE_SYMLINK=0 if your system lacks the symlink function
+# -DHAVE_SYS_STAT_H=0 if your compiler lacks a <sys/stat.h>
+# -DHAVE_SYS_WAIT_H=0 if your compiler lacks a <sys/wait.h>
+# -DHAVE_TZSET=0 if your system lacks a tzset function
+# -DHAVE_UNISTD_H=0 if your compiler lacks a <unistd.h>
+# -Dlocale_t=XXX if your system uses XXX instead of locale_t
+# -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
+# with external linkage, e.g., applications cannot define 'localtime'.
+# -Dssize_t=long on hosts like MS-Windows that lack ssize_t
+# -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has
+# security implications and is not recommended for general use
+# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
+# not needed by the main-program tz code, which is single-threaded.
+# Append other compiler flags as needed, e.g., -pthread on GNU/Linux.
+# -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
+# This is intended for internal use only; it mangles external names.
+# -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
+# -DTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
+# the default is system-supplied, typically "/usr/lib/locale"
+# -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified
+# DST transitions if the time zone files cannot be accessed
+# -DUNINIT_TRAP if reading uninitialized storage can cause problems
+# other than simply getting garbage data
+# -DUSE_LTZ=0 to build zdump with the system time zone library
+# Also set TZDOBJS=zdump.o and CHECK_TIME_T_ALTERNATIVES= below.
+# -DZIC_BLOAT_DEFAULT=\"slim\" to default zic's -b option to "slim", and
+# similarly for "fat". Fat TZif files work around incompatibilities
+# and bugs in some TZif readers, notably readers that mishandle 64-bit
+# data in TZif files. Slim TZif files are more efficient and do not
+# work around these incompatibilities and bugs. If not given, the
+# current default is "fat" but this is intended to change as readers
+# requiring fat files often mishandle timestamps after 2037 anyway.
+# -DZIC_MAX_ABBR_LEN_WO_WARN=3
+# (or some other number) to set the maximum time zone abbreviation length
+# that zic will accept without a warning (the default is 6)
+# $(GCC_DEBUG_FLAGS) if you are using recent GCC and want lots of checking
+# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
+GCC_INSTRUMENT = \
+ -fsanitize=undefined -fsanitize-address-use-after-scope \
+ -fsanitize-undefined-trap-on-error -fstack-protector
+GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 -fno-common \
+ $(GCC_INSTRUMENT) \
+ -Wall -Wextra \
+ -Walloc-size-larger-than=100000 -Warray-bounds=2 \
+ -Wbad-function-cast -Wcast-align=strict -Wdate-time \
+ -Wdeclaration-after-statement -Wdouble-promotion \
+ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \
+ -Winit-self -Wjump-misses-init -Wlogical-op \
+ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
+ -Wold-style-definition -Woverlength-strings -Wpointer-arith \
+ -Wshadow -Wshift-overflow=2 -Wstrict-prototypes -Wstringop-overflow=4 \
+ -Wstringop-truncation -Wsuggest-attribute=cold \
+ -Wsuggest-attribute=const -Wsuggest-attribute=format \
+ -Wsuggest-attribute=malloc \
+ -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \
+ -Wtrampolines -Wundef -Wuninitialized -Wunused \
+ -Wvariadic-macros -Wvla -Wwrite-strings \
+ -Wno-address -Wno-format-nonliteral -Wno-sign-compare \
+ -Wno-type-limits -Wno-unused-parameter
+#
+# If your system has a "GMT offset" field in its "struct tm"s
+# (or if you decide to add such a field in your system's "time.h" file),
+# add the name to a define such as
+# -DTM_GMTOFF=tm_gmtoff
+# to the end of the "CFLAGS=" line. If not defined, the code attempts to
+# guess TM_GMTOFF from other macros; define NO_TM_GMTOFF to suppress this.
+# Similarly, if your system has a "zone abbreviation" field, define
+# -DTM_ZONE=tm_zone
+# and define NO_TM_ZONE to suppress any guessing. These two fields are not
+# required by POSIX, but are widely available on GNU/Linux and BSD systems.
+#
+# The next batch of options control support for external variables
+# exported by tzcode. In practice these variables are less useful
+# than TM_GMTOFF and TM_ZONE. However, most of them are standardized.
+# #
+# # To omit or support the external variable "tzname", add one of:
+# # -DHAVE_TZNAME=0
+# # -DHAVE_TZNAME=1
+# # to the "CFLAGS=" line. "tzname" is required by POSIX 1988 and later.
+# # If not defined, the code attempts to guess HAVE_TZNAME from other macros.
+# # Warning: unless time_tz is also defined, HAVE_TZNAME=1 can cause
+# # crashes when combined with some platforms' standard libraries,
+# # presumably due to memory allocation issues.
+# #
+# # To omit or support the external variables "timezone" and "daylight", add
+# # -DUSG_COMPAT=0
+# # -DUSG_COMPAT=1
+# # to the "CFLAGS=" line; "timezone" and "daylight" are inspired by
+# # Unix Systems Group code and are required by POSIX 2008 (with XSI) and later.
+# # If not defined, the code attempts to guess USG_COMPAT from other macros.
+# #
+# # To support the external variable "altzone", add
+# # -DALTZONE
+# # to the end of the "CFLAGS=" line; although "altzone" appeared in
+# # System V Release 3.1 it has not been standardized.
+#
+# If you want functions that were inspired by early versions of X3J11's work,
+# add
+# -DSTD_INSPIRED
+# to the end of the "CFLAGS=" line. This arranges for the functions
+# "tzsetwall", "offtime", "timelocal", "timegm", "timeoff",
+# "posix2time", and "time2posix" to be added to the time conversion library.
+# "tzsetwall" is like "tzset" except that it arranges for local wall clock
+# time (rather than the timezone specified in the TZ environment variable)
+# to be used.
+# "offtime" is like "gmtime" except that it accepts a second (long) argument
+# that gives an offset to add to the time_t when converting it.
+# "timelocal" is equivalent to "mktime".
+# "timegm" is like "timelocal" except that it turns a struct tm into
+# a time_t using UT (rather than local time as "timelocal" does).
+# "timeoff" is like "timegm" except that it accepts a second (long) argument
+# that gives an offset to use when converting to a time_t.
+# "posix2time" and "time2posix" are described in an included manual page.
+# X3J11's work does not describe any of these functions.
+# Sun has provided "tzsetwall", "timelocal", and "timegm" in SunOS 4.0.
+# These functions may well disappear in future releases of the time
+# conversion package.
+#
+# If you don't want functions that were inspired by NetBSD, add
+# -DNETBSD_INSPIRED=0
+# to the end of the "CFLAGS=" line. Otherwise, the functions
+# "localtime_rz", "mktime_z", "tzalloc", and "tzfree" are added to the
+# time library, and if STD_INSPIRED is also defined the functions
+# "posix2time_z" and "time2posix_z" are added as well.
+# The functions ending in "_z" (or "_rz") are like their unsuffixed
+# (or suffixed-by-"_r") counterparts, except with an extra first
+# argument of opaque type timezone_t that specifies the timezone.
+# "tzalloc" allocates a timezone_t value, and "tzfree" frees it.
+#
+# If you want to allocate state structures in localtime, add
+# -DALL_STATE
+# to the end of the "CFLAGS=" line. Storage is obtained by calling malloc.
+#
+# NIST-PCTS:151-2, Version 1.4, (1993-12-03) is a test suite put
+# out by the National Institute of Standards and Technology
+# which claims to test C and Posix conformance. If you want to pass PCTS, add
+# -DPCTS
+# to the end of the "CFLAGS=" line.
+#
+# If you want strict compliance with XPG4 as of 1994-04-09, add
+# -DXPG4_1994_04_09
+# to the end of the "CFLAGS=" line. This causes "strftime" to always return
+# 53 as a week number (rather than 52 or 53) for January days before
+# January's first Monday when a "%V" format is used and January 1
+# falls on a Friday, Saturday, or Sunday.
+
+CFLAGS=
+
+# Linker flags. Default to $(LFLAGS) for backwards compatibility
+# to release 2012h and earlier.
+
+LDFLAGS= $(LFLAGS)
+
+# For leap seconds, this Makefile uses LEAPSECONDS='-L leapseconds' in
+# submake command lines. The default is no leap seconds.
+
+LEAPSECONDS=
+
+# The zic command and its arguments.
+
+zic= ./zic
+ZIC= $(zic) $(ZFLAGS)
+
+# To shrink the size of installed TZif files,
+# append "-r @N" to omit data before N-seconds-after-the-Epoch.
+# You can also append "-b slim" if that is not already the default;
+# see ZIC_BLOAT_DEFAULT above.
+# See the zic man page for more about -b and -r.
+ZFLAGS=
+
+# How to use zic to install TZif files.
+
+ZIC_INSTALL= $(ZIC) -d '$(DESTDIR)$(TZDIR)' $(LEAPSECONDS)
+
+# The name of a Posix-compliant 'awk' on your system.
+# Older 'mawk' versions, such as the 'mawk' in Ubuntu 16.04, might dump core;
+# on Ubuntu you can work around this with
+# AWK= gawk
+AWK= awk
+
+# The full path name of a Posix-compliant shell, preferably one that supports
+# the Korn shell's 'select' statement as an extension.
+# These days, Bash is the most popular.
+# It should be OK to set this to /bin/sh, on platforms where /bin/sh
+# lacks 'select' or doesn't completely conform to Posix, but /bin/bash
+# is typically nicer if it works.
+KSHELL= /bin/bash
+
+# Name of curl <https://curl.haxx.se/>, used for HTML validation.
+CURL= curl
+
+# Name of GNU Privacy Guard <https://gnupg.org/>, used to sign distributions.
+GPG= gpg
+
+# The path where SGML DTDs are kept and the catalog file(s) to use when
+# validating HTML 4.01. The default should work on both Debian and Red Hat.
+SGML_TOPDIR= /usr
+SGML_DTDDIR= $(SGML_TOPDIR)/share/xml/w3c-sgml-lib/schema/dtd
+SGML_SEARCH_PATH= $(SGML_DTDDIR)/REC-html401-19991224
+SGML_CATALOG_FILES= \
+ $(SGML_TOPDIR)/share/doc/w3-recs/html/www.w3.org/TR/1999/REC-html401-19991224/HTML4.cat:$(SGML_TOPDIR)/share/sgml/html/4.01/HTML4.cat
+
+# The name, arguments and environment of a program to validate HTML 4.01.
+# See <http://openjade.sourceforge.net/doc/> for a validator, and
+# <https://validator.w3.org/source/> for a validation library.
+# Set VALIDATE=':' if you do not have such a program.
+VALIDATE = nsgmls
+VALIDATE_FLAGS = -s -B -wall -wno-unused-param
+VALIDATE_ENV = \
+ SGML_CATALOG_FILES='$(SGML_CATALOG_FILES)' \
+ SGML_SEARCH_PATH='$(SGML_SEARCH_PATH)' \
+ SP_CHARSET_FIXED=YES \
+ SP_ENCODING=UTF-8
+
+# This expensive test requires USE_LTZ.
+# To suppress it, define this macro to be empty.
+CHECK_TIME_T_ALTERNATIVES = check_time_t_alternatives
+
+# SAFE_CHAR is a regular expression that matches a safe character.
+# Some parts of this distribution are limited to safe characters;
+# others can use any UTF-8 character.
+# For now, the safe characters are a safe subset of ASCII.
+# The caller must set the shell variable 'sharp' to the character '#',
+# since Makefile macros cannot contain '#'.
+# TAB_CHAR is a single tab character, in single quotes.
+TAB_CHAR= ' '
+SAFE_CHARSET1= $(TAB_CHAR)' !\"'$$sharp'$$%&'\''()*+,./0123456789:;<=>?@'
+SAFE_CHARSET2= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\^_`'
+SAFE_CHARSET3= 'abcdefghijklmnopqrstuvwxyz{|}~'
+SAFE_CHARSET= $(SAFE_CHARSET1)$(SAFE_CHARSET2)$(SAFE_CHARSET3)
+SAFE_CHAR= '[]'$(SAFE_CHARSET)'-]'
+
+# These characters are Latin-1, and so are likely to be displayable
+# even in editors with limited character sets.
+UNUSUAL_OK_LATIN_1 = «°±»½¾×
+# This IPA symbol is represented in Unicode as the composition of
+# U+0075 and U+032F, and U+032F is not considered alphabetic by some
+# grep implementations that do not grok composition.
+UNUSUAL_OK_IPA = u̯
+# Non-ASCII non-letters that OK_CHAR allows, as these characters are
+# useful in commentary.
+UNUSUAL_OK_CHARSET= $(UNUSUAL_OK_LATIN_1)$(UNUSUAL_OK_IPA)
+
+# OK_CHAR matches any character allowed in the distributed files.
+# This is the same as SAFE_CHAR, except that UNUSUAL_OK_CHARSET and
+# multibyte letters are also allowed so that commentary can contain a
+# few safe symbols and people's names and can quote non-English sources.
+# Other non-letters are limited to ASCII renderings for the
+# convenience of maintainers using XEmacs 21.5.34, which by default
+# mishandles Unicode characters U+0100 and greater.
+OK_CHAR= '[][:alpha:]$(UNUSUAL_OK_CHARSET)'$(SAFE_CHARSET)'-]'
+
+# SAFE_LINE matches a line of safe characters.
+# SAFE_SHARP_LINE is similar, except any OK character can follow '#';
+# this is so that comments can contain non-ASCII characters.
+# OK_LINE matches a line of OK characters.
+SAFE_LINE= '^'$(SAFE_CHAR)'*$$'
+SAFE_SHARP_LINE='^'$(SAFE_CHAR)'*('$$sharp$(OK_CHAR)'*)?$$'
+OK_LINE= '^'$(OK_CHAR)'*$$'
+
+# Flags to give 'tar' when making a distribution.
+# Try to use flags appropriate for GNU tar.
+GNUTARFLAGS= --numeric-owner --owner=0 --group=0 --mode=go+u,go-w --sort=name
+TARFLAGS= `if tar $(GNUTARFLAGS) --version >/dev/null 2>&1; \
+ then echo $(GNUTARFLAGS); \
+ else :; \
+ fi`
+
+# Flags to give 'gzip' when making a distribution.
+GZIPFLAGS= -9n
+
+###############################################################################
+
+#MAKE= make
+
+cc= cc
+CC= $(cc) -DTZDIR='"$(TZDIR)"'
+
+AR= ar
+
+# ':' on typical hosts; 'ranlib' on the ancient hosts that still need ranlib.
+RANLIB= :
+
+TZCOBJS= zic.o
+TZDOBJS= zdump.o localtime.o asctime.o strftime.o
+DATEOBJS= date.o localtime.o strftime.o asctime.o
+LIBSRCS= localtime.c asctime.c difftime.c
+LIBOBJS= localtime.o asctime.o difftime.o
+HEADERS= tzfile.h private.h
+NONLIBSRCS= zic.c zdump.c
+NEWUCBSRCS= date.c strftime.c
+SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) \
+ tzselect.ksh workman.sh
+MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \
+ tzfile.5 tzselect.8 zic.8 zdump.8
+MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \
+ time2posix.3.txt \
+ tzfile.5.txt tzselect.8.txt zic.8.txt zdump.8.txt \
+ date.1.txt
+COMMON= calendars CONTRIBUTING LICENSE Makefile \
+ NEWS README theory.html version
+WEB_PAGES= tz-art.html tz-how-to.html tz-link.html
+CHECK_WEB_PAGES=check_theory.html check_tz-art.html \
+ check_tz-how-to.html check_tz-link.html
+DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES)
+PRIMARY_YDATA= africa antarctica asia australasia \
+ europe northamerica southamerica
+YDATA= $(PRIMARY_YDATA) etcetera
+NDATA= systemv factory
+TDATA_TO_CHECK= $(YDATA) $(NDATA) backward pacificnew
+TDATA= $(YDATA) $(NDATA) $(BACKWARD)
+ZONETABLES= zone1970.tab zone.tab
+TABDATA= iso3166.tab $(TZDATA_TEXT) $(ZONETABLES)
+LEAP_DEPS= leapseconds.awk leap-seconds.list
+TZDATA_ZI_DEPS= ziguard.awk zishrink.awk version $(TDATA) $(PACKRATDATA)
+DSTDATA_ZI_DEPS= ziguard.awk $(TDATA) $(PACKRATDATA)
+DATA= $(TDATA_TO_CHECK) backzone iso3166.tab leap-seconds.list \
+ leapseconds yearistype.sh $(ZONETABLES)
+AWK_SCRIPTS= checklinks.awk checktab.awk leapseconds.awk \
+ ziguard.awk zishrink.awk
+MISC= $(AWK_SCRIPTS) zoneinfo2tdf.pl
+TZS_YEAR= 2050
+TZS_CUTOFF_FLAG= -c $(TZS_YEAR)
+TZS= to$(TZS_YEAR).tzs
+TZS_NEW= to$(TZS_YEAR)new.tzs
+TZS_DEPS= $(PRIMARY_YDATA) asctime.c localtime.c \
+ private.h tzfile.h zdump.c zic.c
+# EIGHT_YARDS is just a yard short of the whole ENCHILADA.
+EIGHT_YARDS = $(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC) tzdata.zi
+ENCHILADA = $(EIGHT_YARDS) $(TZS)
+
+# Consult these files when deciding whether to rebuild the 'version' file.
+# This list is not the same as the output of 'git ls-files', since
+# .gitignore is not distributed.
+VERSION_DEPS= \
+ calendars CONTRIBUTING LICENSE Makefile NEWS README \
+ africa antarctica asctime.c asia australasia \
+ backward backzone \
+ checklinks.awk checktab.awk \
+ date.1 date.c difftime.c \
+ etcetera europe factory iso3166.tab \
+ leap-seconds.list leapseconds.awk localtime.c \
+ newctime.3 newstrftime.3 newtzset.3 northamerica \
+ pacificnew private.h \
+ southamerica strftime.c systemv theory.html \
+ time2posix.3 tz-art.html tz-how-to.html tz-link.html \
+ tzfile.5 tzfile.h tzselect.8 tzselect.ksh \
+ workman.sh yearistype.sh \
+ zdump.8 zdump.c zic.8 zic.c \
+ ziguard.awk zishrink.awk \
+ zone.tab zone1970.tab zoneinfo2tdf.pl
+
+# And for the benefit of csh users on systems that assume the user
+# shell should be used to handle commands in Makefiles. . .
+
+SHELL= /bin/sh
+
+all: tzselect yearistype zic zdump libtz.a $(TABDATA) \
+ vanguard.zi main.zi rearguard.zi
+
+ALL: all date $(ENCHILADA)
+
+install: all $(DATA) $(REDO) $(MANS)
+ mkdir -p '$(DESTDIR)$(BINDIR)' \
+ '$(DESTDIR)$(ZDUMPDIR)' '$(DESTDIR)$(ZICDIR)' \
+ '$(DESTDIR)$(LIBDIR)' \
+ '$(DESTDIR)$(MANDIR)/man3' '$(DESTDIR)$(MANDIR)/man5' \
+ '$(DESTDIR)$(MANDIR)/man8'
+ $(ZIC_INSTALL) -l $(LOCALTIME) \
+ `case '$(POSIXRULES)' in ?*) echo '-p';; esac \
+ ` $(POSIXRULES) \
+ -t '$(DESTDIR)$(TZDEFAULT)'
+ cp -f $(TABDATA) '$(DESTDIR)$(TZDIR)/.'
+ cp tzselect '$(DESTDIR)$(BINDIR)/.'
+ cp zdump '$(DESTDIR)$(ZDUMPDIR)/.'
+ cp zic '$(DESTDIR)$(ZICDIR)/.'
+ cp libtz.a '$(DESTDIR)$(LIBDIR)/.'
+ $(RANLIB) '$(DESTDIR)$(LIBDIR)/libtz.a'
+ cp -f newctime.3 newtzset.3 '$(DESTDIR)$(MANDIR)/man3/.'
+ cp -f tzfile.5 '$(DESTDIR)$(MANDIR)/man5/.'
+ cp -f tzselect.8 zdump.8 zic.8 '$(DESTDIR)$(MANDIR)/man8/.'
+
+INSTALL: ALL install date.1
+ mkdir -p '$(DESTDIR)$(BINDIR)' '$(DESTDIR)$(MANDIR)/man1'
+ cp date '$(DESTDIR)$(BINDIR)/.'
+ cp -f date.1 '$(DESTDIR)$(MANDIR)/man1/.'
+
+version: $(VERSION_DEPS)
+ { (type git) >/dev/null 2>&1 && \
+ V=`git describe --match '[0-9][0-9][0-9][0-9][a-z]*' \
+ --abbrev=7 --dirty` || \
+ V='$(VERSION)'; } && \
+ printf '%s\n' "$$V" >$@.out
+ mv $@.out $@
+
+# These files can be tailored by setting BACKWARD and PACKRATDATA.
+vanguard.zi main.zi rearguard.zi: $(DSTDATA_ZI_DEPS)
+ $(AWK) -v DATAFORM=`expr $@ : '\(.*\).zi'` -f ziguard.awk \
+ $(TDATA) $(PACKRATDATA) >$@.out
+ mv $@.out $@
+# This file has a version comment that attempts to capture any tailoring
+# via BACKWARD, DATAFORM, PACKRATDATA, and REDO.
+tzdata.zi: $(DATAFORM).zi version zishrink.awk
+ version=`sed 1q version` && \
+ LC_ALL=C $(AWK) \
+ -v dataform='$(DATAFORM)' \
+ -v deps='$(DSTDATA_ZI_DEPS) zishrink.awk' \
+ -v redo='$(REDO)' \
+ -v version="$$version" \
+ -f zishrink.awk \
+ $(DATAFORM).zi >$@.out
+ mv $@.out $@
+
+version.h: version
+ VERSION=`cat version` && printf '%s\n' \
+ 'static char const PKGVERSION[]="($(PACKAGE)) ";' \
+ "static char const TZVERSION[]=\"$$VERSION\";" \
+ 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";' \
+ >$@.out
+ mv $@.out $@
+
+zdump: $(TZDOBJS)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS)
+
+zic: $(TZCOBJS)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS)
+
+yearistype: yearistype.sh
+ cp yearistype.sh yearistype
+ chmod +x yearistype
+
+leapseconds: $(LEAP_DEPS)
+ $(AWK) -f leapseconds.awk leap-seconds.list >$@.out
+ mv $@.out $@
+
+# Arguments to pass to submakes of install_data.
+# They can be overridden by later submake arguments.
+INSTALLARGS = \
+ BACKWARD='$(BACKWARD)' \
+ DESTDIR='$(DESTDIR)' \
+ LEAPSECONDS='$(LEAPSECONDS)' \
+ PACKRATDATA='$(PACKRATDATA)' \
+ TZDEFAULT='$(TZDEFAULT)' \
+ TZDIR='$(TZDIR)' \
+ YEARISTYPE='$(YEARISTYPE)' \
+ ZIC='$(ZIC)'
+
+INSTALL_DATA_DEPS = zic leapseconds yearistype tzdata.zi
+
+# 'make install_data' installs one set of TZif files.
+install_data: $(INSTALL_DATA_DEPS)
+ $(ZIC_INSTALL) tzdata.zi
+
+posix_only: $(INSTALL_DATA_DEPS)
+ $(MAKE) $(INSTALLARGS) LEAPSECONDS= install_data
+
+right_only: $(INSTALL_DATA_DEPS)
+ $(MAKE) $(INSTALLARGS) LEAPSECONDS='-L leapseconds' \
+ install_data
+
+# In earlier versions of this makefile, the other two directories were
+# subdirectories of $(TZDIR). However, this led to configuration errors.
+# For example, with posix_right under the earlier scheme,
+# TZ='right/Australia/Adelaide' got you localtime with leap seconds,
+# but gmtime without leap seconds, which led to problems with applications
+# like sendmail that subtract gmtime from localtime.
+# Therefore, the other two directories are now siblings of $(TZDIR).
+# You must replace all of $(TZDIR) to switch from not using leap seconds
+# to using them, or vice versa.
+right_posix: right_only
+ rm -fr '$(DESTDIR)$(TZDIR)-leaps'
+ ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-leaps' || \
+ $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only
+ $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only
+
+posix_right: posix_only
+ rm -fr '$(DESTDIR)$(TZDIR)-posix'
+ ln -s '$(TZDIR_BASENAME)' '$(DESTDIR)$(TZDIR)-posix' || \
+ $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-posix' posix_only
+ $(MAKE) $(INSTALLARGS) TZDIR='$(TZDIR)-leaps' right_only
+
+# This obsolescent rule is present for backwards compatibility with
+# tz releases 2014g through 2015g. It should go away eventually.
+posix_packrat: $(INSTALL_DATA_DEPS)
+ $(MAKE) $(INSTALLARGS) PACKRATDATA=backzone posix_only
+
+zones: $(REDO)
+
+# dummy.zd is not a real file; it is mentioned here only so that the
+# top-level 'make' does not have a syntax error.
+ZDS = dummy.zd
+# Rule used only by submakes invoked by the $(TZS_NEW) rule.
+# It is separate so that GNU 'make -j' can run instances in parallel.
+$(ZDS): zdump
+ ./zdump -i $(TZS_CUTOFF_FLAG) '$(wd)/'$$(expr $@ : '\(.*\).zd') \
+ >$@
+
+TZS_NEW_DEPS = tzdata.zi zdump zic
+$(TZS_NEW): $(TZS_NEW_DEPS)
+ rm -fr tzs$(TZS_YEAR).dir
+ mkdir tzs$(TZS_YEAR).dir
+ $(zic) -d tzs$(TZS_YEAR).dir tzdata.zi
+ $(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \
+ tzdata.zi | LC_ALL=C sort >$@.out
+ wd=`pwd` && \
+ x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \
+ tzdata.zi \
+ | LC_ALL=C sort -t . -k 2,2` && \
+ set x $$x && \
+ shift && \
+ ZDS=$$* && \
+ $(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \
+ ZDS="$$ZDS" $$ZDS && \
+ sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out
+ rm -fr tzs$(TZS_YEAR).dir
+ mv $@.out $@
+
+# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the
+# failed output and fix the inconsistency, perhaps by running 'make force_tzs'.
+$(TZS):
+ touch $@
+
+force_tzs: $(TZS_NEW)
+ cp $(TZS_NEW) $(TZS)
+
+libtz.a: $(LIBOBJS)
+ rm -f $@
+ $(AR) -rc $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+date: $(DATEOBJS)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS)
+
+tzselect: tzselect.ksh version
+ VERSION=`cat version` && sed \
+ -e 's|#!/bin/bash|#!$(KSHELL)|g' \
+ -e 's|AWK=[^}]*|AWK=$(AWK)|g' \
+ -e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \
+ -e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \
+ -e 's|TZDIR=[^}]*|TZDIR=$(TZDIR)|' \
+ -e 's|\(TZVERSION\)=.*|\1='"$$VERSION"'|' \
+ <$@.ksh >$@.out
+ chmod +x $@.out
+ mv $@.out $@
+
+check: check_character_set check_white_space check_links \
+ check_name_lengths check_sorted \
+ check_tables check_web check_zishrink check_tzs
+
+check_character_set: $(ENCHILADA)
+ test ! '$(UTF8_LOCALE)' || \
+ ! printf 'A\304\200B\n' | \
+ LC_ALL='$(UTF8_LOCALE)' grep -q '^A.B$$' >/dev/null 2>&1 || { \
+ LC_ALL='$(UTF8_LOCALE)' && export LC_ALL && \
+ sharp='#' && \
+ ! grep -Env $(SAFE_LINE) $(MANS) date.1 $(MANTXTS) \
+ $(MISC) $(SOURCES) $(WEB_PAGES) \
+ CONTRIBUTING LICENSE README \
+ version tzdata.zi && \
+ ! grep -Env $(SAFE_LINE)'|^UNUSUAL_OK_'$(OK_CHAR)'*$$' \
+ Makefile && \
+ ! grep -Env $(SAFE_SHARP_LINE) $(TDATA_TO_CHECK) backzone \
+ leapseconds yearistype.sh zone.tab && \
+ ! grep -Env $(OK_LINE) $(ENCHILADA); \
+ }
+ touch $@
+
+check_white_space: $(ENCHILADA)
+ patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \
+ ! grep -En "$$pat" \
+ $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list)
+ ! grep -n '[[:space:]]$$' \
+ $$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list)
+ touch $@
+
+PRECEDES_FILE_NAME = ^(Zone|Link[[:space:]]+[^[:space:]]+)[[:space:]]+
+FILE_NAME_COMPONENT_TOO_LONG = \
+ $(PRECEDES_FILE_NAME)[^[:space:]]*[^/[:space:]]{15}
+
+check_name_lengths: $(TDATA_TO_CHECK) backzone
+ ! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \
+ $(TDATA_TO_CHECK) backzone
+ touch $@
+
+CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
+
+check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
+ $(AWK) '/^Link/ {print $$3}' backward | LC_ALL=C sort -cu
+ $(AWK) '/^Zone/ {print $$2}' backzone | LC_ALL=C sort -cu
+ touch $@
+
+check_links: checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
+ $(AWK) -f checklinks.awk $(TDATA_TO_CHECK)
+ $(AWK) -f checklinks.awk tzdata.zi
+ touch $@
+
+check_tables: checktab.awk $(PRIMARY_YDATA) $(ZONETABLES)
+ for tab in $(ZONETABLES); do \
+ $(AWK) -f checktab.awk -v zone_table=$$tab $(PRIMARY_YDATA) \
+ || exit; \
+ done
+ touch $@
+
+check_tzs: $(TZS) $(TZS_NEW)
+ if test -s $(TZS); then \
+ diff -u $(TZS) $(TZS_NEW); \
+ else \
+ cp $(TZS_NEW) $(TZS); \
+ fi
+ touch $@
+
+check_web: $(CHECK_WEB_PAGES)
+check_theory.html: theory.html
+check_tz-art.html: tz-art.html
+check_tz-link.html: tz-link.html
+check_theory.html check_tz-art.html check_tz-link.html:
+ $(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \
+ -F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \
+ test ! -s $@.out || { cat $@.out; exit 1; }
+ mv $@.out $@
+check_tz-how-to.html: tz-how-to.html
+ $(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) tz-how-to.html
+ touch $@
+
+# Check that zishrink.awk does not alter the data, and that ziguard.awk
+# preserves main-format data.
+check_zishrink: check_zishrink_posix check_zishrink_right
+check_zishrink_posix check_zishrink_right: \
+ zic leapseconds $(PACKRATDATA) $(TDATA) $(DATAFORM).zi tzdata.zi
+ rm -fr $@.dir $@-t.dir $@-shrunk.dir
+ mkdir $@.dir $@-t.dir $@-shrunk.dir
+ case $@ in \
+ *_right) leap='-L leapseconds';; \
+ *) leap=;; \
+ esac && \
+ $(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \
+ $(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \
+ case $(DATAFORM) in \
+ main) \
+ $(ZIC) $$leap -d $@-t.dir $(TDATA) && \
+ $(AWK) '/^Rule/' $(TDATA) | \
+ $(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \
+ diff -r $@.dir $@-t.dir;; \
+ esac
+ diff -r $@.dir $@-shrunk.dir
+ rm -fr $@.dir $@-t.dir $@-shrunk.dir
+ touch $@
+
+clean_misc:
+ rm -fr check_*.dir
+ rm -f *.o *.out $(TIME_T_ALTERNATIVES) \
+ check_* core typecheck_* \
+ date tzselect version.h zdump zic yearistype libtz.a
+clean: clean_misc
+ rm -fr *.dir tzdb-*/
+ rm -f *.zi $(TZS_NEW)
+
+maintainer-clean: clean
+ @echo 'This command is intended for maintainers to use; it'
+ @echo 'deletes files that may need special tools to rebuild.'
+ rm -f leapseconds version $(MANTXTS) $(TZS) *.asc *.tar.*
+
+names:
+ @echo $(ENCHILADA)
+
+public: check check_public $(CHECK_TIME_T_ALTERNATIVES) \
+ tarballs signatures
+
+date.1.txt: date.1
+newctime.3.txt: newctime.3
+newstrftime.3.txt: newstrftime.3
+newtzset.3.txt: newtzset.3
+time2posix.3.txt: time2posix.3
+tzfile.5.txt: tzfile.5
+tzselect.8.txt: tzselect.8
+zdump.8.txt: zdump.8
+zic.8.txt: zic.8
+
+$(MANTXTS): workman.sh
+ LC_ALL=C sh workman.sh `expr $@ : '\(.*\)\.txt$$'` >$@.out
+ mv $@.out $@
+
+# Set the timestamps to those of the git repository, if available,
+# and if the files have not changed since then.
+# This uses GNU 'touch' syntax 'touch -d@N FILE',
+# where N is the number of seconds since 1970.
+# If git or GNU 'touch' is absent, don't bother to sync with git timestamps.
+# Also, set the timestamp of each prebuilt file like 'leapseconds'
+# to be the maximum of the files it depends on.
+set-timestamps.out: $(EIGHT_YARDS)
+ rm -f $@
+ if (type git) >/dev/null 2>&1 && \
+ files=`git ls-files $(EIGHT_YARDS)` && \
+ touch -md @1 test.out; then \
+ rm -f test.out && \
+ for file in $$files; do \
+ if git diff --quiet $$file; then \
+ time=`git log -1 --format='tformat:%ct' $$file` && \
+ touch -cmd @$$time $$file; \
+ else \
+ echo >&2 "$$file: warning: does not match repository"; \
+ fi || exit; \
+ done; \
+ fi
+ touch -cmr `ls -t $(LEAP_DEPS) | sed 1q` leapseconds
+ for file in `ls $(MANTXTS) | sed 's/\.txt$$//'`; do \
+ touch -cmr `ls -t $$file workman.sh | sed 1q` $$file.txt || \
+ exit; \
+ done
+ touch -cmr `ls -t $(TZDATA_ZI_DEPS) | sed 1q` tzdata.zi
+ touch -cmr `ls -t $(VERSION_DEPS) | sed 1q` version
+ touch $@
+set-tzs-timestamp.out: $(TZS)
+ touch -cmr `ls -t $(TZS_DEPS) | sed 1q` $(TZS)
+ touch $@
+
+# The zics below ensure that each data file can stand on its own.
+# We also do an all-files run to catch links to links.
+
+check_public: $(VERSION_DEPS)
+ rm -fr public.dir
+ mkdir public.dir
+ ln $(VERSION_DEPS) public.dir
+ cd public.dir && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' ALL
+ for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi; do \
+ public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \
+ done
+ public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK)
+ rm -fr public.dir
+ touch $@
+
+# Check that the code works under various alternative
+# implementations of time_t.
+check_time_t_alternatives: $(TIME_T_ALTERNATIVES)
+$(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD)
+$(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
+ rm -fr $@.dir
+ mkdir $@.dir
+ ln $(VERSION_DEPS) $@.dir
+ case $@ in \
+ int32_t) range=-2147483648,2147483648;; \
+ u*) range=0,4294967296;; \
+ *) range=-4294967296,4294967296;; \
+ esac && \
+ wd=`pwd` && \
+ zones=`$(AWK) '/^[^#]/ { print $$3 }' <zone1970.tab` && \
+ if test $@ = $(TIME_T_ALTERNATIVES_HEAD); then \
+ range_target=; \
+ else \
+ range_target=to$$range.tzs; \
+ fi && \
+ (cd $@.dir && \
+ $(MAKE) TOPDIR="$$wd/$@.dir" \
+ CFLAGS='$(CFLAGS) -Dtime_tz='"'$@'" \
+ REDO='$(REDO)' \
+ D=$$wd/$@.dir \
+ TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
+ install $$range_target) && \
+ test $@ = $(TIME_T_ALTERNATIVES_HEAD) || { \
+ (cd $(TIME_T_ALTERNATIVES_HEAD).dir && \
+ $(MAKE) TOPDIR="$$wd/$@.dir" \
+ TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
+ D=$$wd/$@.dir \
+ to$$range.tzs) && \
+ diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
+ $@.dir/to$$range.tzs && \
+ if diff -q Makefile Makefile 2>/dev/null; then \
+ quiet_option='-q'; \
+ else \
+ quiet_option=''; \
+ fi && \
+ diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \
+ $@.dir/etc && \
+ diff $$quiet_option -r \
+ $(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \
+ $@.dir/usr/share; \
+ }
+ touch $@
+
+TRADITIONAL_ASC = \
+ tzcode$(VERSION).tar.gz.asc \
+ tzdata$(VERSION).tar.gz.asc
+REARGUARD_ASC = \
+ tzdata$(VERSION)-rearguard.tar.gz.asc
+ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \
+ tzdb-$(VERSION).tar.lz.asc
+
+tarballs rearguard_tarballs traditional_tarballs \
+signatures rearguard_signatures traditional_signatures: \
+ version set-timestamps.out rearguard.zi
+ VERSION=`cat version` && \
+ $(MAKE) VERSION="$$VERSION" $@_version
+
+# These *_version rules are intended for use if VERSION is set by some
+# other means. Ordinarily these rules are used only by the above
+# non-_version rules, which set VERSION on the 'make' command line.
+tarballs_version: traditional_tarballs_version rearguard_tarballs_version \
+ tzdb-$(VERSION).tar.lz
+rearguard_tarballs_version: \
+ tzdata$(VERSION)-rearguard.tar.gz
+traditional_tarballs_version: \
+ tzcode$(VERSION).tar.gz tzdata$(VERSION).tar.gz
+signatures_version: $(ALL_ASC)
+rearguard_signatures_version: $(REARGUARD_ASC)
+traditional_signatures_version: $(TRADITIONAL_ASC)
+
+tzcode$(VERSION).tar.gz: set-timestamps.out
+ LC_ALL=C && export LC_ALL && \
+ tar $(TARFLAGS) -cf - \
+ $(COMMON) $(DOCS) $(SOURCES) | \
+ gzip $(GZIPFLAGS) >$@.out
+ mv $@.out $@
+
+tzdata$(VERSION).tar.gz: set-timestamps.out
+ LC_ALL=C && export LC_ALL && \
+ tar $(TARFLAGS) -cf - $(COMMON) $(DATA) $(MISC) | \
+ gzip $(GZIPFLAGS) >$@.out
+ mv $@.out $@
+
+tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
+ rm -fr tzdata$(VERSION)-rearguard.dir
+ mkdir tzdata$(VERSION)-rearguard.dir
+ ln $(COMMON) $(DATA) $(MISC) tzdata$(VERSION)-rearguard.dir
+ cd tzdata$(VERSION)-rearguard.dir && \
+ rm -f $(TDATA) $(PACKRATDATA) version
+ for f in $(TDATA) $(PACKRATDATA); do \
+ rearf=tzdata$(VERSION)-rearguard.dir/$$f; \
+ $(AWK) -v DATAFORM=rearguard -f ziguard.awk $$f >$$rearf && \
+ touch -cmr `ls -t ziguard.awk $$f` $$rearf || exit; \
+ done
+ sed '1s/$$/-rearguard/' \
+ <version >tzdata$(VERSION)-rearguard.dir/version
+ touch -cmr version tzdata$(VERSION)-rearguard.dir/version
+ LC_ALL=C && export LC_ALL && \
+ (cd tzdata$(VERSION)-rearguard.dir && \
+ tar $(TARFLAGS) -cf - $(COMMON) $(DATA) $(MISC) | \
+ gzip $(GZIPFLAGS)) >$@.out
+ mv $@.out $@
+
+tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
+ rm -fr tzdb-$(VERSION)
+ mkdir tzdb-$(VERSION)
+ ln $(ENCHILADA) tzdb-$(VERSION)
+ touch -cmr `ls -t tzdb-$(VERSION)/* | sed 1q` tzdb-$(VERSION)
+ LC_ALL=C && export LC_ALL && \
+ tar $(TARFLAGS) -cf - tzdb-$(VERSION) | lzip -9 >$@.out
+ mv $@.out $@
+
+tzcode$(VERSION).tar.gz.asc: tzcode$(VERSION).tar.gz
+tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz
+tzdata$(VERSION)-rearguard.tar.gz.asc: tzdata$(VERSION)-rearguard.tar.gz
+tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz
+$(ALL_ASC):
+ $(GPG) --armor --detach-sign $?
+
+TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T
+typecheck: typecheck_long_long typecheck_unsigned
+typecheck_long_long typecheck_unsigned: $(VERSION_DEPS)
+ rm -fr $@.dir
+ mkdir $@.dir
+ ln $(VERSION_DEPS) $@.dir
+ cd $@.dir && \
+ case $@ in \
+ *_long_long) i="long long";; \
+ *_unsigned ) i="unsigned" ;; \
+ esac && \
+ typecheck_cflags='' && \
+ $(MAKE) \
+ CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \
+ TOPDIR="`pwd`" \
+ install
+ $@.dir/zdump -i -c 1970,1971 Europe/Rome
+ touch $@
+
+zonenames: tzdata.zi
+ @$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi
+
+asctime.o: private.h tzfile.h
+date.o: private.h
+difftime.o: private.h
+localtime.o: private.h tzfile.h
+strftime.o: private.h tzfile.h
+zdump.o: version.h
+zic.o: private.h tzfile.h version.h
+
+.KEEP_STATE:
+
+.PHONY: ALL INSTALL all
+.PHONY: check check_time_t_alternatives
+.PHONY: check_web check_zishrink
+.PHONY: clean clean_misc dummy.zd force_tzs
+.PHONY: install install_data maintainer-clean names
+.PHONY: posix_only posix_packrat posix_right public
+.PHONY: rearguard_signatures rearguard_signatures_version
+.PHONY: rearguard_tarballs rearguard_tarballs_version
+.PHONY: right_only right_posix signatures signatures_version
+.PHONY: tarballs tarballs_version
+.PHONY: traditional_signatures traditional_signatures_version
+.PHONY: traditional_tarballs traditional_tarballs_version
+.PHONY: typecheck
+.PHONY: zonenames zones
+.PHONY: $(ZDS)
diff --git a/NEWS b/tz/NEWS
index 8b05f8f..8b05f8f 100644
--- a/NEWS
+++ b/tz/NEWS
diff --git a/README b/tz/README
index dd6fcf7..dd6fcf7 100644
--- a/README
+++ b/tz/README
diff --git a/africa b/tz/africa
index feb6017..feb6017 100644
--- a/africa
+++ b/tz/africa
diff --git a/antarctica b/tz/antarctica
index 2059983..2059983 100644
--- a/antarctica
+++ b/tz/antarctica
diff --git a/asctime.c b/tz/asctime.c
index 56c54b3..56c54b3 100644
--- a/asctime.c
+++ b/tz/asctime.c
diff --git a/asia b/tz/asia
index 348e2b5..348e2b5 100644
--- a/asia
+++ b/tz/asia
diff --git a/australasia b/tz/australasia
index 0544e58..0544e58 100644
--- a/australasia
+++ b/tz/australasia
diff --git a/backward b/tz/backward
index b4ae3cf..b4ae3cf 100644
--- a/backward
+++ b/tz/backward
diff --git a/backzone b/tz/backzone
index 2a54e6c..2a54e6c 100644
--- a/backzone
+++ b/tz/backzone
diff --git a/calendars b/tz/calendars
index 8bc7062..8bc7062 100644
--- a/calendars
+++ b/tz/calendars
diff --git a/checklinks.awk b/tz/checklinks.awk
index f309010..f309010 100644
--- a/checklinks.awk
+++ b/tz/checklinks.awk
diff --git a/checktab.awk b/tz/checktab.awk
index ec145b5..ec145b5 100644
--- a/checktab.awk
+++ b/tz/checktab.awk
diff --git a/date.1 b/tz/date.1
index 6e79cc1..6e79cc1 100644
--- a/date.1
+++ b/tz/date.1
diff --git a/date.c b/tz/date.c
index 2cc533f..2cc533f 100644
--- a/date.c
+++ b/tz/date.c
diff --git a/difftime.c b/tz/difftime.c
index 7b96927..7b96927 100644
--- a/difftime.c
+++ b/tz/difftime.c
diff --git a/etcetera b/tz/etcetera
index a1606bd..a1606bd 100644
--- a/etcetera
+++ b/tz/etcetera
diff --git a/europe b/tz/europe
index 5dc0397..5dc0397 100644
--- a/europe
+++ b/tz/europe
diff --git a/factory b/tz/factory
index 9f5fc33..9f5fc33 100644
--- a/factory
+++ b/tz/factory
diff --git a/iso3166.tab b/tz/iso3166.tab
index a4ff61a..a4ff61a 100644
--- a/iso3166.tab
+++ b/tz/iso3166.tab
diff --git a/leap-seconds.list b/tz/leap-seconds.list
index fd3d192..fd3d192 100644
--- a/leap-seconds.list
+++ b/tz/leap-seconds.list
diff --git a/leapseconds.awk b/tz/leapseconds.awk
index 242e9d6..242e9d6 100644
--- a/leapseconds.awk
+++ b/tz/leapseconds.awk
diff --git a/localtime.c b/tz/localtime.c
index 033e88f..033e88f 100644
--- a/localtime.c
+++ b/tz/localtime.c
diff --git a/newctime.3 b/tz/newctime.3
index 565e89a..565e89a 100644
--- a/newctime.3
+++ b/tz/newctime.3
diff --git a/newstrftime.3 b/tz/newstrftime.3
index eee503e..eee503e 100644
--- a/newstrftime.3
+++ b/tz/newstrftime.3
diff --git a/newtzset.3 b/tz/newtzset.3
index 4959851..4959851 100644
--- a/newtzset.3
+++ b/tz/newtzset.3
diff --git a/northamerica b/tz/northamerica
index 9e3577b..9e3577b 100644
--- a/northamerica
+++ b/tz/northamerica
diff --git a/pacificnew b/tz/pacificnew
index 8403219..8403219 100644
--- a/pacificnew
+++ b/tz/pacificnew
diff --git a/private.h b/tz/private.h
index 1ead147..1ead147 100644
--- a/private.h
+++ b/tz/private.h
diff --git a/southamerica b/tz/southamerica
index 397a2cc..397a2cc 100644
--- a/southamerica
+++ b/tz/southamerica
diff --git a/strftime.c b/tz/strftime.c
index ac26f4b..ac26f4b 100644
--- a/strftime.c
+++ b/tz/strftime.c
diff --git a/systemv b/tz/systemv
index a8c037c..a8c037c 100644
--- a/systemv
+++ b/tz/systemv
diff --git a/theory.html b/tz/theory.html
index e0b3233..e0b3233 100644
--- a/theory.html
+++ b/tz/theory.html
diff --git a/time2posix.3 b/tz/time2posix.3
index e4b8e81..e4b8e81 100644
--- a/time2posix.3
+++ b/tz/time2posix.3
diff --git a/tz-art.html b/tz/tz-art.html
index 8c57174..8c57174 100644
--- a/tz-art.html
+++ b/tz/tz-art.html
diff --git a/tz-how-to.html b/tz/tz-how-to.html
index 2e4842d..2e4842d 100644
--- a/tz-how-to.html
+++ b/tz/tz-how-to.html
diff --git a/tz-link.html b/tz/tz-link.html
index 85fc001..85fc001 100644
--- a/tz-link.html
+++ b/tz/tz-link.html
diff --git a/tzfile.5 b/tz/tzfile.5
index cd4c483..cd4c483 100644
--- a/tzfile.5
+++ b/tz/tzfile.5
diff --git a/tzfile.h b/tz/tzfile.h
index ee91104..ee91104 100644
--- a/tzfile.h
+++ b/tz/tzfile.h
diff --git a/tzselect.8 b/tz/tzselect.8
index 51f751c..51f751c 100644
--- a/tzselect.8
+++ b/tz/tzselect.8
diff --git a/tzselect.ksh b/tz/tzselect.ksh
index 18fce27..18fce27 100644
--- a/tzselect.ksh
+++ b/tz/tzselect.ksh
diff --git a/workman.sh b/tz/workman.sh
index 8fb18a4..8fb18a4 100644
--- a/workman.sh
+++ b/tz/workman.sh
diff --git a/yearistype.sh b/tz/yearistype.sh
index d674175..d674175 100644
--- a/yearistype.sh
+++ b/tz/yearistype.sh
diff --git a/zdump.8 b/tz/zdump.8
index fb6b8df..fb6b8df 100644
--- a/zdump.8
+++ b/tz/zdump.8
diff --git a/zdump.c b/tz/zdump.c
index 0fc8ced..0fc8ced 100644
--- a/zdump.c
+++ b/tz/zdump.c
diff --git a/zic.8 b/tz/zic.8
index dc0220f..dc0220f 100644
--- a/zic.8
+++ b/tz/zic.8
diff --git a/zic.c b/tz/zic.c
index 8bf5628..8bf5628 100644
--- a/zic.c
+++ b/tz/zic.c
diff --git a/ziguard.awk b/tz/ziguard.awk
index e8ef49e..e8ef49e 100644
--- a/ziguard.awk
+++ b/tz/ziguard.awk
diff --git a/zishrink.awk b/tz/zishrink.awk
index 4e187ac..4e187ac 100644
--- a/zishrink.awk
+++ b/tz/zishrink.awk
diff --git a/zone.tab b/tz/zone.tab
index 408fcb2..408fcb2 100644
--- a/zone.tab
+++ b/tz/zone.tab
diff --git a/zone1970.tab b/tz/zone1970.tab
index 822ffa1..822ffa1 100644
--- a/zone1970.tab
+++ b/tz/zone1970.tab
diff --git a/zoneinfo2tdf.pl b/tz/zoneinfo2tdf.pl
index e07b00c..e07b00c 100755
--- a/zoneinfo2tdf.pl
+++ b/tz/zoneinfo2tdf.pl