1Metadata-Version: 2.1
2Name: pytz
3Version: 2021.3
4Summary: World timezone definitions, modern and historical
5Home-page: http://pythonhosted.org/pytz
6Author: Stuart Bishop
7Author-email: stuart@stuartbishop.net
8Maintainer: Stuart Bishop
9Maintainer-email: stuart@stuartbishop.net
10License: MIT
11Download-URL: https://pypi.org/project/pytz/
12Keywords: timezone,tzinfo,datetime,olson,time
13Platform: Independent
14Classifier: Development Status :: 6 - Mature
15Classifier: Intended Audience :: Developers
16Classifier: License :: OSI Approved :: MIT License
17Classifier: Natural Language :: English
18Classifier: Operating System :: OS Independent
19Classifier: Programming Language :: Python
20Classifier: Programming Language :: Python :: 2
21Classifier: Programming Language :: Python :: 2.4
22Classifier: Programming Language :: Python :: 2.5
23Classifier: Programming Language :: Python :: 2.6
24Classifier: Programming Language :: Python :: 2.7
25Classifier: Programming Language :: Python :: 3
26Classifier: Programming Language :: Python :: 3.1
27Classifier: Programming Language :: Python :: 3.2
28Classifier: Programming Language :: Python :: 3.3
29Classifier: Programming Language :: Python :: 3.4
30Classifier: Programming Language :: Python :: 3.5
31Classifier: Programming Language :: Python :: 3.6
32Classifier: Programming Language :: Python :: 3.7
33Classifier: Programming Language :: Python :: 3.8
34Classifier: Programming Language :: Python :: 3.9
35Classifier: Topic :: Software Development :: Libraries :: Python Modules
36License-File: LICENSE.txt
37
38pytz - World Timezone Definitions for Python
39============================================
40
41:Author: Stuart Bishop <stuart@stuartbishop.net>
42
43Introduction
44~~~~~~~~~~~~
45
46pytz brings the Olson tz database into Python. This library allows
47accurate and cross platform timezone calculations using Python 2.4
48or higher. It also solves the issue of ambiguous times at the end
49of daylight saving time, which you can read more about in the Python
50Library Reference (``datetime.tzinfo``).
51
52Almost all of the Olson timezones are supported.
53
54.. note::
55
56    This library differs from the documented Python API for
57    tzinfo implementations; if you want to create local wallclock
58    times you need to use the ``localize()`` method documented in this
59    document. In addition, if you perform date arithmetic on local
60    times that cross DST boundaries, the result may be in an incorrect
61    timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get
62    2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A
63    ``normalize()`` method is provided to correct this. Unfortunately these
64    issues cannot be resolved without modifying the Python datetime
65    implementation (see PEP-431).
66
67
68Installation
69~~~~~~~~~~~~
70
71This package can either be installed using ``pip`` or from a tarball using the
72standard Python distutils.
73
74If you are installing using ``pip``, you don't need to download anything as the
75latest version will be downloaded for you from PyPI::
76
77    pip install pytz
78
79If you are installing from a tarball, run the following command as an
80administrative user::
81
82    python setup.py install
83
84
85pytz for Enterprise
86~~~~~~~~~~~~~~~~~~~
87
88Available as part of the Tidelift Subscription.
89
90The maintainers of pytz and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. `Learn more. <https://tidelift.com/subscription/pkg/pypi-pytz?utm_source=pypi-pytz&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_.
91
92
93Example & Usage
94~~~~~~~~~~~~~~~
95
96Localized times and date arithmetic
97-----------------------------------
98
99>>> from datetime import datetime, timedelta
100>>> from pytz import timezone
101>>> import pytz
102>>> utc = pytz.utc
103>>> utc.zone
104'UTC'
105>>> eastern = timezone('US/Eastern')
106>>> eastern.zone
107'US/Eastern'
108>>> amsterdam = timezone('Europe/Amsterdam')
109>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z'
110
111This library only supports two ways of building a localized time. The
112first is to use the ``localize()`` method provided by the pytz library.
113This is used to localize a naive datetime (datetime with no timezone
114information):
115
116>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
117>>> print(loc_dt.strftime(fmt))
1182002-10-27 06:00:00 EST-0500
119
120The second way of building a localized time is by converting an existing
121localized time using the standard ``astimezone()`` method:
122
123>>> ams_dt = loc_dt.astimezone(amsterdam)
124>>> ams_dt.strftime(fmt)
125'2002-10-27 12:00:00 CET+0100'
126
127Unfortunately using the tzinfo argument of the standard datetime
128constructors ''does not work'' with pytz for many timezones.
129
130>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt)  # /!\ Does not work this way!
131'2002-10-27 12:00:00 LMT+0020'
132
133It is safe for timezones without daylight saving transitions though, such
134as UTC:
135
136>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt)  # /!\ Not recommended except for UTC
137'2002-10-27 12:00:00 UTC+0000'
138
139The preferred way of dealing with times is to always work in UTC,
140converting to localtime only when generating output to be read
141by humans.
142
143>>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
144>>> loc_dt = utc_dt.astimezone(eastern)
145>>> loc_dt.strftime(fmt)
146'2002-10-27 01:00:00 EST-0500'
147
148This library also allows you to do date arithmetic using local
149times, although it is more complicated than working in UTC as you
150need to use the ``normalize()`` method to handle daylight saving time
151and other timezone transitions. In this example, ``loc_dt`` is set
152to the instant when daylight saving time ends in the US/Eastern
153timezone.
154
155>>> before = loc_dt - timedelta(minutes=10)
156>>> before.strftime(fmt)
157'2002-10-27 00:50:00 EST-0500'
158>>> eastern.normalize(before).strftime(fmt)
159'2002-10-27 01:50:00 EDT-0400'
160>>> after = eastern.normalize(before + timedelta(minutes=20))
161>>> after.strftime(fmt)
162'2002-10-27 01:10:00 EST-0500'
163
164Creating local times is also tricky, and the reason why working with
165local times is not recommended. Unfortunately, you cannot just pass
166a ``tzinfo`` argument when constructing a datetime (see the next
167section for more details)
168
169>>> dt = datetime(2002, 10, 27, 1, 30, 0)
170>>> dt1 = eastern.localize(dt, is_dst=True)
171>>> dt1.strftime(fmt)
172'2002-10-27 01:30:00 EDT-0400'
173>>> dt2 = eastern.localize(dt, is_dst=False)
174>>> dt2.strftime(fmt)
175'2002-10-27 01:30:00 EST-0500'
176
177Converting between timezones is more easily done, using the
178standard astimezone method.
179
180>>> utc_dt = utc.localize(datetime.utcfromtimestamp(1143408899))
181>>> utc_dt.strftime(fmt)
182'2006-03-26 21:34:59 UTC+0000'
183>>> au_tz = timezone('Australia/Sydney')
184>>> au_dt = utc_dt.astimezone(au_tz)
185>>> au_dt.strftime(fmt)
186'2006-03-27 08:34:59 AEDT+1100'
187>>> utc_dt2 = au_dt.astimezone(utc)
188>>> utc_dt2.strftime(fmt)
189'2006-03-26 21:34:59 UTC+0000'
190>>> utc_dt == utc_dt2
191True
192
193You can take shortcuts when dealing with the UTC side of timezone
194conversions. ``normalize()`` and ``localize()`` are not really
195necessary when there are no daylight saving time transitions to
196deal with.
197
198>>> utc_dt = datetime.utcfromtimestamp(1143408899).replace(tzinfo=utc)
199>>> utc_dt.strftime(fmt)
200'2006-03-26 21:34:59 UTC+0000'
201>>> au_tz = timezone('Australia/Sydney')
202>>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz))
203>>> au_dt.strftime(fmt)
204'2006-03-27 08:34:59 AEDT+1100'
205>>> utc_dt2 = au_dt.astimezone(utc)
206>>> utc_dt2.strftime(fmt)
207'2006-03-26 21:34:59 UTC+0000'
208
209
210``tzinfo`` API
211--------------
212
213The ``tzinfo`` instances returned by the ``timezone()`` function have
214been extended to cope with ambiguous times by adding an ``is_dst``
215parameter to the ``utcoffset()``, ``dst()`` && ``tzname()`` methods.
216
217>>> tz = timezone('America/St_Johns')
218
219>>> normal = datetime(2009, 9, 1)
220>>> ambiguous = datetime(2009, 10, 31, 23, 30)
221
222The ``is_dst`` parameter is ignored for most timestamps. It is only used
223during DST transition ambiguous periods to resolve that ambiguity.
224
225>>> print(tz.utcoffset(normal, is_dst=True))
226-1 day, 21:30:00
227>>> print(tz.dst(normal, is_dst=True))
2281:00:00
229>>> tz.tzname(normal, is_dst=True)
230'NDT'
231
232>>> print(tz.utcoffset(ambiguous, is_dst=True))
233-1 day, 21:30:00
234>>> print(tz.dst(ambiguous, is_dst=True))
2351:00:00
236>>> tz.tzname(ambiguous, is_dst=True)
237'NDT'
238
239>>> print(tz.utcoffset(normal, is_dst=False))
240-1 day, 21:30:00
241>>> tz.dst(normal, is_dst=False).seconds
2423600
243>>> tz.tzname(normal, is_dst=False)
244'NDT'
245
246>>> print(tz.utcoffset(ambiguous, is_dst=False))
247-1 day, 20:30:00
248>>> tz.dst(ambiguous, is_dst=False)
249datetime.timedelta(0)
250>>> tz.tzname(ambiguous, is_dst=False)
251'NST'
252
253If ``is_dst`` is not specified, ambiguous timestamps will raise
254an ``pytz.exceptions.AmbiguousTimeError`` exception.
255
256>>> print(tz.utcoffset(normal))
257-1 day, 21:30:00
258>>> print(tz.dst(normal))
2591:00:00
260>>> tz.tzname(normal)
261'NDT'
262
263>>> import pytz.exceptions
264>>> try:
265...     tz.utcoffset(ambiguous)
266... except pytz.exceptions.AmbiguousTimeError:
267...     print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
268pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
269>>> try:
270...     tz.dst(ambiguous)
271... except pytz.exceptions.AmbiguousTimeError:
272...     print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
273pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
274>>> try:
275...     tz.tzname(ambiguous)
276... except pytz.exceptions.AmbiguousTimeError:
277...     print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous)
278pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00
279
280
281Problems with Localtime
282~~~~~~~~~~~~~~~~~~~~~~~
283
284The major problem we have to deal with is that certain datetimes
285may occur twice in a year. For example, in the US/Eastern timezone
286on the last Sunday morning in October, the following sequence
287happens:
288
289    - 01:00 EDT occurs
290    - 1 hour later, instead of 2:00am the clock is turned back 1 hour
291      and 01:00 happens again (this time 01:00 EST)
292
293In fact, every instant between 01:00 and 02:00 occurs twice. This means
294that if you try and create a time in the 'US/Eastern' timezone
295the standard datetime syntax, there is no way to specify if you meant
296before of after the end-of-daylight-saving-time transition. Using the
297pytz custom syntax, the best you can do is make an educated guess:
298
299>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 1, 30, 00))
300>>> loc_dt.strftime(fmt)
301'2002-10-27 01:30:00 EST-0500'
302
303As you can see, the system has chosen one for you and there is a 50%
304chance of it being out by one hour. For some applications, this does
305not matter. However, if you are trying to schedule meetings with people
306in different timezones or analyze log files it is not acceptable.
307
308The best and simplest solution is to stick with using UTC.  The pytz
309package encourages using UTC for internal timezone representation by
310including a special UTC implementation based on the standard Python
311reference implementation in the Python documentation.
312
313The UTC timezone unpickles to be the same instance, and pickles to a
314smaller size than other pytz tzinfo instances.  The UTC implementation
315can be obtained as pytz.utc, pytz.UTC, or pytz.timezone('UTC').
316
317>>> import pickle, pytz
318>>> dt = datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc)
319>>> naive = dt.replace(tzinfo=None)
320>>> p = pickle.dumps(dt, 1)
321>>> naive_p = pickle.dumps(naive, 1)
322>>> len(p) - len(naive_p)
32317
324>>> new = pickle.loads(p)
325>>> new == dt
326True
327>>> new is dt
328False
329>>> new.tzinfo is dt.tzinfo
330True
331>>> pytz.utc is pytz.UTC is pytz.timezone('UTC')
332True
333
334Note that some other timezones are commonly thought of as the same (GMT,
335Greenwich, Universal, etc.). The definition of UTC is distinct from these
336other timezones, and they are not equivalent. For this reason, they will
337not compare the same in Python.
338
339>>> utc == pytz.timezone('GMT')
340False
341
342See the section `What is UTC`_, below.
343
344If you insist on working with local times, this library provides a
345facility for constructing them unambiguously:
346
347>>> loc_dt = datetime(2002, 10, 27, 1, 30, 00)
348>>> est_dt = eastern.localize(loc_dt, is_dst=True)
349>>> edt_dt = eastern.localize(loc_dt, is_dst=False)
350>>> print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt))
3512002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500
352
353If you pass None as the is_dst flag to localize(), pytz will refuse to
354guess and raise exceptions if you try to build ambiguous or non-existent
355times.
356
357For example, 1:30am on 27th Oct 2002 happened twice in the US/Eastern
358timezone when the clocks where put back at the end of Daylight Saving
359Time:
360
361>>> dt = datetime(2002, 10, 27, 1, 30, 00)
362>>> try:
363...     eastern.localize(dt, is_dst=None)
364... except pytz.exceptions.AmbiguousTimeError:
365...     print('pytz.exceptions.AmbiguousTimeError: %s' % dt)
366pytz.exceptions.AmbiguousTimeError: 2002-10-27 01:30:00
367
368Similarly, 2:30am on 7th April 2002 never happened at all in the
369US/Eastern timezone, as the clocks where put forward at 2:00am skipping
370the entire hour:
371
372>>> dt = datetime(2002, 4, 7, 2, 30, 00)
373>>> try:
374...     eastern.localize(dt, is_dst=None)
375... except pytz.exceptions.NonExistentTimeError:
376...     print('pytz.exceptions.NonExistentTimeError: %s' % dt)
377pytz.exceptions.NonExistentTimeError: 2002-04-07 02:30:00
378
379Both of these exceptions share a common base class to make error handling
380easier:
381
382>>> isinstance(pytz.AmbiguousTimeError(), pytz.InvalidTimeError)
383True
384>>> isinstance(pytz.NonExistentTimeError(), pytz.InvalidTimeError)
385True
386
387
388A special case is where countries change their timezone definitions
389with no daylight savings time switch. For example, in 1915 Warsaw
390switched from Warsaw time to Central European time with no daylight savings
391transition. So at the stroke of midnight on August 5th 1915 the clocks
392were wound back 24 minutes creating an ambiguous time period that cannot
393be specified without referring to the timezone abbreviation or the
394actual UTC offset. In this case midnight happened twice, neither time
395during a daylight saving time period. pytz handles this transition by
396treating the ambiguous period before the switch as daylight savings
397time, and the ambiguous period after as standard time.
398
399
400>>> warsaw = pytz.timezone('Europe/Warsaw')
401>>> amb_dt1 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=True)
402>>> amb_dt1.strftime(fmt)
403'1915-08-04 23:59:59 WMT+0124'
404>>> amb_dt2 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=False)
405>>> amb_dt2.strftime(fmt)
406'1915-08-04 23:59:59 CET+0100'
407>>> switch_dt = warsaw.localize(datetime(1915, 8, 5, 00, 00, 00), is_dst=False)
408>>> switch_dt.strftime(fmt)
409'1915-08-05 00:00:00 CET+0100'
410>>> str(switch_dt - amb_dt1)
411'0:24:01'
412>>> str(switch_dt - amb_dt2)
413'0:00:01'
414
415The best way of creating a time during an ambiguous time period is
416by converting from another timezone such as UTC:
417
418>>> utc_dt = datetime(1915, 8, 4, 22, 36, tzinfo=pytz.utc)
419>>> utc_dt.astimezone(warsaw).strftime(fmt)
420'1915-08-04 23:36:00 CET+0100'
421
422The standard Python way of handling all these ambiguities is not to
423handle them, such as demonstrated in this example using the US/Eastern
424timezone definition from the Python documentation (Note that this
425implementation only works for dates between 1987 and 2006 - it is
426included for tests only!):
427
428>>> from pytz.reference import Eastern # pytz.reference only for tests
429>>> dt = datetime(2002, 10, 27, 0, 30, tzinfo=Eastern)
430>>> str(dt)
431'2002-10-27 00:30:00-04:00'
432>>> str(dt + timedelta(hours=1))
433'2002-10-27 01:30:00-05:00'
434>>> str(dt + timedelta(hours=2))
435'2002-10-27 02:30:00-05:00'
436>>> str(dt + timedelta(hours=3))
437'2002-10-27 03:30:00-05:00'
438
439Notice the first two results? At first glance you might think they are
440correct, but taking the UTC offset into account you find that they are
441actually two hours appart instead of the 1 hour we asked for.
442
443>>> from pytz.reference import UTC # pytz.reference only for tests
444>>> str(dt.astimezone(UTC))
445'2002-10-27 04:30:00+00:00'
446>>> str((dt + timedelta(hours=1)).astimezone(UTC))
447'2002-10-27 06:30:00+00:00'
448
449
450Country Information
451~~~~~~~~~~~~~~~~~~~
452
453A mechanism is provided to access the timezones commonly in use
454for a particular country, looked up using the ISO 3166 country code.
455It returns a list of strings that can be used to retrieve the relevant
456tzinfo instance using ``pytz.timezone()``:
457
458>>> print(' '.join(pytz.country_timezones['nz']))
459Pacific/Auckland Pacific/Chatham
460
461The Olson database comes with a ISO 3166 country code to English country
462name mapping that pytz exposes as a dictionary:
463
464>>> print(pytz.country_names['nz'])
465New Zealand
466
467
468What is UTC
469~~~~~~~~~~~
470
471'UTC' is `Coordinated Universal Time`_. It is a successor to, but distinct
472from, Greenwich Mean Time (GMT) and the various definitions of Universal
473Time. UTC is now the worldwide standard for regulating clocks and time
474measurement.
475
476All other timezones are defined relative to UTC, and include offsets like
477UTC+0800 - hours to add or subtract from UTC to derive the local time. No
478daylight saving time occurs in UTC, making it a useful timezone to perform
479date arithmetic without worrying about the confusion and ambiguities caused
480by daylight saving time transitions, your country changing its timezone, or
481mobile computers that roam through multiple timezones.
482
483..  _Coordinated Universal Time: https://en.wikipedia.org/wiki/Coordinated_Universal_Time
484
485
486Helpers
487~~~~~~~
488
489There are two lists of timezones provided.
490
491``all_timezones`` is the exhaustive list of the timezone names that can
492be used.
493
494>>> from pytz import all_timezones
495>>> len(all_timezones) >= 500
496True
497>>> 'Etc/Greenwich' in all_timezones
498True
499
500``common_timezones`` is a list of useful, current timezones. It doesn't
501contain deprecated zones or historical zones, except for a few I've
502deemed in common usage, such as US/Eastern (open a bug report if you
503think other timezones are deserving of being included here). It is also
504a sequence of strings.
505
506>>> from pytz import common_timezones
507>>> len(common_timezones) < len(all_timezones)
508True
509>>> 'Etc/Greenwich' in common_timezones
510False
511>>> 'Australia/Melbourne' in common_timezones
512True
513>>> 'US/Eastern' in common_timezones
514True
515>>> 'Canada/Eastern' in common_timezones
516True
517>>> 'Australia/Yancowinna' in all_timezones
518True
519>>> 'Australia/Yancowinna' in common_timezones
520False
521
522Both ``common_timezones`` and ``all_timezones`` are alphabetically
523sorted:
524
525>>> common_timezones_dupe = common_timezones[:]
526>>> common_timezones_dupe.sort()
527>>> common_timezones == common_timezones_dupe
528True
529>>> all_timezones_dupe = all_timezones[:]
530>>> all_timezones_dupe.sort()
531>>> all_timezones == all_timezones_dupe
532True
533
534``all_timezones`` and ``common_timezones`` are also available as sets.
535
536>>> from pytz import all_timezones_set, common_timezones_set
537>>> 'US/Eastern' in all_timezones_set
538True
539>>> 'US/Eastern' in common_timezones_set
540True
541>>> 'Australia/Victoria' in common_timezones_set
542False
543
544You can also retrieve lists of timezones used by particular countries
545using the ``country_timezones()`` function. It requires an ISO-3166
546two letter country code.
547
548>>> from pytz import country_timezones
549>>> print(' '.join(country_timezones('ch')))
550Europe/Zurich
551>>> print(' '.join(country_timezones('CH')))
552Europe/Zurich
553
554
555Internationalization - i18n/l10n
556~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
557
558Pytz is an interface to the IANA database, which uses ASCII names. The `Unicode  Consortium's Unicode Locales (CLDR) <http://cldr.unicode.org>`_
559project provides translations. Thomas Khyn's
560`l18n <https://pypi.org/project/l18n/>`_ package can be used to access
561these translations from Python.
562
563
564License
565~~~~~~~
566
567MIT license.
568
569This code is also available as part of Zope 3 under the Zope Public
570License,  Version 2.1 (ZPL).
571
572I'm happy to relicense this code if necessary for inclusion in other
573open source projects.
574
575
576Latest Versions
577~~~~~~~~~~~~~~~
578
579This package will be updated after releases of the Olson timezone
580database.  The latest version can be downloaded from the `Python Package
581Index <https://pypi.org/project/pytz/>`_.  The code that is used
582to generate this distribution is hosted on launchpad.net and available
583using git::
584
585    git clone https://git.launchpad.net/pytz
586
587A mirror on github is also available at https://github.com/stub42/pytz
588
589Announcements of new releases are made on
590`Launchpad <https://launchpad.net/pytz>`_, and the
591`Atom feed <http://feeds.launchpad.net/pytz/announcements.atom>`_
592hosted there.
593
594
595Bugs, Feature Requests & Patches
596~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
597
598Bugs can be reported using `Launchpad Bugs <https://bugs.launchpad.net/pytz>`_.
599
600
601Security Issues
602~~~~~~~~~~~~~~~
603
604Reports about security issues can be made via `Tidelift <https://tidelift.com/security>`_.
605
606
607Issues & Limitations
608~~~~~~~~~~~~~~~~~~~~
609
610- Offsets from UTC are rounded to the nearest whole minute, so timezones
611  such as Europe/Amsterdam pre 1937 will be up to 30 seconds out. This
612  is a limitation of the Python datetime library.
613
614- If you think a timezone definition is incorrect, I probably can't fix
615  it. pytz is a direct translation of the Olson timezone database, and
616  changes to the timezone definitions need to be made to this source.
617  If you find errors they should be reported to the time zone mailing
618  list, linked from http://www.iana.org/time-zones.
619
620
621Further Reading
622~~~~~~~~~~~~~~~
623
624More info than you want to know about timezones:
625http://www.twinsun.com/tz/tz-link.htm
626
627
628Contact
629~~~~~~~
630
631Stuart Bishop <stuart@stuartbishop.net>
632
633
634
635
636