aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authordshmatkov <dshmatkov@yandex-team.ru>2022-02-10 16:48:27 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:48:27 +0300
commit98201819fed99e5a9f5b174dca304cab0162e1c9 (patch)
tree5d5cb817648f650d76cf1076100726fd9b8448e8 /contrib/python
parent3a1449f44e2361ebf1a230ca6ab2cbcb1fed4e74 (diff)
downloadydb-98201819fed99e5a9f5b174dca304cab0162e1c9.tar.gz
Restoring authorship annotation for <dshmatkov@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/boto3/ya.make8
-rw-r--r--contrib/python/dateutil/README.rst288
-rw-r--r--contrib/python/dateutil/dateutil/__init__.py14
-rw-r--r--contrib/python/dateutil/dateutil/_common.py22
-rw-r--r--contrib/python/dateutil/dateutil/easter.py4
-rw-r--r--contrib/python/dateutil/dateutil/parser/__init__.py114
-rw-r--r--contrib/python/dateutil/dateutil/parser/_parser.py3030
-rw-r--r--contrib/python/dateutil/dateutil/parser/isoparser.py768
-rw-r--r--contrib/python/dateutil/dateutil/relativedelta.py140
-rw-r--r--contrib/python/dateutil/dateutil/rrule.py84
-rw-r--r--contrib/python/dateutil/dateutil/test/_common.py450
-rw-r--r--contrib/python/dateutil/dateutil/test/property/test_isoparse_prop.py52
-rw-r--r--contrib/python/dateutil/dateutil/test/property/test_parser_prop.py44
-rw-r--r--contrib/python/dateutil/dateutil/test/test_easter.py154
-rw-r--r--contrib/python/dateutil/dateutil/test/test_import_star.py26
-rw-r--r--contrib/python/dateutil/dateutil/test/test_imports.py96
-rw-r--r--contrib/python/dateutil/dateutil/test/test_internals.py142
-rw-r--r--contrib/python/dateutil/dateutil/test/test_isoparser.py868
-rw-r--r--contrib/python/dateutil/dateutil/test/test_parser.py980
-rw-r--r--contrib/python/dateutil/dateutil/test/test_relativedelta.py1334
-rw-r--r--contrib/python/dateutil/dateutil/test/test_rrule.py9672
-rw-r--r--contrib/python/dateutil/dateutil/test/test_tz.py5072
-rw-r--r--contrib/python/dateutil/dateutil/test/test_utils.py42
-rw-r--r--contrib/python/dateutil/dateutil/tz/__init__.py16
-rw-r--r--contrib/python/dateutil/dateutil/tz/_common.py60
-rw-r--r--contrib/python/dateutil/dateutil/tz/_factories.py70
-rw-r--r--contrib/python/dateutil/dateutil/tz/tz.py766
-rw-r--r--contrib/python/dateutil/dateutil/utils.py138
-rw-r--r--contrib/python/dateutil/dateutil/zoneinfo/__init__.py24
-rw-r--r--contrib/python/dateutil/dateutil/zoneinfo/rebuild.py10
-rw-r--r--contrib/python/dateutil/tests/ya.make2
-rw-r--r--contrib/python/dateutil/ya.make16
-rw-r--r--contrib/python/ya.make56
33 files changed, 12281 insertions, 12281 deletions
diff --git a/contrib/python/boto3/ya.make b/contrib/python/boto3/ya.make
index 8b0681428f..bd12ae12b7 100644
--- a/contrib/python/boto3/ya.make
+++ b/contrib/python/boto3/ya.make
@@ -6,12 +6,12 @@ VERSION(1.17.112)
LICENSE(Apache-2.0)
-PEERDIR(
- contrib/python/botocore
+PEERDIR(
+ contrib/python/botocore
contrib/python/jmespath
contrib/python/s3transfer
-)
-
+)
+
NO_LINT()
PY_SRCS(
diff --git a/contrib/python/dateutil/README.rst b/contrib/python/dateutil/README.rst
index 8348478725..106023b324 100644
--- a/contrib/python/dateutil/README.rst
+++ b/contrib/python/dateutil/README.rst
@@ -1,168 +1,168 @@
-dateutil - powerful extensions to datetime
-==========================================
-
+dateutil - powerful extensions to datetime
+==========================================
+
|pypi| |support| |licence|
-
-|gitter| |readthedocs|
-
+
+|gitter| |readthedocs|
+
|travis| |appveyor| |pipelines| |coverage|
-
-.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square
- :target: https://pypi.org/project/python-dateutil/
- :alt: pypi version
-
-.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square
- :target: https://pypi.org/project/python-dateutil/
- :alt: supported Python version
-
-.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build
- :target: https://travis-ci.org/dateutil/dateutil
- :alt: travis build status
-
-.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor
- :target: https://ci.appveyor.com/project/dateutil/dateutil
- :alt: appveyor build status
-
+
+.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square
+ :target: https://pypi.org/project/python-dateutil/
+ :alt: pypi version
+
+.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square
+ :target: https://pypi.org/project/python-dateutil/
+ :alt: supported Python version
+
+.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build
+ :target: https://travis-ci.org/dateutil/dateutil
+ :alt: travis build status
+
+.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor
+ :target: https://ci.appveyor.com/project/dateutil/dateutil
+ :alt: appveyor build status
+
.. |pipelines| image:: https://dev.azure.com/pythondateutilazure/dateutil/_apis/build/status/dateutil.dateutil?branchName=master
:target: https://dev.azure.com/pythondateutilazure/dateutil/_build/latest?definitionId=1&branchName=master
:alt: azure pipelines build status
.. |coverage| image:: https://codecov.io/gh/dateutil/dateutil/branch/master/graphs/badge.svg?branch=master
:target: https://codecov.io/gh/dateutil/dateutil?branch=master
- :alt: Code coverage
-
-.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg
- :alt: Join the chat at https://gitter.im/dateutil/dateutil
- :target: https://gitter.im/dateutil/dateutil
-
-.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square
- :target: https://pypi.org/project/python-dateutil/
- :alt: licence
-
-.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs
- :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/
- :target: https://dateutil.readthedocs.io/en/latest/
-
-The `dateutil` module provides powerful extensions to
-the standard `datetime` module, available in Python.
-
+ :alt: Code coverage
+
+.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg
+ :alt: Join the chat at https://gitter.im/dateutil/dateutil
+ :target: https://gitter.im/dateutil/dateutil
+
+.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square
+ :target: https://pypi.org/project/python-dateutil/
+ :alt: licence
+
+.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs
+ :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/
+ :target: https://dateutil.readthedocs.io/en/latest/
+
+The `dateutil` module provides powerful extensions to
+the standard `datetime` module, available in Python.
+
Installation
============
`dateutil` can be installed from PyPI using `pip` (note that the package name is
different from the importable name)::
-
+
pip install python-dateutil
-Download
-========
-dateutil is available on PyPI
-https://pypi.org/project/python-dateutil/
-
-The documentation is hosted at:
-https://dateutil.readthedocs.io/en/stable/
-
-Code
-====
+Download
+========
+dateutil is available on PyPI
+https://pypi.org/project/python-dateutil/
+
+The documentation is hosted at:
+https://dateutil.readthedocs.io/en/stable/
+
+Code
+====
The code and issue tracker are hosted on GitHub:
-https://github.com/dateutil/dateutil/
-
-Features
-========
-
-* Computing of relative deltas (next month, next year,
+https://github.com/dateutil/dateutil/
+
+Features
+========
+
+* Computing of relative deltas (next month, next year,
next Monday, last week of month, etc);
-* Computing of relative deltas between two given
- date and/or datetime objects;
-* Computing of dates based on very flexible recurrence rules,
- using a superset of the `iCalendar <https://www.ietf.org/rfc/rfc2445.txt>`_
- specification. Parsing of RFC strings is supported as well.
-* Generic parsing of dates in almost any string format;
-* Timezone (tzinfo) implementations for tzfile(5) format
- files (/etc/localtime, /usr/share/zoneinfo, etc), TZ
- environment string (in all known formats), iCalendar
- format files, given ranges (with help from relative deltas),
- local machine timezone, fixed offset timezone, UTC timezone,
- and Windows registry-based time zones.
-* Internal up-to-date world timezone information based on
- Olson's database.
-* Computing of Easter Sunday dates for any given year,
- using Western, Orthodox or Julian algorithms;
-* A comprehensive test suite.
-
-Quick example
-=============
-Here's a snapshot, just to give an idea about the power of the
-package. For more examples, look at the documentation.
-
-Suppose you want to know how much time is left, in
-years/months/days/etc, before the next easter happening on a
-year with a Friday 13th in August, and you want to get today's
-date out of the "date" unix system command. Here is the code:
-
-.. doctest:: readmeexample
-
- >>> from dateutil.relativedelta import *
- >>> from dateutil.easter import *
- >>> from dateutil.rrule import *
- >>> from dateutil.parser import *
- >>> from datetime import *
- >>> now = parse("Sat Oct 11 17:13:46 UTC 2003")
- >>> today = now.date()
- >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year
- >>> rdelta = relativedelta(easter(year), today)
- >>> print("Today is: %s" % today)
- Today is: 2003-10-11
- >>> print("Year with next Aug 13th on a Friday is: %s" % year)
- Year with next Aug 13th on a Friday is: 2004
- >>> print("How far is the Easter of that year: %s" % rdelta)
- How far is the Easter of that year: relativedelta(months=+6)
- >>> print("And the Easter of that year is: %s" % (today+rdelta))
- And the Easter of that year is: 2004-04-11
-
-Being exactly 6 months ahead was **really** a coincidence :)
-
-Contributing
-============
-
-We welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository.
-
-
-Author
-======
-The dateutil module was written by Gustavo Niemeyer <gustavo@niemeyer.net>
-in 2003.
-
-It is maintained by:
-
-* Gustavo Niemeyer <gustavo@niemeyer.net> 2003-2011
-* Tomi Pieviläinen <tomi.pievilainen@iki.fi> 2012-2014
-* Yaron de Leeuw <me@jarondl.net> 2014-2016
-* Paul Ganssle <paul@ganssle.io> 2015-
-
+* Computing of relative deltas between two given
+ date and/or datetime objects;
+* Computing of dates based on very flexible recurrence rules,
+ using a superset of the `iCalendar <https://www.ietf.org/rfc/rfc2445.txt>`_
+ specification. Parsing of RFC strings is supported as well.
+* Generic parsing of dates in almost any string format;
+* Timezone (tzinfo) implementations for tzfile(5) format
+ files (/etc/localtime, /usr/share/zoneinfo, etc), TZ
+ environment string (in all known formats), iCalendar
+ format files, given ranges (with help from relative deltas),
+ local machine timezone, fixed offset timezone, UTC timezone,
+ and Windows registry-based time zones.
+* Internal up-to-date world timezone information based on
+ Olson's database.
+* Computing of Easter Sunday dates for any given year,
+ using Western, Orthodox or Julian algorithms;
+* A comprehensive test suite.
+
+Quick example
+=============
+Here's a snapshot, just to give an idea about the power of the
+package. For more examples, look at the documentation.
+
+Suppose you want to know how much time is left, in
+years/months/days/etc, before the next easter happening on a
+year with a Friday 13th in August, and you want to get today's
+date out of the "date" unix system command. Here is the code:
+
+.. doctest:: readmeexample
+
+ >>> from dateutil.relativedelta import *
+ >>> from dateutil.easter import *
+ >>> from dateutil.rrule import *
+ >>> from dateutil.parser import *
+ >>> from datetime import *
+ >>> now = parse("Sat Oct 11 17:13:46 UTC 2003")
+ >>> today = now.date()
+ >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year
+ >>> rdelta = relativedelta(easter(year), today)
+ >>> print("Today is: %s" % today)
+ Today is: 2003-10-11
+ >>> print("Year with next Aug 13th on a Friday is: %s" % year)
+ Year with next Aug 13th on a Friday is: 2004
+ >>> print("How far is the Easter of that year: %s" % rdelta)
+ How far is the Easter of that year: relativedelta(months=+6)
+ >>> print("And the Easter of that year is: %s" % (today+rdelta))
+ And the Easter of that year is: 2004-04-11
+
+Being exactly 6 months ahead was **really** a coincidence :)
+
+Contributing
+============
+
+We welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository.
+
+
+Author
+======
+The dateutil module was written by Gustavo Niemeyer <gustavo@niemeyer.net>
+in 2003.
+
+It is maintained by:
+
+* Gustavo Niemeyer <gustavo@niemeyer.net> 2003-2011
+* Tomi Pieviläinen <tomi.pievilainen@iki.fi> 2012-2014
+* Yaron de Leeuw <me@jarondl.net> 2014-2016
+* Paul Ganssle <paul@ganssle.io> 2015-
+
Starting with version 2.4.1 and running until 2.8.2, all source and binary
distributions will be signed by a PGP key that has, at the very least, been
signed by the key which made the previous release. A table of release signing
keys can be found below:
-
-=========== ============================
-Releases Signing key fingerprint
-=========== ============================
+
+=========== ============================
+Releases Signing key fingerprint
+=========== ============================
2.4.1-2.8.2 `6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB`_
-=========== ============================
-
+=========== ============================
+
New releases *may* have signed tags, but binary and source distributions
uploaded to PyPI will no longer have GPG signatures attached.
-
-Contact
-=======
-Our mailing list is available at `dateutil@python.org <https://mail.python.org/mailman/listinfo/dateutil>`_. As it is hosted by the PSF, it is subject to the `PSF code of
+
+Contact
+=======
+Our mailing list is available at `dateutil@python.org <https://mail.python.org/mailman/listinfo/dateutil>`_. As it is hosted by the PSF, it is subject to the `PSF code of
conduct <https://www.python.org/psf/conduct/>`_.
-
-License
-=======
-
-All contributions after December 1, 2017 released under dual license - either `Apache 2.0 License <https://www.apache.org/licenses/LICENSE-2.0>`_ or the `BSD 3-Clause License <https://opensource.org/licenses/BSD-3-Clause>`_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License.
-
-
-.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB:
- https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB
+
+License
+=======
+
+All contributions after December 1, 2017 released under dual license - either `Apache 2.0 License <https://www.apache.org/licenses/LICENSE-2.0>`_ or the `BSD 3-Clause License <https://opensource.org/licenses/BSD-3-Clause>`_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License.
+
+
+.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB:
+ https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB
diff --git a/contrib/python/dateutil/dateutil/__init__.py b/contrib/python/dateutil/dateutil/__init__.py
index f0bc8352db..0defb82e21 100644
--- a/contrib/python/dateutil/dateutil/__init__.py
+++ b/contrib/python/dateutil/dateutil/__init__.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-try:
- from ._version import version as __version__
-except ImportError:
- __version__ = 'unknown'
-
-__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz',
- 'utils', 'zoneinfo']
+try:
+ from ._version import version as __version__
+except ImportError:
+ __version__ = 'unknown'
+
+__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz',
+ 'utils', 'zoneinfo']
diff --git a/contrib/python/dateutil/dateutil/_common.py b/contrib/python/dateutil/dateutil/_common.py
index 30cc3f7520..4eb2659bd2 100644
--- a/contrib/python/dateutil/dateutil/_common.py
+++ b/contrib/python/dateutil/dateutil/_common.py
@@ -24,20 +24,20 @@ class weekday(object):
return False
return True
- def __hash__(self):
- return hash((
- self.weekday,
- self.n,
- ))
-
- def __ne__(self, other):
- return not (self == other)
-
+ def __hash__(self):
+ return hash((
+ self.weekday,
+ self.n,
+ ))
+
+ def __ne__(self, other):
+ return not (self == other)
+
def __repr__(self):
s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday]
if not self.n:
return s
else:
return "%s(%+d)" % (s, self.n)
-
-# vim:ts=4:sw=4:et
+
+# vim:ts=4:sw=4:et
diff --git a/contrib/python/dateutil/dateutil/easter.py b/contrib/python/dateutil/dateutil/easter.py
index 14a16edbf9..f74d1f7442 100644
--- a/contrib/python/dateutil/dateutil/easter.py
+++ b/contrib/python/dateutil/dateutil/easter.py
@@ -41,11 +41,11 @@ def easter(year, method=EASTER_WESTERN):
More about the algorithm may be found at:
- `GM Arts: Easter Algorithms <http://www.gmarts.org/index.php?go=415>`_
+ `GM Arts: Easter Algorithms <http://www.gmarts.org/index.php?go=415>`_
and
- `The Calendar FAQ: Easter <https://www.tondering.dk/claus/cal/easter.php>`_
+ `The Calendar FAQ: Easter <https://www.tondering.dk/claus/cal/easter.php>`_
"""
diff --git a/contrib/python/dateutil/dateutil/parser/__init__.py b/contrib/python/dateutil/dateutil/parser/__init__.py
index cda37f1a69..d174b0e4dc 100644
--- a/contrib/python/dateutil/dateutil/parser/__init__.py
+++ b/contrib/python/dateutil/dateutil/parser/__init__.py
@@ -1,61 +1,61 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
from ._parser import parse, parser, parserinfo, ParserError
-from ._parser import DEFAULTPARSER, DEFAULTTZPARSER
-from ._parser import UnknownTimezoneWarning
-
-from ._parser import __doc__
-
-from .isoparser import isoparser, isoparse
-
-__all__ = ['parse', 'parser', 'parserinfo',
- 'isoparse', 'isoparser',
+from ._parser import DEFAULTPARSER, DEFAULTTZPARSER
+from ._parser import UnknownTimezoneWarning
+
+from ._parser import __doc__
+
+from .isoparser import isoparser, isoparse
+
+__all__ = ['parse', 'parser', 'parserinfo',
+ 'isoparse', 'isoparser',
'ParserError',
- 'UnknownTimezoneWarning']
-
-
-###
-# Deprecate portions of the private interface so that downstream code that
-# is improperly relying on it is given *some* notice.
-
-
-def __deprecated_private_func(f):
- from functools import wraps
- import warnings
-
- msg = ('{name} is a private function and may break without warning, '
- 'it will be moved and or renamed in future versions.')
- msg = msg.format(name=f.__name__)
-
- @wraps(f)
- def deprecated_func(*args, **kwargs):
- warnings.warn(msg, DeprecationWarning)
- return f(*args, **kwargs)
-
- return deprecated_func
-
-def __deprecate_private_class(c):
- import warnings
-
- msg = ('{name} is a private class and may break without warning, '
- 'it will be moved and or renamed in future versions.')
- msg = msg.format(name=c.__name__)
-
- class private_class(c):
- __doc__ = c.__doc__
-
- def __init__(self, *args, **kwargs):
- warnings.warn(msg, DeprecationWarning)
- super(private_class, self).__init__(*args, **kwargs)
-
- private_class.__name__ = c.__name__
-
- return private_class
-
-
+ 'UnknownTimezoneWarning']
+
+
+###
+# Deprecate portions of the private interface so that downstream code that
+# is improperly relying on it is given *some* notice.
+
+
+def __deprecated_private_func(f):
+ from functools import wraps
+ import warnings
+
+ msg = ('{name} is a private function and may break without warning, '
+ 'it will be moved and or renamed in future versions.')
+ msg = msg.format(name=f.__name__)
+
+ @wraps(f)
+ def deprecated_func(*args, **kwargs):
+ warnings.warn(msg, DeprecationWarning)
+ return f(*args, **kwargs)
+
+ return deprecated_func
+
+def __deprecate_private_class(c):
+ import warnings
+
+ msg = ('{name} is a private class and may break without warning, '
+ 'it will be moved and or renamed in future versions.')
+ msg = msg.format(name=c.__name__)
+
+ class private_class(c):
+ __doc__ = c.__doc__
+
+ def __init__(self, *args, **kwargs):
+ warnings.warn(msg, DeprecationWarning)
+ super(private_class, self).__init__(*args, **kwargs)
+
+ private_class.__name__ = c.__name__
+
+ return private_class
+
+
from ._parser import _timelex, _resultbase
from ._parser import _tzparser, _parsetz
-
-_timelex = __deprecate_private_class(_timelex)
-_tzparser = __deprecate_private_class(_tzparser)
-_resultbase = __deprecate_private_class(_resultbase)
-_parsetz = __deprecated_private_func(_parsetz)
+
+_timelex = __deprecate_private_class(_timelex)
+_tzparser = __deprecate_private_class(_tzparser)
+_resultbase = __deprecate_private_class(_resultbase)
+_parsetz = __deprecated_private_func(_parsetz)
diff --git a/contrib/python/dateutil/dateutil/parser/_parser.py b/contrib/python/dateutil/dateutil/parser/_parser.py
index fa81f84093..37d1663b2f 100644
--- a/contrib/python/dateutil/dateutil/parser/_parser.py
+++ b/contrib/python/dateutil/dateutil/parser/_parser.py
@@ -1,1135 +1,1135 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers a generic date/time string parser which is able to parse
-most known formats to represent a date and/or time.
-
-This module attempts to be forgiving with regards to unlikely input formats,
-returning a datetime object even for dates which are ambiguous. If an element
-of a date/time stamp is omitted, the following rules are applied:
-
-- If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour
- on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is
- specified.
-- If a time zone is omitted, a timezone-naive datetime is returned.
-
-If any other elements are missing, they are taken from the
-:class:`datetime.datetime` object passed to the parameter ``default``. If this
-results in a day number exceeding the valid number of days per month, the
-value falls back to the end of the month.
-
-Additional resources about date/time string formats can be found below:
-
-- `A summary of the international standard date and time notation
+# -*- coding: utf-8 -*-
+"""
+This module offers a generic date/time string parser which is able to parse
+most known formats to represent a date and/or time.
+
+This module attempts to be forgiving with regards to unlikely input formats,
+returning a datetime object even for dates which are ambiguous. If an element
+of a date/time stamp is omitted, the following rules are applied:
+
+- If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour
+ on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is
+ specified.
+- If a time zone is omitted, a timezone-naive datetime is returned.
+
+If any other elements are missing, they are taken from the
+:class:`datetime.datetime` object passed to the parameter ``default``. If this
+results in a day number exceeding the valid number of days per month, the
+value falls back to the end of the month.
+
+Additional resources about date/time string formats can be found below:
+
+- `A summary of the international standard date and time notation
<https://www.cl.cam.ac.uk/~mgk25/iso-time.html>`_
- `W3C Date and Time Formats <https://www.w3.org/TR/NOTE-datetime>`_
-- `Time Formats (Planetary Rings Node) <https://pds-rings.seti.org:443/tools/time_formats.html>`_
-- `CPAN ParseDate module
+- `Time Formats (Planetary Rings Node) <https://pds-rings.seti.org:443/tools/time_formats.html>`_
+- `CPAN ParseDate module
<https://metacpan.org/pod/release/MUIR/Time-modules-2013.0912/lib/Time/ParseDate.pm>`_
-- `Java SimpleDateFormat Class
- <https://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>`_
-"""
-from __future__ import unicode_literals
-
-import datetime
-import re
-import string
-import time
-import warnings
-
-from calendar import monthrange
-from io import StringIO
-
-import six
+- `Java SimpleDateFormat Class
+ <https://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>`_
+"""
+from __future__ import unicode_literals
+
+import datetime
+import re
+import string
+import time
+import warnings
+
+from calendar import monthrange
+from io import StringIO
+
+import six
from six import integer_types, text_type
-
-from decimal import Decimal
-
-from warnings import warn
-
-from .. import relativedelta
-from .. import tz
-
+
+from decimal import Decimal
+
+from warnings import warn
+
+from .. import relativedelta
+from .. import tz
+
__all__ = ["parse", "parserinfo", "ParserError"]
-
-
-# TODO: pandas.core.tools.datetimes imports this explicitly. Might be worth
-# making public and/or figuring out if there is something we can
-# take off their plate.
-class _timelex(object):
- # Fractional seconds are sometimes split by a comma
- _split_decimal = re.compile("([.,])")
-
- def __init__(self, instream):
+
+
+# TODO: pandas.core.tools.datetimes imports this explicitly. Might be worth
+# making public and/or figuring out if there is something we can
+# take off their plate.
+class _timelex(object):
+ # Fractional seconds are sometimes split by a comma
+ _split_decimal = re.compile("([.,])")
+
+ def __init__(self, instream):
if isinstance(instream, (bytes, bytearray)):
instream = instream.decode()
-
- if isinstance(instream, text_type):
- instream = StringIO(instream)
- elif getattr(instream, 'read', None) is None:
- raise TypeError('Parser must be a string or character stream, not '
- '{itype}'.format(itype=instream.__class__.__name__))
-
- self.instream = instream
- self.charstack = []
- self.tokenstack = []
- self.eof = False
-
- def get_token(self):
- """
- This function breaks the time string into lexical units (tokens), which
- can be parsed by the parser. Lexical units are demarcated by changes in
- the character set, so any continuous string of letters is considered
- one unit, any continuous string of numbers is considered one unit.
-
- The main complication arises from the fact that dots ('.') can be used
- both as separators (e.g. "Sep.20.2009") or decimal points (e.g.
- "4:30:21.447"). As such, it is necessary to read the full context of
- any dot-separated strings before breaking it into tokens; as such, this
- function maintains a "token stack", for when the ambiguous context
- demands that multiple tokens be parsed at once.
- """
- if self.tokenstack:
- return self.tokenstack.pop(0)
-
- seenletters = False
- token = None
- state = None
-
- while not self.eof:
- # We only realize that we've reached the end of a token when we
- # find a character that's not part of the current token - since
- # that character may be part of the next token, it's stored in the
- # charstack.
- if self.charstack:
- nextchar = self.charstack.pop(0)
- else:
- nextchar = self.instream.read(1)
- while nextchar == '\x00':
- nextchar = self.instream.read(1)
-
- if not nextchar:
- self.eof = True
- break
- elif not state:
- # First character of the token - determines if we're starting
- # to parse a word, a number or something else.
- token = nextchar
- if self.isword(nextchar):
- state = 'a'
- elif self.isnum(nextchar):
- state = '0'
- elif self.isspace(nextchar):
- token = ' '
- break # emit token
- else:
- break # emit token
- elif state == 'a':
- # If we've already started reading a word, we keep reading
- # letters until we find something that's not part of a word.
- seenletters = True
- if self.isword(nextchar):
- token += nextchar
- elif nextchar == '.':
- token += nextchar
- state = 'a.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == '0':
- # If we've already started reading a number, we keep reading
- # numbers until we find something that doesn't fit.
- if self.isnum(nextchar):
- token += nextchar
- elif nextchar == '.' or (nextchar == ',' and len(token) >= 2):
- token += nextchar
- state = '0.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == 'a.':
- # If we've seen some letters and a dot separator, continue
- # parsing, and the tokens will be broken up later.
- seenletters = True
- if nextchar == '.' or self.isword(nextchar):
- token += nextchar
- elif self.isnum(nextchar) and token[-1] == '.':
- token += nextchar
- state = '0.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == '0.':
- # If we've seen at least one dot separator, keep going, we'll
- # break up the tokens later.
- if nextchar == '.' or self.isnum(nextchar):
- token += nextchar
- elif self.isword(nextchar) and token[-1] == '.':
- token += nextchar
- state = 'a.'
- else:
- self.charstack.append(nextchar)
- break # emit token
-
- if (state in ('a.', '0.') and (seenletters or token.count('.') > 1 or
- token[-1] in '.,')):
- l = self._split_decimal.split(token)
- token = l[0]
- for tok in l[1:]:
- if tok:
- self.tokenstack.append(tok)
-
- if state == '0.' and token.count('.') == 0:
- token = token.replace(',', '.')
-
- return token
-
- def __iter__(self):
- return self
-
- def __next__(self):
- token = self.get_token()
- if token is None:
- raise StopIteration
-
- return token
-
- def next(self):
- return self.__next__() # Python 2.x support
-
- @classmethod
- def split(cls, s):
- return list(cls(s))
-
- @classmethod
- def isword(cls, nextchar):
- """ Whether or not the next character is part of a word """
- return nextchar.isalpha()
-
- @classmethod
- def isnum(cls, nextchar):
- """ Whether the next character is part of a number """
- return nextchar.isdigit()
-
- @classmethod
- def isspace(cls, nextchar):
- """ Whether the next character is whitespace """
- return nextchar.isspace()
-
-
-class _resultbase(object):
-
- def __init__(self):
- for attr in self.__slots__:
- setattr(self, attr, None)
-
- def _repr(self, classname):
- l = []
- for attr in self.__slots__:
- value = getattr(self, attr)
- if value is not None:
- l.append("%s=%s" % (attr, repr(value)))
- return "%s(%s)" % (classname, ", ".join(l))
-
- def __len__(self):
- return (sum(getattr(self, attr) is not None
- for attr in self.__slots__))
-
- def __repr__(self):
- return self._repr(self.__class__.__name__)
-
-
-class parserinfo(object):
- """
- Class which handles what inputs are accepted. Subclass this to customize
- the language and acceptable values for each parameter.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM
- and YMD. Default is ``False``.
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken
- to be the year, otherwise the last number is taken to be the year.
- Default is ``False``.
- """
-
- # m from a.m/p.m, t from ISO T separator
- JUMP = [" ", ".", ",", ";", "-", "/", "'",
- "at", "on", "and", "ad", "m", "t", "of",
- "st", "nd", "rd", "th"]
-
- WEEKDAYS = [("Mon", "Monday"),
- ("Tue", "Tuesday"), # TODO: "Tues"
- ("Wed", "Wednesday"),
- ("Thu", "Thursday"), # TODO: "Thurs"
- ("Fri", "Friday"),
- ("Sat", "Saturday"),
- ("Sun", "Sunday")]
- MONTHS = [("Jan", "January"),
- ("Feb", "February"), # TODO: "Febr"
- ("Mar", "March"),
- ("Apr", "April"),
- ("May", "May"),
- ("Jun", "June"),
- ("Jul", "July"),
- ("Aug", "August"),
- ("Sep", "Sept", "September"),
- ("Oct", "October"),
- ("Nov", "November"),
- ("Dec", "December")]
- HMS = [("h", "hour", "hours"),
- ("m", "minute", "minutes"),
- ("s", "second", "seconds")]
- AMPM = [("am", "a"),
- ("pm", "p")]
+
+ if isinstance(instream, text_type):
+ instream = StringIO(instream)
+ elif getattr(instream, 'read', None) is None:
+ raise TypeError('Parser must be a string or character stream, not '
+ '{itype}'.format(itype=instream.__class__.__name__))
+
+ self.instream = instream
+ self.charstack = []
+ self.tokenstack = []
+ self.eof = False
+
+ def get_token(self):
+ """
+ This function breaks the time string into lexical units (tokens), which
+ can be parsed by the parser. Lexical units are demarcated by changes in
+ the character set, so any continuous string of letters is considered
+ one unit, any continuous string of numbers is considered one unit.
+
+ The main complication arises from the fact that dots ('.') can be used
+ both as separators (e.g. "Sep.20.2009") or decimal points (e.g.
+ "4:30:21.447"). As such, it is necessary to read the full context of
+ any dot-separated strings before breaking it into tokens; as such, this
+ function maintains a "token stack", for when the ambiguous context
+ demands that multiple tokens be parsed at once.
+ """
+ if self.tokenstack:
+ return self.tokenstack.pop(0)
+
+ seenletters = False
+ token = None
+ state = None
+
+ while not self.eof:
+ # We only realize that we've reached the end of a token when we
+ # find a character that's not part of the current token - since
+ # that character may be part of the next token, it's stored in the
+ # charstack.
+ if self.charstack:
+ nextchar = self.charstack.pop(0)
+ else:
+ nextchar = self.instream.read(1)
+ while nextchar == '\x00':
+ nextchar = self.instream.read(1)
+
+ if not nextchar:
+ self.eof = True
+ break
+ elif not state:
+ # First character of the token - determines if we're starting
+ # to parse a word, a number or something else.
+ token = nextchar
+ if self.isword(nextchar):
+ state = 'a'
+ elif self.isnum(nextchar):
+ state = '0'
+ elif self.isspace(nextchar):
+ token = ' '
+ break # emit token
+ else:
+ break # emit token
+ elif state == 'a':
+ # If we've already started reading a word, we keep reading
+ # letters until we find something that's not part of a word.
+ seenletters = True
+ if self.isword(nextchar):
+ token += nextchar
+ elif nextchar == '.':
+ token += nextchar
+ state = 'a.'
+ else:
+ self.charstack.append(nextchar)
+ break # emit token
+ elif state == '0':
+ # If we've already started reading a number, we keep reading
+ # numbers until we find something that doesn't fit.
+ if self.isnum(nextchar):
+ token += nextchar
+ elif nextchar == '.' or (nextchar == ',' and len(token) >= 2):
+ token += nextchar
+ state = '0.'
+ else:
+ self.charstack.append(nextchar)
+ break # emit token
+ elif state == 'a.':
+ # If we've seen some letters and a dot separator, continue
+ # parsing, and the tokens will be broken up later.
+ seenletters = True
+ if nextchar == '.' or self.isword(nextchar):
+ token += nextchar
+ elif self.isnum(nextchar) and token[-1] == '.':
+ token += nextchar
+ state = '0.'
+ else:
+ self.charstack.append(nextchar)
+ break # emit token
+ elif state == '0.':
+ # If we've seen at least one dot separator, keep going, we'll
+ # break up the tokens later.
+ if nextchar == '.' or self.isnum(nextchar):
+ token += nextchar
+ elif self.isword(nextchar) and token[-1] == '.':
+ token += nextchar
+ state = 'a.'
+ else:
+ self.charstack.append(nextchar)
+ break # emit token
+
+ if (state in ('a.', '0.') and (seenletters or token.count('.') > 1 or
+ token[-1] in '.,')):
+ l = self._split_decimal.split(token)
+ token = l[0]
+ for tok in l[1:]:
+ if tok:
+ self.tokenstack.append(tok)
+
+ if state == '0.' and token.count('.') == 0:
+ token = token.replace(',', '.')
+
+ return token
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ token = self.get_token()
+ if token is None:
+ raise StopIteration
+
+ return token
+
+ def next(self):
+ return self.__next__() # Python 2.x support
+
+ @classmethod
+ def split(cls, s):
+ return list(cls(s))
+
+ @classmethod
+ def isword(cls, nextchar):
+ """ Whether or not the next character is part of a word """
+ return nextchar.isalpha()
+
+ @classmethod
+ def isnum(cls, nextchar):
+ """ Whether the next character is part of a number """
+ return nextchar.isdigit()
+
+ @classmethod
+ def isspace(cls, nextchar):
+ """ Whether the next character is whitespace """
+ return nextchar.isspace()
+
+
+class _resultbase(object):
+
+ def __init__(self):
+ for attr in self.__slots__:
+ setattr(self, attr, None)
+
+ def _repr(self, classname):
+ l = []
+ for attr in self.__slots__:
+ value = getattr(self, attr)
+ if value is not None:
+ l.append("%s=%s" % (attr, repr(value)))
+ return "%s(%s)" % (classname, ", ".join(l))
+
+ def __len__(self):
+ return (sum(getattr(self, attr) is not None
+ for attr in self.__slots__))
+
+ def __repr__(self):
+ return self._repr(self.__class__.__name__)
+
+
+class parserinfo(object):
+ """
+ Class which handles what inputs are accepted. Subclass this to customize
+ the language and acceptable values for each parameter.
+
+ :param dayfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM
+ and YMD. Default is ``False``.
+
+ :param yearfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken
+ to be the year, otherwise the last number is taken to be the year.
+ Default is ``False``.
+ """
+
+ # m from a.m/p.m, t from ISO T separator
+ JUMP = [" ", ".", ",", ";", "-", "/", "'",
+ "at", "on", "and", "ad", "m", "t", "of",
+ "st", "nd", "rd", "th"]
+
+ WEEKDAYS = [("Mon", "Monday"),
+ ("Tue", "Tuesday"), # TODO: "Tues"
+ ("Wed", "Wednesday"),
+ ("Thu", "Thursday"), # TODO: "Thurs"
+ ("Fri", "Friday"),
+ ("Sat", "Saturday"),
+ ("Sun", "Sunday")]
+ MONTHS = [("Jan", "January"),
+ ("Feb", "February"), # TODO: "Febr"
+ ("Mar", "March"),
+ ("Apr", "April"),
+ ("May", "May"),
+ ("Jun", "June"),
+ ("Jul", "July"),
+ ("Aug", "August"),
+ ("Sep", "Sept", "September"),
+ ("Oct", "October"),
+ ("Nov", "November"),
+ ("Dec", "December")]
+ HMS = [("h", "hour", "hours"),
+ ("m", "minute", "minutes"),
+ ("s", "second", "seconds")]
+ AMPM = [("am", "a"),
+ ("pm", "p")]
UTCZONE = ["UTC", "GMT", "Z", "z"]
- PERTAIN = ["of"]
- TZOFFSET = {}
- # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate",
- # "Anno Domini", "Year of Our Lord"]
-
- def __init__(self, dayfirst=False, yearfirst=False):
- self._jump = self._convert(self.JUMP)
- self._weekdays = self._convert(self.WEEKDAYS)
- self._months = self._convert(self.MONTHS)
- self._hms = self._convert(self.HMS)
- self._ampm = self._convert(self.AMPM)
- self._utczone = self._convert(self.UTCZONE)
- self._pertain = self._convert(self.PERTAIN)
-
- self.dayfirst = dayfirst
- self.yearfirst = yearfirst
-
- self._year = time.localtime().tm_year
- self._century = self._year // 100 * 100
-
- def _convert(self, lst):
- dct = {}
- for i, v in enumerate(lst):
- if isinstance(v, tuple):
- for v in v:
- dct[v.lower()] = i
- else:
- dct[v.lower()] = i
- return dct
-
- def jump(self, name):
- return name.lower() in self._jump
-
- def weekday(self, name):
- try:
- return self._weekdays[name.lower()]
- except KeyError:
- pass
- return None
-
- def month(self, name):
- try:
- return self._months[name.lower()] + 1
- except KeyError:
- pass
- return None
-
- def hms(self, name):
- try:
- return self._hms[name.lower()]
- except KeyError:
- return None
-
- def ampm(self, name):
- try:
- return self._ampm[name.lower()]
- except KeyError:
- return None
-
- def pertain(self, name):
- return name.lower() in self._pertain
-
- def utczone(self, name):
- return name.lower() in self._utczone
-
- def tzoffset(self, name):
- if name in self._utczone:
- return 0
-
- return self.TZOFFSET.get(name)
-
- def convertyear(self, year, century_specified=False):
- """
- Converts two-digit years to year within [-50, 49]
- range of self._year (current local time)
- """
-
- # Function contract is that the year is always positive
- assert year >= 0
-
- if year < 100 and not century_specified:
- # assume current century to start
- year += self._century
-
- if year >= self._year + 50: # if too far in future
- year -= 100
- elif year < self._year - 50: # if too far in past
- year += 100
-
- return year
-
- def validate(self, res):
- # move to info
- if res.year is not None:
- res.year = self.convertyear(res.year, res.century_specified)
-
+ PERTAIN = ["of"]
+ TZOFFSET = {}
+ # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate",
+ # "Anno Domini", "Year of Our Lord"]
+
+ def __init__(self, dayfirst=False, yearfirst=False):
+ self._jump = self._convert(self.JUMP)
+ self._weekdays = self._convert(self.WEEKDAYS)
+ self._months = self._convert(self.MONTHS)
+ self._hms = self._convert(self.HMS)
+ self._ampm = self._convert(self.AMPM)
+ self._utczone = self._convert(self.UTCZONE)
+ self._pertain = self._convert(self.PERTAIN)
+
+ self.dayfirst = dayfirst
+ self.yearfirst = yearfirst
+
+ self._year = time.localtime().tm_year
+ self._century = self._year // 100 * 100
+
+ def _convert(self, lst):
+ dct = {}
+ for i, v in enumerate(lst):
+ if isinstance(v, tuple):
+ for v in v:
+ dct[v.lower()] = i
+ else:
+ dct[v.lower()] = i
+ return dct
+
+ def jump(self, name):
+ return name.lower() in self._jump
+
+ def weekday(self, name):
+ try:
+ return self._weekdays[name.lower()]
+ except KeyError:
+ pass
+ return None
+
+ def month(self, name):
+ try:
+ return self._months[name.lower()] + 1
+ except KeyError:
+ pass
+ return None
+
+ def hms(self, name):
+ try:
+ return self._hms[name.lower()]
+ except KeyError:
+ return None
+
+ def ampm(self, name):
+ try:
+ return self._ampm[name.lower()]
+ except KeyError:
+ return None
+
+ def pertain(self, name):
+ return name.lower() in self._pertain
+
+ def utczone(self, name):
+ return name.lower() in self._utczone
+
+ def tzoffset(self, name):
+ if name in self._utczone:
+ return 0
+
+ return self.TZOFFSET.get(name)
+
+ def convertyear(self, year, century_specified=False):
+ """
+ Converts two-digit years to year within [-50, 49]
+ range of self._year (current local time)
+ """
+
+ # Function contract is that the year is always positive
+ assert year >= 0
+
+ if year < 100 and not century_specified:
+ # assume current century to start
+ year += self._century
+
+ if year >= self._year + 50: # if too far in future
+ year -= 100
+ elif year < self._year - 50: # if too far in past
+ year += 100
+
+ return year
+
+ def validate(self, res):
+ # move to info
+ if res.year is not None:
+ res.year = self.convertyear(res.year, res.century_specified)
+
if ((res.tzoffset == 0 and not res.tzname) or
(res.tzname == 'Z' or res.tzname == 'z')):
- res.tzname = "UTC"
- res.tzoffset = 0
- elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname):
- res.tzoffset = 0
- return True
-
-
-class _ymd(list):
- def __init__(self, *args, **kwargs):
- super(self.__class__, self).__init__(*args, **kwargs)
- self.century_specified = False
- self.dstridx = None
- self.mstridx = None
- self.ystridx = None
-
- @property
- def has_year(self):
- return self.ystridx is not None
-
- @property
- def has_month(self):
- return self.mstridx is not None
-
- @property
- def has_day(self):
- return self.dstridx is not None
-
- def could_be_day(self, value):
- if self.has_day:
- return False
- elif not self.has_month:
- return 1 <= value <= 31
- elif not self.has_year:
+ res.tzname = "UTC"
+ res.tzoffset = 0
+ elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname):
+ res.tzoffset = 0
+ return True
+
+
+class _ymd(list):
+ def __init__(self, *args, **kwargs):
+ super(self.__class__, self).__init__(*args, **kwargs)
+ self.century_specified = False
+ self.dstridx = None
+ self.mstridx = None
+ self.ystridx = None
+
+ @property
+ def has_year(self):
+ return self.ystridx is not None
+
+ @property
+ def has_month(self):
+ return self.mstridx is not None
+
+ @property
+ def has_day(self):
+ return self.dstridx is not None
+
+ def could_be_day(self, value):
+ if self.has_day:
+ return False
+ elif not self.has_month:
+ return 1 <= value <= 31
+ elif not self.has_year:
# Be permissive, assume leap year
- month = self[self.mstridx]
- return 1 <= value <= monthrange(2000, month)[1]
- else:
- month = self[self.mstridx]
- year = self[self.ystridx]
- return 1 <= value <= monthrange(year, month)[1]
-
- def append(self, val, label=None):
- if hasattr(val, '__len__'):
- if val.isdigit() and len(val) > 2:
- self.century_specified = True
- if label not in [None, 'Y']: # pragma: no cover
- raise ValueError(label)
- label = 'Y'
- elif val > 100:
- self.century_specified = True
- if label not in [None, 'Y']: # pragma: no cover
- raise ValueError(label)
- label = 'Y'
-
- super(self.__class__, self).append(int(val))
-
- if label == 'M':
- if self.has_month:
- raise ValueError('Month is already set')
- self.mstridx = len(self) - 1
- elif label == 'D':
- if self.has_day:
- raise ValueError('Day is already set')
- self.dstridx = len(self) - 1
- elif label == 'Y':
- if self.has_year:
- raise ValueError('Year is already set')
- self.ystridx = len(self) - 1
-
- def _resolve_from_stridxs(self, strids):
- """
- Try to resolve the identities of year/month/day elements using
- ystridx, mstridx, and dstridx, if enough of these are specified.
- """
- if len(self) == 3 and len(strids) == 2:
- # we can back out the remaining stridx value
- missing = [x for x in range(3) if x not in strids.values()]
- key = [x for x in ['y', 'm', 'd'] if x not in strids]
- assert len(missing) == len(key) == 1
- key = key[0]
- val = missing[0]
- strids[key] = val
-
- assert len(self) == len(strids) # otherwise this should not be called
- out = {key: self[strids[key]] for key in strids}
- return (out.get('y'), out.get('m'), out.get('d'))
-
- def resolve_ymd(self, yearfirst, dayfirst):
- len_ymd = len(self)
- year, month, day = (None, None, None)
-
- strids = (('y', self.ystridx),
- ('m', self.mstridx),
- ('d', self.dstridx))
-
- strids = {key: val for key, val in strids if val is not None}
- if (len(self) == len(strids) > 0 or
- (len(self) == 3 and len(strids) == 2)):
- return self._resolve_from_stridxs(strids)
-
- mstridx = self.mstridx
-
- if len_ymd > 3:
- raise ValueError("More than three YMD values")
- elif len_ymd == 1 or (mstridx is not None and len_ymd == 2):
- # One member, or two members with a month string
- if mstridx is not None:
- month = self[mstridx]
- # since mstridx is 0 or 1, self[mstridx-1] always
- # looks up the other element
- other = self[mstridx - 1]
- else:
- other = self[0]
-
- if len_ymd > 1 or mstridx is None:
- if other > 31:
- year = other
- else:
- day = other
-
- elif len_ymd == 2:
- # Two members with numbers
- if self[0] > 31:
- # 99-01
- year, month = self
- elif self[1] > 31:
- # 01-99
- month, year = self
- elif dayfirst and self[1] <= 12:
- # 13-01
- day, month = self
- else:
- # 01-13
- month, day = self
-
- elif len_ymd == 3:
- # Three members
- if mstridx == 0:
- if self[1] > 31:
- # Apr-2003-25
- month, year, day = self
- else:
- month, day, year = self
- elif mstridx == 1:
- if self[0] > 31 or (yearfirst and self[2] <= 31):
- # 99-Jan-01
- year, month, day = self
- else:
- # 01-Jan-01
+ month = self[self.mstridx]
+ return 1 <= value <= monthrange(2000, month)[1]
+ else:
+ month = self[self.mstridx]
+ year = self[self.ystridx]
+ return 1 <= value <= monthrange(year, month)[1]
+
+ def append(self, val, label=None):
+ if hasattr(val, '__len__'):
+ if val.isdigit() and len(val) > 2:
+ self.century_specified = True
+ if label not in [None, 'Y']: # pragma: no cover
+ raise ValueError(label)
+ label = 'Y'
+ elif val > 100:
+ self.century_specified = True
+ if label not in [None, 'Y']: # pragma: no cover
+ raise ValueError(label)
+ label = 'Y'
+
+ super(self.__class__, self).append(int(val))
+
+ if label == 'M':
+ if self.has_month:
+ raise ValueError('Month is already set')
+ self.mstridx = len(self) - 1
+ elif label == 'D':
+ if self.has_day:
+ raise ValueError('Day is already set')
+ self.dstridx = len(self) - 1
+ elif label == 'Y':
+ if self.has_year:
+ raise ValueError('Year is already set')
+ self.ystridx = len(self) - 1
+
+ def _resolve_from_stridxs(self, strids):
+ """
+ Try to resolve the identities of year/month/day elements using
+ ystridx, mstridx, and dstridx, if enough of these are specified.
+ """
+ if len(self) == 3 and len(strids) == 2:
+ # we can back out the remaining stridx value
+ missing = [x for x in range(3) if x not in strids.values()]
+ key = [x for x in ['y', 'm', 'd'] if x not in strids]
+ assert len(missing) == len(key) == 1
+ key = key[0]
+ val = missing[0]
+ strids[key] = val
+
+ assert len(self) == len(strids) # otherwise this should not be called
+ out = {key: self[strids[key]] for key in strids}
+ return (out.get('y'), out.get('m'), out.get('d'))
+
+ def resolve_ymd(self, yearfirst, dayfirst):
+ len_ymd = len(self)
+ year, month, day = (None, None, None)
+
+ strids = (('y', self.ystridx),
+ ('m', self.mstridx),
+ ('d', self.dstridx))
+
+ strids = {key: val for key, val in strids if val is not None}
+ if (len(self) == len(strids) > 0 or
+ (len(self) == 3 and len(strids) == 2)):
+ return self._resolve_from_stridxs(strids)
+
+ mstridx = self.mstridx
+
+ if len_ymd > 3:
+ raise ValueError("More than three YMD values")
+ elif len_ymd == 1 or (mstridx is not None and len_ymd == 2):
+ # One member, or two members with a month string
+ if mstridx is not None:
+ month = self[mstridx]
+ # since mstridx is 0 or 1, self[mstridx-1] always
+ # looks up the other element
+ other = self[mstridx - 1]
+ else:
+ other = self[0]
+
+ if len_ymd > 1 or mstridx is None:
+ if other > 31:
+ year = other
+ else:
+ day = other
+
+ elif len_ymd == 2:
+ # Two members with numbers
+ if self[0] > 31:
+ # 99-01
+ year, month = self
+ elif self[1] > 31:
+ # 01-99
+ month, year = self
+ elif dayfirst and self[1] <= 12:
+ # 13-01
+ day, month = self
+ else:
+ # 01-13
+ month, day = self
+
+ elif len_ymd == 3:
+ # Three members
+ if mstridx == 0:
+ if self[1] > 31:
+ # Apr-2003-25
+ month, year, day = self
+ else:
+ month, day, year = self
+ elif mstridx == 1:
+ if self[0] > 31 or (yearfirst and self[2] <= 31):
+ # 99-Jan-01
+ year, month, day = self
+ else:
+ # 01-Jan-01
# Give precedence to day-first, since
- # two-digit years is usually hand-written.
- day, month, year = self
-
- elif mstridx == 2:
- # WTF!?
- if self[1] > 31:
- # 01-99-Jan
- day, year, month = self
- else:
- # 99-01-Jan
- year, day, month = self
-
- else:
- if (self[0] > 31 or
- self.ystridx == 0 or
- (yearfirst and self[1] <= 12 and self[2] <= 31)):
- # 99-01-01
- if dayfirst and self[2] <= 12:
- year, day, month = self
- else:
- year, month, day = self
- elif self[0] > 12 or (dayfirst and self[1] <= 12):
- # 13-01-01
- day, month, year = self
- else:
- # 01-13-01
- month, day, year = self
-
- return year, month, day
-
-
-class parser(object):
- def __init__(self, info=None):
- self.info = info or parserinfo()
-
- def parse(self, timestr, default=None,
- ignoretz=False, tzinfos=None, **kwargs):
- """
- Parse the date/time string into a :class:`datetime.datetime` object.
-
- :param timestr:
- Any date/time string using the supported formats.
-
- :param default:
- The default datetime object, if this is a datetime object and not
- ``None``, elements specified in ``timestr`` replace elements in the
- default object.
-
- :param ignoretz:
- If set ``True``, time zones in parsed strings are ignored and a
- naive :class:`datetime.datetime` object is returned.
-
- :param tzinfos:
- Additional time zone names / aliases which may be present in the
- string. This argument maps time zone names (and optionally offsets
- from those time zones) to time zones. This parameter can be a
- dictionary with timezone aliases mapping time zone names to time
- zones or a function taking two parameters (``tzname`` and
- ``tzoffset``) and returning a time zone.
-
- The timezones to which the names are mapped can be an integer
- offset from UTC in seconds or a :class:`tzinfo` object.
-
- .. doctest::
- :options: +NORMALIZE_WHITESPACE
-
- >>> from dateutil.parser import parse
- >>> from dateutil.tz import gettz
- >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
- >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
- >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21,
- tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
-
- This parameter is ignored if ``ignoretz`` is set.
-
- :param \\*\\*kwargs:
- Keyword arguments as passed to ``_parse()``.
-
- :return:
- Returns a :class:`datetime.datetime` object or, if the
- ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
- first element being a :class:`datetime.datetime` object, the second
- a tuple containing the fuzzy tokens.
-
+ # two-digit years is usually hand-written.
+ day, month, year = self
+
+ elif mstridx == 2:
+ # WTF!?
+ if self[1] > 31:
+ # 01-99-Jan
+ day, year, month = self
+ else:
+ # 99-01-Jan
+ year, day, month = self
+
+ else:
+ if (self[0] > 31 or
+ self.ystridx == 0 or
+ (yearfirst and self[1] <= 12 and self[2] <= 31)):
+ # 99-01-01
+ if dayfirst and self[2] <= 12:
+ year, day, month = self
+ else:
+ year, month, day = self
+ elif self[0] > 12 or (dayfirst and self[1] <= 12):
+ # 13-01-01
+ day, month, year = self
+ else:
+ # 01-13-01
+ month, day, year = self
+
+ return year, month, day
+
+
+class parser(object):
+ def __init__(self, info=None):
+ self.info = info or parserinfo()
+
+ def parse(self, timestr, default=None,
+ ignoretz=False, tzinfos=None, **kwargs):
+ """
+ Parse the date/time string into a :class:`datetime.datetime` object.
+
+ :param timestr:
+ Any date/time string using the supported formats.
+
+ :param default:
+ The default datetime object, if this is a datetime object and not
+ ``None``, elements specified in ``timestr`` replace elements in the
+ default object.
+
+ :param ignoretz:
+ If set ``True``, time zones in parsed strings are ignored and a
+ naive :class:`datetime.datetime` object is returned.
+
+ :param tzinfos:
+ Additional time zone names / aliases which may be present in the
+ string. This argument maps time zone names (and optionally offsets
+ from those time zones) to time zones. This parameter can be a
+ dictionary with timezone aliases mapping time zone names to time
+ zones or a function taking two parameters (``tzname`` and
+ ``tzoffset``) and returning a time zone.
+
+ The timezones to which the names are mapped can be an integer
+ offset from UTC in seconds or a :class:`tzinfo` object.
+
+ .. doctest::
+ :options: +NORMALIZE_WHITESPACE
+
+ >>> from dateutil.parser import parse
+ >>> from dateutil.tz import gettz
+ >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
+ >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
+ datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
+ >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
+ datetime.datetime(2012, 1, 19, 17, 21,
+ tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
+
+ This parameter is ignored if ``ignoretz`` is set.
+
+ :param \\*\\*kwargs:
+ Keyword arguments as passed to ``_parse()``.
+
+ :return:
+ Returns a :class:`datetime.datetime` object or, if the
+ ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
+ first element being a :class:`datetime.datetime` object, the second
+ a tuple containing the fuzzy tokens.
+
:raises ParserError:
- Raised for invalid or unknown string format, if the provided
- :class:`tzinfo` is not in a valid format, or if an invalid date
- would be created.
-
- :raises TypeError:
- Raised for non-string or character stream input.
-
- :raises OverflowError:
- Raised if the parsed date exceeds the largest valid C integer on
- your system.
- """
-
- if default is None:
- default = datetime.datetime.now().replace(hour=0, minute=0,
- second=0, microsecond=0)
-
- res, skipped_tokens = self._parse(timestr, **kwargs)
-
- if res is None:
+ Raised for invalid or unknown string format, if the provided
+ :class:`tzinfo` is not in a valid format, or if an invalid date
+ would be created.
+
+ :raises TypeError:
+ Raised for non-string or character stream input.
+
+ :raises OverflowError:
+ Raised if the parsed date exceeds the largest valid C integer on
+ your system.
+ """
+
+ if default is None:
+ default = datetime.datetime.now().replace(hour=0, minute=0,
+ second=0, microsecond=0)
+
+ res, skipped_tokens = self._parse(timestr, **kwargs)
+
+ if res is None:
raise ParserError("Unknown string format: %s", timestr)
-
- if len(res) == 0:
+
+ if len(res) == 0:
raise ParserError("String does not contain a date: %s", timestr)
-
+
try:
ret = self._build_naive(res, default)
except ValueError as e:
six.raise_from(ParserError(str(e) + ": %s", timestr), e)
-
- if not ignoretz:
- ret = self._build_tzaware(ret, res, tzinfos)
-
- if kwargs.get('fuzzy_with_tokens', False):
- return ret, skipped_tokens
- else:
- return ret
-
- class _result(_resultbase):
- __slots__ = ["year", "month", "day", "weekday",
- "hour", "minute", "second", "microsecond",
- "tzname", "tzoffset", "ampm","any_unused_tokens"]
-
- def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
- fuzzy_with_tokens=False):
- """
- Private method which performs the heavy lifting of parsing, called from
- ``parse()``, which passes on its ``kwargs`` to this function.
-
- :param timestr:
- The string to parse.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM
- and YMD. If set to ``None``, this value is retrieved from the
- current :class:`parserinfo` object (which itself defaults to
- ``False``).
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken
- to be the year, otherwise the last number is taken to be the year.
- If this is set to ``None``, the value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param fuzzy:
- Whether to allow fuzzy parsing, allowing for string like "Today is
- January 1, 2047 at 8:21:00AM".
-
- :param fuzzy_with_tokens:
- If ``True``, ``fuzzy`` is automatically set to True, and the parser
- will return a tuple where the first element is the parsed
- :class:`datetime.datetime` datetimestamp and the second element is
- a tuple containing the portions of the string which were ignored:
-
- .. doctest::
-
- >>> from dateutil.parser import parse
- >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
- (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
-
- """
- if fuzzy_with_tokens:
- fuzzy = True
-
- info = self.info
-
- if dayfirst is None:
- dayfirst = info.dayfirst
-
- if yearfirst is None:
- yearfirst = info.yearfirst
-
- res = self._result()
- l = _timelex.split(timestr) # Splits the timestr into tokens
-
- skipped_idxs = []
-
- # year/month/day list
- ymd = _ymd()
-
- len_l = len(l)
- i = 0
- try:
- while i < len_l:
-
- # Check if it's a number
- value_repr = l[i]
- try:
- value = float(value_repr)
- except ValueError:
- value = None
-
- if value is not None:
- # Numeric token
- i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
-
- # Check weekday
- elif info.weekday(l[i]) is not None:
- value = info.weekday(l[i])
- res.weekday = value
-
- # Check month name
- elif info.month(l[i]) is not None:
- value = info.month(l[i])
- ymd.append(value, 'M')
-
- if i + 1 < len_l:
- if l[i + 1] in ('-', '/'):
- # Jan-01[-99]
- sep = l[i + 1]
- ymd.append(l[i + 2])
-
- if i + 3 < len_l and l[i + 3] == sep:
- # Jan-01-99
- ymd.append(l[i + 4])
- i += 2
-
- i += 2
-
- elif (i + 4 < len_l and l[i + 1] == l[i + 3] == ' ' and
- info.pertain(l[i + 2])):
- # Jan of 01
- # In this case, 01 is clearly year
- if l[i + 4].isdigit():
- # Convert it here to become unambiguous
- value = int(l[i + 4])
- year = str(info.convertyear(value))
- ymd.append(year, 'Y')
- else:
- # Wrong guess
- pass
- # TODO: not hit in tests
- i += 4
-
- # Check am/pm
- elif info.ampm(l[i]) is not None:
- value = info.ampm(l[i])
- val_is_ampm = self._ampm_valid(res.hour, res.ampm, fuzzy)
-
- if val_is_ampm:
- res.hour = self._adjust_ampm(res.hour, value)
- res.ampm = value
-
- elif fuzzy:
- skipped_idxs.append(i)
-
- # Check for a timezone name
- elif self._could_be_tzname(res.hour, res.tzname, res.tzoffset, l[i]):
- res.tzname = l[i]
- res.tzoffset = info.tzoffset(res.tzname)
-
- # Check for something like GMT+3, or BRST+3. Notice
- # that it doesn't mean "I am 3 hours after GMT", but
- # "my time +3 is GMT". If found, we reverse the
- # logic so that timezone parsing code will get it
- # right.
- if i + 1 < len_l and l[i + 1] in ('+', '-'):
- l[i + 1] = ('+', '-')[l[i + 1] == '+']
- res.tzoffset = None
- if info.utczone(res.tzname):
- # With something like GMT+3, the timezone
- # is *not* GMT.
- res.tzname = None
-
- # Check for a numbered timezone
- elif res.hour is not None and l[i] in ('+', '-'):
- signal = (-1, 1)[l[i] == '+']
- len_li = len(l[i + 1])
-
- # TODO: check that l[i + 1] is integer?
- if len_li == 4:
- # -0300
- hour_offset = int(l[i + 1][:2])
- min_offset = int(l[i + 1][2:])
- elif i + 2 < len_l and l[i + 2] == ':':
- # -03:00
- hour_offset = int(l[i + 1])
- min_offset = int(l[i + 3]) # TODO: Check that l[i+3] is minute-like?
- i += 2
- elif len_li <= 2:
- # -[0]3
- hour_offset = int(l[i + 1][:2])
- min_offset = 0
- else:
- raise ValueError(timestr)
-
- res.tzoffset = signal * (hour_offset * 3600 + min_offset * 60)
-
- # Look for a timezone name between parenthesis
- if (i + 5 < len_l and
- info.jump(l[i + 2]) and l[i + 3] == '(' and
- l[i + 5] == ')' and
- 3 <= len(l[i + 4]) and
- self._could_be_tzname(res.hour, res.tzname,
- None, l[i + 4])):
- # -0300 (BRST)
- res.tzname = l[i + 4]
- i += 4
-
- i += 1
-
- # Check jumps
- elif not (info.jump(l[i]) or fuzzy):
- raise ValueError(timestr)
-
- else:
- skipped_idxs.append(i)
- i += 1
-
- # Process year/month/day
- year, month, day = ymd.resolve_ymd(yearfirst, dayfirst)
-
- res.century_specified = ymd.century_specified
- res.year = year
- res.month = month
- res.day = day
-
- except (IndexError, ValueError):
- return None, None
-
- if not info.validate(res):
- return None, None
-
- if fuzzy_with_tokens:
- skipped_tokens = self._recombine_skipped(l, skipped_idxs)
- return res, tuple(skipped_tokens)
- else:
- return res, None
-
- def _parse_numeric_token(self, tokens, idx, info, ymd, res, fuzzy):
- # Token is a number
- value_repr = tokens[idx]
- try:
- value = self._to_decimal(value_repr)
- except Exception as e:
- six.raise_from(ValueError('Unknown numeric token'), e)
-
- len_li = len(value_repr)
-
- len_l = len(tokens)
-
- if (len(ymd) == 3 and len_li in (2, 4) and
- res.hour is None and
- (idx + 1 >= len_l or
- (tokens[idx + 1] != ':' and
- info.hms(tokens[idx + 1]) is None))):
- # 19990101T23[59]
- s = tokens[idx]
- res.hour = int(s[:2])
-
- if len_li == 4:
- res.minute = int(s[2:])
-
- elif len_li == 6 or (len_li > 6 and tokens[idx].find('.') == 6):
- # YYMMDD or HHMMSS[.ss]
- s = tokens[idx]
-
- if not ymd and '.' not in tokens[idx]:
- ymd.append(s[:2])
- ymd.append(s[2:4])
- ymd.append(s[4:])
- else:
- # 19990101T235959[.59]
-
- # TODO: Check if res attributes already set.
- res.hour = int(s[:2])
- res.minute = int(s[2:4])
- res.second, res.microsecond = self._parsems(s[4:])
-
- elif len_li in (8, 12, 14):
- # YYYYMMDD
- s = tokens[idx]
- ymd.append(s[:4], 'Y')
- ymd.append(s[4:6])
- ymd.append(s[6:8])
-
- if len_li > 8:
- res.hour = int(s[8:10])
- res.minute = int(s[10:12])
-
- if len_li > 12:
- res.second = int(s[12:])
-
- elif self._find_hms_idx(idx, tokens, info, allow_jump=True) is not None:
- # HH[ ]h or MM[ ]m or SS[.ss][ ]s
- hms_idx = self._find_hms_idx(idx, tokens, info, allow_jump=True)
- (idx, hms) = self._parse_hms(idx, tokens, info, hms_idx)
- if hms is not None:
- # TODO: checking that hour/minute/second are not
- # already set?
- self._assign_hms(res, value_repr, hms)
-
- elif idx + 2 < len_l and tokens[idx + 1] == ':':
- # HH:MM[:SS[.ss]]
- res.hour = int(value)
- value = self._to_decimal(tokens[idx + 2]) # TODO: try/except for this?
- (res.minute, res.second) = self._parse_min_sec(value)
-
- if idx + 4 < len_l and tokens[idx + 3] == ':':
- res.second, res.microsecond = self._parsems(tokens[idx + 4])
-
- idx += 2
-
- idx += 2
-
- elif idx + 1 < len_l and tokens[idx + 1] in ('-', '/', '.'):
- sep = tokens[idx + 1]
- ymd.append(value_repr)
-
- if idx + 2 < len_l and not info.jump(tokens[idx + 2]):
- if tokens[idx + 2].isdigit():
- # 01-01[-01]
- ymd.append(tokens[idx + 2])
- else:
- # 01-Jan[-01]
- value = info.month(tokens[idx + 2])
-
- if value is not None:
- ymd.append(value, 'M')
- else:
- raise ValueError()
-
- if idx + 3 < len_l and tokens[idx + 3] == sep:
- # We have three members
- value = info.month(tokens[idx + 4])
-
- if value is not None:
- ymd.append(value, 'M')
- else:
- ymd.append(tokens[idx + 4])
- idx += 2
-
- idx += 1
- idx += 1
-
- elif idx + 1 >= len_l or info.jump(tokens[idx + 1]):
- if idx + 2 < len_l and info.ampm(tokens[idx + 2]) is not None:
- # 12 am
- hour = int(value)
- res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 2]))
- idx += 1
- else:
- # Year, month or day
- ymd.append(value)
- idx += 1
-
- elif info.ampm(tokens[idx + 1]) is not None and (0 <= value < 24):
- # 12am
- hour = int(value)
- res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 1]))
- idx += 1
-
- elif ymd.could_be_day(value):
- ymd.append(value)
-
- elif not fuzzy:
- raise ValueError()
-
- return idx
-
- def _find_hms_idx(self, idx, tokens, info, allow_jump):
- len_l = len(tokens)
-
- if idx+1 < len_l and info.hms(tokens[idx+1]) is not None:
- # There is an "h", "m", or "s" label following this token. We take
- # assign the upcoming label to the current token.
- # e.g. the "12" in 12h"
- hms_idx = idx + 1
-
- elif (allow_jump and idx+2 < len_l and tokens[idx+1] == ' ' and
- info.hms(tokens[idx+2]) is not None):
- # There is a space and then an "h", "m", or "s" label.
- # e.g. the "12" in "12 h"
- hms_idx = idx + 2
-
- elif idx > 0 and info.hms(tokens[idx-1]) is not None:
+
+ if not ignoretz:
+ ret = self._build_tzaware(ret, res, tzinfos)
+
+ if kwargs.get('fuzzy_with_tokens', False):
+ return ret, skipped_tokens
+ else:
+ return ret
+
+ class _result(_resultbase):
+ __slots__ = ["year", "month", "day", "weekday",
+ "hour", "minute", "second", "microsecond",
+ "tzname", "tzoffset", "ampm","any_unused_tokens"]
+
+ def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
+ fuzzy_with_tokens=False):
+ """
+ Private method which performs the heavy lifting of parsing, called from
+ ``parse()``, which passes on its ``kwargs`` to this function.
+
+ :param timestr:
+ The string to parse.
+
+ :param dayfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM
+ and YMD. If set to ``None``, this value is retrieved from the
+ current :class:`parserinfo` object (which itself defaults to
+ ``False``).
+
+ :param yearfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken
+ to be the year, otherwise the last number is taken to be the year.
+ If this is set to ``None``, the value is retrieved from the current
+ :class:`parserinfo` object (which itself defaults to ``False``).
+
+ :param fuzzy:
+ Whether to allow fuzzy parsing, allowing for string like "Today is
+ January 1, 2047 at 8:21:00AM".
+
+ :param fuzzy_with_tokens:
+ If ``True``, ``fuzzy`` is automatically set to True, and the parser
+ will return a tuple where the first element is the parsed
+ :class:`datetime.datetime` datetimestamp and the second element is
+ a tuple containing the portions of the string which were ignored:
+
+ .. doctest::
+
+ >>> from dateutil.parser import parse
+ >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
+ (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
+
+ """
+ if fuzzy_with_tokens:
+ fuzzy = True
+
+ info = self.info
+
+ if dayfirst is None:
+ dayfirst = info.dayfirst
+
+ if yearfirst is None:
+ yearfirst = info.yearfirst
+
+ res = self._result()
+ l = _timelex.split(timestr) # Splits the timestr into tokens
+
+ skipped_idxs = []
+
+ # year/month/day list
+ ymd = _ymd()
+
+ len_l = len(l)
+ i = 0
+ try:
+ while i < len_l:
+
+ # Check if it's a number
+ value_repr = l[i]
+ try:
+ value = float(value_repr)
+ except ValueError:
+ value = None
+
+ if value is not None:
+ # Numeric token
+ i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
+
+ # Check weekday
+ elif info.weekday(l[i]) is not None:
+ value = info.weekday(l[i])
+ res.weekday = value
+
+ # Check month name
+ elif info.month(l[i]) is not None:
+ value = info.month(l[i])
+ ymd.append(value, 'M')
+
+ if i + 1 < len_l:
+ if l[i + 1] in ('-', '/'):
+ # Jan-01[-99]
+ sep = l[i + 1]
+ ymd.append(l[i + 2])
+
+ if i + 3 < len_l and l[i + 3] == sep:
+ # Jan-01-99
+ ymd.append(l[i + 4])
+ i += 2
+
+ i += 2
+
+ elif (i + 4 < len_l and l[i + 1] == l[i + 3] == ' ' and
+ info.pertain(l[i + 2])):
+ # Jan of 01
+ # In this case, 01 is clearly year
+ if l[i + 4].isdigit():
+ # Convert it here to become unambiguous
+ value = int(l[i + 4])
+ year = str(info.convertyear(value))
+ ymd.append(year, 'Y')
+ else:
+ # Wrong guess
+ pass
+ # TODO: not hit in tests
+ i += 4
+
+ # Check am/pm
+ elif info.ampm(l[i]) is not None:
+ value = info.ampm(l[i])
+ val_is_ampm = self._ampm_valid(res.hour, res.ampm, fuzzy)
+
+ if val_is_ampm:
+ res.hour = self._adjust_ampm(res.hour, value)
+ res.ampm = value
+
+ elif fuzzy:
+ skipped_idxs.append(i)
+
+ # Check for a timezone name
+ elif self._could_be_tzname(res.hour, res.tzname, res.tzoffset, l[i]):
+ res.tzname = l[i]
+ res.tzoffset = info.tzoffset(res.tzname)
+
+ # Check for something like GMT+3, or BRST+3. Notice
+ # that it doesn't mean "I am 3 hours after GMT", but
+ # "my time +3 is GMT". If found, we reverse the
+ # logic so that timezone parsing code will get it
+ # right.
+ if i + 1 < len_l and l[i + 1] in ('+', '-'):
+ l[i + 1] = ('+', '-')[l[i + 1] == '+']
+ res.tzoffset = None
+ if info.utczone(res.tzname):
+ # With something like GMT+3, the timezone
+ # is *not* GMT.
+ res.tzname = None
+
+ # Check for a numbered timezone
+ elif res.hour is not None and l[i] in ('+', '-'):
+ signal = (-1, 1)[l[i] == '+']
+ len_li = len(l[i + 1])
+
+ # TODO: check that l[i + 1] is integer?
+ if len_li == 4:
+ # -0300
+ hour_offset = int(l[i + 1][:2])
+ min_offset = int(l[i + 1][2:])
+ elif i + 2 < len_l and l[i + 2] == ':':
+ # -03:00
+ hour_offset = int(l[i + 1])
+ min_offset = int(l[i + 3]) # TODO: Check that l[i+3] is minute-like?
+ i += 2
+ elif len_li <= 2:
+ # -[0]3
+ hour_offset = int(l[i + 1][:2])
+ min_offset = 0
+ else:
+ raise ValueError(timestr)
+
+ res.tzoffset = signal * (hour_offset * 3600 + min_offset * 60)
+
+ # Look for a timezone name between parenthesis
+ if (i + 5 < len_l and
+ info.jump(l[i + 2]) and l[i + 3] == '(' and
+ l[i + 5] == ')' and
+ 3 <= len(l[i + 4]) and
+ self._could_be_tzname(res.hour, res.tzname,
+ None, l[i + 4])):
+ # -0300 (BRST)
+ res.tzname = l[i + 4]
+ i += 4
+
+ i += 1
+
+ # Check jumps
+ elif not (info.jump(l[i]) or fuzzy):
+ raise ValueError(timestr)
+
+ else:
+ skipped_idxs.append(i)
+ i += 1
+
+ # Process year/month/day
+ year, month, day = ymd.resolve_ymd(yearfirst, dayfirst)
+
+ res.century_specified = ymd.century_specified
+ res.year = year
+ res.month = month
+ res.day = day
+
+ except (IndexError, ValueError):
+ return None, None
+
+ if not info.validate(res):
+ return None, None
+
+ if fuzzy_with_tokens:
+ skipped_tokens = self._recombine_skipped(l, skipped_idxs)
+ return res, tuple(skipped_tokens)
+ else:
+ return res, None
+
+ def _parse_numeric_token(self, tokens, idx, info, ymd, res, fuzzy):
+ # Token is a number
+ value_repr = tokens[idx]
+ try:
+ value = self._to_decimal(value_repr)
+ except Exception as e:
+ six.raise_from(ValueError('Unknown numeric token'), e)
+
+ len_li = len(value_repr)
+
+ len_l = len(tokens)
+
+ if (len(ymd) == 3 and len_li in (2, 4) and
+ res.hour is None and
+ (idx + 1 >= len_l or
+ (tokens[idx + 1] != ':' and
+ info.hms(tokens[idx + 1]) is None))):
+ # 19990101T23[59]
+ s = tokens[idx]
+ res.hour = int(s[:2])
+
+ if len_li == 4:
+ res.minute = int(s[2:])
+
+ elif len_li == 6 or (len_li > 6 and tokens[idx].find('.') == 6):
+ # YYMMDD or HHMMSS[.ss]
+ s = tokens[idx]
+
+ if not ymd and '.' not in tokens[idx]:
+ ymd.append(s[:2])
+ ymd.append(s[2:4])
+ ymd.append(s[4:])
+ else:
+ # 19990101T235959[.59]
+
+ # TODO: Check if res attributes already set.
+ res.hour = int(s[:2])
+ res.minute = int(s[2:4])
+ res.second, res.microsecond = self._parsems(s[4:])
+
+ elif len_li in (8, 12, 14):
+ # YYYYMMDD
+ s = tokens[idx]
+ ymd.append(s[:4], 'Y')
+ ymd.append(s[4:6])
+ ymd.append(s[6:8])
+
+ if len_li > 8:
+ res.hour = int(s[8:10])
+ res.minute = int(s[10:12])
+
+ if len_li > 12:
+ res.second = int(s[12:])
+
+ elif self._find_hms_idx(idx, tokens, info, allow_jump=True) is not None:
+ # HH[ ]h or MM[ ]m or SS[.ss][ ]s
+ hms_idx = self._find_hms_idx(idx, tokens, info, allow_jump=True)
+ (idx, hms) = self._parse_hms(idx, tokens, info, hms_idx)
+ if hms is not None:
+ # TODO: checking that hour/minute/second are not
+ # already set?
+ self._assign_hms(res, value_repr, hms)
+
+ elif idx + 2 < len_l and tokens[idx + 1] == ':':
+ # HH:MM[:SS[.ss]]
+ res.hour = int(value)
+ value = self._to_decimal(tokens[idx + 2]) # TODO: try/except for this?
+ (res.minute, res.second) = self._parse_min_sec(value)
+
+ if idx + 4 < len_l and tokens[idx + 3] == ':':
+ res.second, res.microsecond = self._parsems(tokens[idx + 4])
+
+ idx += 2
+
+ idx += 2
+
+ elif idx + 1 < len_l and tokens[idx + 1] in ('-', '/', '.'):
+ sep = tokens[idx + 1]
+ ymd.append(value_repr)
+
+ if idx + 2 < len_l and not info.jump(tokens[idx + 2]):
+ if tokens[idx + 2].isdigit():
+ # 01-01[-01]
+ ymd.append(tokens[idx + 2])
+ else:
+ # 01-Jan[-01]
+ value = info.month(tokens[idx + 2])
+
+ if value is not None:
+ ymd.append(value, 'M')
+ else:
+ raise ValueError()
+
+ if idx + 3 < len_l and tokens[idx + 3] == sep:
+ # We have three members
+ value = info.month(tokens[idx + 4])
+
+ if value is not None:
+ ymd.append(value, 'M')
+ else:
+ ymd.append(tokens[idx + 4])
+ idx += 2
+
+ idx += 1
+ idx += 1
+
+ elif idx + 1 >= len_l or info.jump(tokens[idx + 1]):
+ if idx + 2 < len_l and info.ampm(tokens[idx + 2]) is not None:
+ # 12 am
+ hour = int(value)
+ res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 2]))
+ idx += 1
+ else:
+ # Year, month or day
+ ymd.append(value)
+ idx += 1
+
+ elif info.ampm(tokens[idx + 1]) is not None and (0 <= value < 24):
+ # 12am
+ hour = int(value)
+ res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 1]))
+ idx += 1
+
+ elif ymd.could_be_day(value):
+ ymd.append(value)
+
+ elif not fuzzy:
+ raise ValueError()
+
+ return idx
+
+ def _find_hms_idx(self, idx, tokens, info, allow_jump):
+ len_l = len(tokens)
+
+ if idx+1 < len_l and info.hms(tokens[idx+1]) is not None:
+ # There is an "h", "m", or "s" label following this token. We take
+ # assign the upcoming label to the current token.
+ # e.g. the "12" in 12h"
+ hms_idx = idx + 1
+
+ elif (allow_jump and idx+2 < len_l and tokens[idx+1] == ' ' and
+ info.hms(tokens[idx+2]) is not None):
+ # There is a space and then an "h", "m", or "s" label.
+ # e.g. the "12" in "12 h"
+ hms_idx = idx + 2
+
+ elif idx > 0 and info.hms(tokens[idx-1]) is not None:
# There is a "h", "m", or "s" preceding this token. Since neither
- # of the previous cases was hit, there is no label following this
- # token, so we use the previous label.
- # e.g. the "04" in "12h04"
- hms_idx = idx-1
-
- elif (1 < idx == len_l-1 and tokens[idx-1] == ' ' and
- info.hms(tokens[idx-2]) is not None):
- # If we are looking at the final token, we allow for a
- # backward-looking check to skip over a space.
- # TODO: Are we sure this is the right condition here?
- hms_idx = idx - 2
-
- else:
- hms_idx = None
-
- return hms_idx
-
- def _assign_hms(self, res, value_repr, hms):
- # See GH issue #427, fixing float rounding
- value = self._to_decimal(value_repr)
-
- if hms == 0:
- # Hour
- res.hour = int(value)
- if value % 1:
- res.minute = int(60*(value % 1))
-
- elif hms == 1:
- (res.minute, res.second) = self._parse_min_sec(value)
-
- elif hms == 2:
- (res.second, res.microsecond) = self._parsems(value_repr)
-
- def _could_be_tzname(self, hour, tzname, tzoffset, token):
- return (hour is not None and
- tzname is None and
- tzoffset is None and
- len(token) <= 5 and
+ # of the previous cases was hit, there is no label following this
+ # token, so we use the previous label.
+ # e.g. the "04" in "12h04"
+ hms_idx = idx-1
+
+ elif (1 < idx == len_l-1 and tokens[idx-1] == ' ' and
+ info.hms(tokens[idx-2]) is not None):
+ # If we are looking at the final token, we allow for a
+ # backward-looking check to skip over a space.
+ # TODO: Are we sure this is the right condition here?
+ hms_idx = idx - 2
+
+ else:
+ hms_idx = None
+
+ return hms_idx
+
+ def _assign_hms(self, res, value_repr, hms):
+ # See GH issue #427, fixing float rounding
+ value = self._to_decimal(value_repr)
+
+ if hms == 0:
+ # Hour
+ res.hour = int(value)
+ if value % 1:
+ res.minute = int(60*(value % 1))
+
+ elif hms == 1:
+ (res.minute, res.second) = self._parse_min_sec(value)
+
+ elif hms == 2:
+ (res.second, res.microsecond) = self._parsems(value_repr)
+
+ def _could_be_tzname(self, hour, tzname, tzoffset, token):
+ return (hour is not None and
+ tzname is None and
+ tzoffset is None and
+ len(token) <= 5 and
(all(x in string.ascii_uppercase for x in token)
or token in self.info.UTCZONE))
-
- def _ampm_valid(self, hour, ampm, fuzzy):
- """
- For fuzzy parsing, 'a' or 'am' (both valid English words)
- may erroneously trigger the AM/PM flag. Deal with that
- here.
- """
- val_is_ampm = True
-
- # If there's already an AM/PM flag, this one isn't one.
- if fuzzy and ampm is not None:
- val_is_ampm = False
-
- # If AM/PM is found and hour is not, raise a ValueError
- if hour is None:
- if fuzzy:
- val_is_ampm = False
- else:
- raise ValueError('No hour specified with AM or PM flag.')
- elif not 0 <= hour <= 12:
- # If AM/PM is found, it's a 12 hour clock, so raise
- # an error for invalid range
- if fuzzy:
- val_is_ampm = False
- else:
- raise ValueError('Invalid hour specified for 12-hour clock.')
-
- return val_is_ampm
-
- def _adjust_ampm(self, hour, ampm):
- if hour < 12 and ampm == 1:
- hour += 12
- elif hour == 12 and ampm == 0:
- hour = 0
- return hour
-
- def _parse_min_sec(self, value):
- # TODO: Every usage of this function sets res.second to the return
- # value. Are there any cases where second will be returned as None and
+
+ def _ampm_valid(self, hour, ampm, fuzzy):
+ """
+ For fuzzy parsing, 'a' or 'am' (both valid English words)
+ may erroneously trigger the AM/PM flag. Deal with that
+ here.
+ """
+ val_is_ampm = True
+
+ # If there's already an AM/PM flag, this one isn't one.
+ if fuzzy and ampm is not None:
+ val_is_ampm = False
+
+ # If AM/PM is found and hour is not, raise a ValueError
+ if hour is None:
+ if fuzzy:
+ val_is_ampm = False
+ else:
+ raise ValueError('No hour specified with AM or PM flag.')
+ elif not 0 <= hour <= 12:
+ # If AM/PM is found, it's a 12 hour clock, so raise
+ # an error for invalid range
+ if fuzzy:
+ val_is_ampm = False
+ else:
+ raise ValueError('Invalid hour specified for 12-hour clock.')
+
+ return val_is_ampm
+
+ def _adjust_ampm(self, hour, ampm):
+ if hour < 12 and ampm == 1:
+ hour += 12
+ elif hour == 12 and ampm == 0:
+ hour = 0
+ return hour
+
+ def _parse_min_sec(self, value):
+ # TODO: Every usage of this function sets res.second to the return
+ # value. Are there any cases where second will be returned as None and
# we *don't* want to set res.second = None?
- minute = int(value)
- second = None
-
- sec_remainder = value % 1
- if sec_remainder:
- second = int(60 * sec_remainder)
- return (minute, second)
-
- def _parse_hms(self, idx, tokens, info, hms_idx):
- # TODO: Is this going to admit a lot of false-positives for when we
- # just happen to have digits and "h", "m" or "s" characters in non-date
- # text? I guess hex hashes won't have that problem, but there's plenty
- # of random junk out there.
- if hms_idx is None:
- hms = None
- new_idx = idx
- elif hms_idx > idx:
- hms = info.hms(tokens[hms_idx])
- new_idx = hms_idx
- else:
- # Looking backwards, increment one.
- hms = info.hms(tokens[hms_idx]) + 1
- new_idx = idx
-
- return (new_idx, hms)
-
+ minute = int(value)
+ second = None
+
+ sec_remainder = value % 1
+ if sec_remainder:
+ second = int(60 * sec_remainder)
+ return (minute, second)
+
+ def _parse_hms(self, idx, tokens, info, hms_idx):
+ # TODO: Is this going to admit a lot of false-positives for when we
+ # just happen to have digits and "h", "m" or "s" characters in non-date
+ # text? I guess hex hashes won't have that problem, but there's plenty
+ # of random junk out there.
+ if hms_idx is None:
+ hms = None
+ new_idx = idx
+ elif hms_idx > idx:
+ hms = info.hms(tokens[hms_idx])
+ new_idx = hms_idx
+ else:
+ # Looking backwards, increment one.
+ hms = info.hms(tokens[hms_idx]) + 1
+ new_idx = idx
+
+ return (new_idx, hms)
+
# ------------------------------------------------------------------
# Handling for individual tokens. These are kept as methods instead
# of functions for the sake of customizability via subclassing.
-
+
def _parsems(self, value):
"""Parse a I[.F] seconds value into (seconds, microseconds)."""
if "." not in value:
@@ -1137,7 +1137,7 @@ class parser(object):
else:
i, f = value.split(".")
return int(i), int(f.ljust(6, "0")[:6])
-
+
def _to_decimal(self, val):
try:
decimal_value = Decimal(val)
@@ -1156,97 +1156,97 @@ class parser(object):
# methods instead of functions for the sake of customizability via
# subclassing.
- def _build_tzinfo(self, tzinfos, tzname, tzoffset):
- if callable(tzinfos):
- tzdata = tzinfos(tzname, tzoffset)
- else:
- tzdata = tzinfos.get(tzname)
- # handle case where tzinfo is paased an options that returns None
- # eg tzinfos = {'BRST' : None}
- if isinstance(tzdata, datetime.tzinfo) or tzdata is None:
- tzinfo = tzdata
- elif isinstance(tzdata, text_type):
- tzinfo = tz.tzstr(tzdata)
- elif isinstance(tzdata, integer_types):
- tzinfo = tz.tzoffset(tzname, tzdata)
+ def _build_tzinfo(self, tzinfos, tzname, tzoffset):
+ if callable(tzinfos):
+ tzdata = tzinfos(tzname, tzoffset)
+ else:
+ tzdata = tzinfos.get(tzname)
+ # handle case where tzinfo is paased an options that returns None
+ # eg tzinfos = {'BRST' : None}
+ if isinstance(tzdata, datetime.tzinfo) or tzdata is None:
+ tzinfo = tzdata
+ elif isinstance(tzdata, text_type):
+ tzinfo = tz.tzstr(tzdata)
+ elif isinstance(tzdata, integer_types):
+ tzinfo = tz.tzoffset(tzname, tzdata)
else:
raise TypeError("Offset must be tzinfo subclass, tz string, "
"or int offset.")
- return tzinfo
-
- def _build_tzaware(self, naive, res, tzinfos):
- if (callable(tzinfos) or (tzinfos and res.tzname in tzinfos)):
- tzinfo = self._build_tzinfo(tzinfos, res.tzname, res.tzoffset)
- aware = naive.replace(tzinfo=tzinfo)
- aware = self._assign_tzname(aware, res.tzname)
-
- elif res.tzname and res.tzname in time.tzname:
- aware = naive.replace(tzinfo=tz.tzlocal())
-
- # Handle ambiguous local datetime
- aware = self._assign_tzname(aware, res.tzname)
-
- # This is mostly relevant for winter GMT zones parsed in the UK
- if (aware.tzname() != res.tzname and
- res.tzname in self.info.UTCZONE):
+ return tzinfo
+
+ def _build_tzaware(self, naive, res, tzinfos):
+ if (callable(tzinfos) or (tzinfos and res.tzname in tzinfos)):
+ tzinfo = self._build_tzinfo(tzinfos, res.tzname, res.tzoffset)
+ aware = naive.replace(tzinfo=tzinfo)
+ aware = self._assign_tzname(aware, res.tzname)
+
+ elif res.tzname and res.tzname in time.tzname:
+ aware = naive.replace(tzinfo=tz.tzlocal())
+
+ # Handle ambiguous local datetime
+ aware = self._assign_tzname(aware, res.tzname)
+
+ # This is mostly relevant for winter GMT zones parsed in the UK
+ if (aware.tzname() != res.tzname and
+ res.tzname in self.info.UTCZONE):
aware = aware.replace(tzinfo=tz.UTC)
-
- elif res.tzoffset == 0:
+
+ elif res.tzoffset == 0:
aware = naive.replace(tzinfo=tz.UTC)
-
- elif res.tzoffset:
- aware = naive.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
-
- elif not res.tzname and not res.tzoffset:
- # i.e. no timezone information was found.
- aware = naive
-
- elif res.tzname:
- # tz-like string was parsed but we don't know what to do
- # with it
- warnings.warn("tzname {tzname} identified but not understood. "
- "Pass `tzinfos` argument in order to correctly "
- "return a timezone-aware datetime. In a future "
- "version, this will raise an "
- "exception.".format(tzname=res.tzname),
- category=UnknownTimezoneWarning)
- aware = naive
-
- return aware
-
- def _build_naive(self, res, default):
- repl = {}
- for attr in ("year", "month", "day", "hour",
- "minute", "second", "microsecond"):
- value = getattr(res, attr)
- if value is not None:
- repl[attr] = value
-
- if 'day' not in repl:
- # If the default day exceeds the last day of the month, fall back
- # to the end of the month.
- cyear = default.year if res.year is None else res.year
- cmonth = default.month if res.month is None else res.month
- cday = default.day if res.day is None else res.day
-
- if cday > monthrange(cyear, cmonth)[1]:
- repl['day'] = monthrange(cyear, cmonth)[1]
-
- naive = default.replace(**repl)
-
- if res.weekday is not None and not res.day:
- naive = naive + relativedelta.relativedelta(weekday=res.weekday)
-
- return naive
-
- def _assign_tzname(self, dt, tzname):
- if dt.tzname() != tzname:
- new_dt = tz.enfold(dt, fold=1)
- if new_dt.tzname() == tzname:
- return new_dt
-
- return dt
-
+
+ elif res.tzoffset:
+ aware = naive.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
+
+ elif not res.tzname and not res.tzoffset:
+ # i.e. no timezone information was found.
+ aware = naive
+
+ elif res.tzname:
+ # tz-like string was parsed but we don't know what to do
+ # with it
+ warnings.warn("tzname {tzname} identified but not understood. "
+ "Pass `tzinfos` argument in order to correctly "
+ "return a timezone-aware datetime. In a future "
+ "version, this will raise an "
+ "exception.".format(tzname=res.tzname),
+ category=UnknownTimezoneWarning)
+ aware = naive
+
+ return aware
+
+ def _build_naive(self, res, default):
+ repl = {}
+ for attr in ("year", "month", "day", "hour",
+ "minute", "second", "microsecond"):
+ value = getattr(res, attr)
+ if value is not None:
+ repl[attr] = value
+
+ if 'day' not in repl:
+ # If the default day exceeds the last day of the month, fall back
+ # to the end of the month.
+ cyear = default.year if res.year is None else res.year
+ cmonth = default.month if res.month is None else res.month
+ cday = default.day if res.day is None else res.day
+
+ if cday > monthrange(cyear, cmonth)[1]:
+ repl['day'] = monthrange(cyear, cmonth)[1]
+
+ naive = default.replace(**repl)
+
+ if res.weekday is not None and not res.day:
+ naive = naive + relativedelta.relativedelta(weekday=res.weekday)
+
+ return naive
+
+ def _assign_tzname(self, dt, tzname):
+ if dt.tzname() != tzname:
+ new_dt = tz.enfold(dt, fold=1)
+ if new_dt.tzname() == tzname:
+ return new_dt
+
+ return dt
+
def _recombine_skipped(self, tokens, skipped_idxs):
"""
>>> tokens = ["foo", " ", "bar", " ", "19June2000", "baz"]
@@ -1260,331 +1260,331 @@ class parser(object):
skipped_tokens[-1] = skipped_tokens[-1] + tokens[idx]
else:
skipped_tokens.append(tokens[idx])
-
+
return skipped_tokens
-
-
-DEFAULTPARSER = parser()
-
-
-def parse(timestr, parserinfo=None, **kwargs):
- """
-
- Parse a string in one of the supported formats, using the
- ``parserinfo`` parameters.
-
- :param timestr:
- A string containing a date/time stamp.
-
- :param parserinfo:
- A :class:`parserinfo` object containing parameters for the parser.
- If ``None``, the default arguments to the :class:`parserinfo`
- constructor are used.
-
- The ``**kwargs`` parameter takes the following keyword arguments:
-
- :param default:
- The default datetime object, if this is a datetime object and not
- ``None``, elements specified in ``timestr`` replace elements in the
- default object.
-
- :param ignoretz:
- If set ``True``, time zones in parsed strings are ignored and a naive
- :class:`datetime` object is returned.
-
- :param tzinfos:
- Additional time zone names / aliases which may be present in the
- string. This argument maps time zone names (and optionally offsets
- from those time zones) to time zones. This parameter can be a
- dictionary with timezone aliases mapping time zone names to time
- zones or a function taking two parameters (``tzname`` and
- ``tzoffset``) and returning a time zone.
-
- The timezones to which the names are mapped can be an integer
- offset from UTC in seconds or a :class:`tzinfo` object.
-
- .. doctest::
- :options: +NORMALIZE_WHITESPACE
-
- >>> from dateutil.parser import parse
- >>> from dateutil.tz import gettz
- >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
- >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
- >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21,
- tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
-
- This parameter is ignored if ``ignoretz`` is set.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM and
- YMD. If set to ``None``, this value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken to
- be the year, otherwise the last number is taken to be the year. If
- this is set to ``None``, the value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param fuzzy:
- Whether to allow fuzzy parsing, allowing for string like "Today is
- January 1, 2047 at 8:21:00AM".
-
- :param fuzzy_with_tokens:
- If ``True``, ``fuzzy`` is automatically set to True, and the parser
- will return a tuple where the first element is the parsed
- :class:`datetime.datetime` datetimestamp and the second element is
- a tuple containing the portions of the string which were ignored:
-
- .. doctest::
-
- >>> from dateutil.parser import parse
- >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
- (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
-
- :return:
- Returns a :class:`datetime.datetime` object or, if the
- ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
- first element being a :class:`datetime.datetime` object, the second
- a tuple containing the fuzzy tokens.
-
+
+
+DEFAULTPARSER = parser()
+
+
+def parse(timestr, parserinfo=None, **kwargs):
+ """
+
+ Parse a string in one of the supported formats, using the
+ ``parserinfo`` parameters.
+
+ :param timestr:
+ A string containing a date/time stamp.
+
+ :param parserinfo:
+ A :class:`parserinfo` object containing parameters for the parser.
+ If ``None``, the default arguments to the :class:`parserinfo`
+ constructor are used.
+
+ The ``**kwargs`` parameter takes the following keyword arguments:
+
+ :param default:
+ The default datetime object, if this is a datetime object and not
+ ``None``, elements specified in ``timestr`` replace elements in the
+ default object.
+
+ :param ignoretz:
+ If set ``True``, time zones in parsed strings are ignored and a naive
+ :class:`datetime` object is returned.
+
+ :param tzinfos:
+ Additional time zone names / aliases which may be present in the
+ string. This argument maps time zone names (and optionally offsets
+ from those time zones) to time zones. This parameter can be a
+ dictionary with timezone aliases mapping time zone names to time
+ zones or a function taking two parameters (``tzname`` and
+ ``tzoffset``) and returning a time zone.
+
+ The timezones to which the names are mapped can be an integer
+ offset from UTC in seconds or a :class:`tzinfo` object.
+
+ .. doctest::
+ :options: +NORMALIZE_WHITESPACE
+
+ >>> from dateutil.parser import parse
+ >>> from dateutil.tz import gettz
+ >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
+ >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
+ datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
+ >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
+ datetime.datetime(2012, 1, 19, 17, 21,
+ tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
+
+ This parameter is ignored if ``ignoretz`` is set.
+
+ :param dayfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM and
+ YMD. If set to ``None``, this value is retrieved from the current
+ :class:`parserinfo` object (which itself defaults to ``False``).
+
+ :param yearfirst:
+ Whether to interpret the first value in an ambiguous 3-integer date
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken to
+ be the year, otherwise the last number is taken to be the year. If
+ this is set to ``None``, the value is retrieved from the current
+ :class:`parserinfo` object (which itself defaults to ``False``).
+
+ :param fuzzy:
+ Whether to allow fuzzy parsing, allowing for string like "Today is
+ January 1, 2047 at 8:21:00AM".
+
+ :param fuzzy_with_tokens:
+ If ``True``, ``fuzzy`` is automatically set to True, and the parser
+ will return a tuple where the first element is the parsed
+ :class:`datetime.datetime` datetimestamp and the second element is
+ a tuple containing the portions of the string which were ignored:
+
+ .. doctest::
+
+ >>> from dateutil.parser import parse
+ >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
+ (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
+
+ :return:
+ Returns a :class:`datetime.datetime` object or, if the
+ ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
+ first element being a :class:`datetime.datetime` object, the second
+ a tuple containing the fuzzy tokens.
+
:raises ParserError:
Raised for invalid or unknown string formats, if the provided
:class:`tzinfo` is not in a valid format, or if an invalid date would
be created.
-
- :raises OverflowError:
- Raised if the parsed date exceeds the largest valid C integer on
- your system.
- """
- if parserinfo:
- return parser(parserinfo).parse(timestr, **kwargs)
- else:
- return DEFAULTPARSER.parse(timestr, **kwargs)
-
-
-class _tzparser(object):
-
- class _result(_resultbase):
-
- __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset",
- "start", "end"]
-
- class _attr(_resultbase):
- __slots__ = ["month", "week", "weekday",
- "yday", "jyday", "day", "time"]
-
- def __repr__(self):
- return self._repr("")
-
- def __init__(self):
- _resultbase.__init__(self)
- self.start = self._attr()
- self.end = self._attr()
-
- def parse(self, tzstr):
- res = self._result()
- l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x]
- used_idxs = list()
- try:
-
- len_l = len(l)
-
- i = 0
- while i < len_l:
- # BRST+3[BRDT[+2]]
- j = i
- while j < len_l and not [x for x in l[j]
- if x in "0123456789:,-+"]:
- j += 1
- if j != i:
- if not res.stdabbr:
- offattr = "stdoffset"
- res.stdabbr = "".join(l[i:j])
- else:
- offattr = "dstoffset"
- res.dstabbr = "".join(l[i:j])
-
- for ii in range(j):
- used_idxs.append(ii)
- i = j
- if (i < len_l and (l[i] in ('+', '-') or l[i][0] in
- "0123456789")):
- if l[i] in ('+', '-'):
- # Yes, that's right. See the TZ variable
- # documentation.
- signal = (1, -1)[l[i] == '+']
- used_idxs.append(i)
- i += 1
- else:
- signal = -1
- len_li = len(l[i])
- if len_li == 4:
- # -0300
- setattr(res, offattr, (int(l[i][:2]) * 3600 +
- int(l[i][2:]) * 60) * signal)
- elif i + 1 < len_l and l[i + 1] == ':':
- # -03:00
- setattr(res, offattr,
- (int(l[i]) * 3600 +
- int(l[i + 2]) * 60) * signal)
- used_idxs.append(i)
- i += 2
- elif len_li <= 2:
- # -[0]3
- setattr(res, offattr,
- int(l[i][:2]) * 3600 * signal)
- else:
- return None
- used_idxs.append(i)
- i += 1
- if res.dstabbr:
- break
- else:
- break
-
-
- if i < len_l:
- for j in range(i, len_l):
- if l[j] == ';':
- l[j] = ','
-
- assert l[i] == ','
-
- i += 1
-
- if i >= len_l:
- pass
- elif (8 <= l.count(',') <= 9 and
- not [y for x in l[i:] if x != ','
- for y in x if y not in "0123456789+-"]):
- # GMT0BST,3,0,30,3600,10,0,26,7200[,3600]
- for x in (res.start, res.end):
- x.month = int(l[i])
- used_idxs.append(i)
- i += 2
- if l[i] == '-':
- value = int(l[i + 1]) * -1
- used_idxs.append(i)
- i += 1
- else:
- value = int(l[i])
- used_idxs.append(i)
- i += 2
- if value:
- x.week = value
- x.weekday = (int(l[i]) - 1) % 7
- else:
- x.day = int(l[i])
- used_idxs.append(i)
- i += 2
- x.time = int(l[i])
- used_idxs.append(i)
- i += 2
- if i < len_l:
- if l[i] in ('-', '+'):
- signal = (-1, 1)[l[i] == "+"]
- used_idxs.append(i)
- i += 1
- else:
- signal = 1
- used_idxs.append(i)
- res.dstoffset = (res.stdoffset + int(l[i]) * signal)
-
- # This was a made-up format that is not in normal use
- warn(('Parsed time zone "%s"' % tzstr) +
- 'is in a non-standard dateutil-specific format, which ' +
- 'is now deprecated; support for parsing this format ' +
- 'will be removed in future versions. It is recommended ' +
- 'that you switch to a standard format like the GNU ' +
- 'TZ variable format.', tz.DeprecatedTzFormatWarning)
- elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
- not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
- '.', '-', ':')
- for y in x if y not in "0123456789"]):
- for x in (res.start, res.end):
- if l[i] == 'J':
- # non-leap year day (1 based)
- used_idxs.append(i)
- i += 1
- x.jyday = int(l[i])
- elif l[i] == 'M':
- # month[-.]week[-.]weekday
- used_idxs.append(i)
- i += 1
- x.month = int(l[i])
- used_idxs.append(i)
- i += 1
- assert l[i] in ('-', '.')
- used_idxs.append(i)
- i += 1
- x.week = int(l[i])
- if x.week == 5:
- x.week = -1
- used_idxs.append(i)
- i += 1
- assert l[i] in ('-', '.')
- used_idxs.append(i)
- i += 1
- x.weekday = (int(l[i]) - 1) % 7
- else:
- # year day (zero based)
- x.yday = int(l[i]) + 1
-
- used_idxs.append(i)
- i += 1
-
- if i < len_l and l[i] == '/':
- used_idxs.append(i)
- i += 1
- # start time
- len_li = len(l[i])
- if len_li == 4:
- # -0300
- x.time = (int(l[i][:2]) * 3600 +
- int(l[i][2:]) * 60)
- elif i + 1 < len_l and l[i + 1] == ':':
- # -03:00
- x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60
- used_idxs.append(i)
- i += 2
- if i + 1 < len_l and l[i + 1] == ':':
- used_idxs.append(i)
- i += 2
- x.time += int(l[i])
- elif len_li <= 2:
- # -[0]3
- x.time = (int(l[i][:2]) * 3600)
- else:
- return None
- used_idxs.append(i)
- i += 1
-
- assert i == len_l or l[i] == ','
-
- i += 1
-
- assert i >= len_l
-
- except (IndexError, ValueError, AssertionError):
- return None
-
- unused_idxs = set(range(len_l)).difference(used_idxs)
- res.any_unused_tokens = not {l[n] for n in unused_idxs}.issubset({",",":"})
- return res
-
-
-DEFAULTTZPARSER = _tzparser()
-
-
-def _parsetz(tzstr):
- return DEFAULTTZPARSER.parse(tzstr)
-
+
+ :raises OverflowError:
+ Raised if the parsed date exceeds the largest valid C integer on
+ your system.
+ """
+ if parserinfo:
+ return parser(parserinfo).parse(timestr, **kwargs)
+ else:
+ return DEFAULTPARSER.parse(timestr, **kwargs)
+
+
+class _tzparser(object):
+
+ class _result(_resultbase):
+
+ __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset",
+ "start", "end"]
+
+ class _attr(_resultbase):
+ __slots__ = ["month", "week", "weekday",
+ "yday", "jyday", "day", "time"]
+
+ def __repr__(self):
+ return self._repr("")
+
+ def __init__(self):
+ _resultbase.__init__(self)
+ self.start = self._attr()
+ self.end = self._attr()
+
+ def parse(self, tzstr):
+ res = self._result()
+ l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x]
+ used_idxs = list()
+ try:
+
+ len_l = len(l)
+
+ i = 0
+ while i < len_l:
+ # BRST+3[BRDT[+2]]
+ j = i
+ while j < len_l and not [x for x in l[j]
+ if x in "0123456789:,-+"]:
+ j += 1
+ if j != i:
+ if not res.stdabbr:
+ offattr = "stdoffset"
+ res.stdabbr = "".join(l[i:j])
+ else:
+ offattr = "dstoffset"
+ res.dstabbr = "".join(l[i:j])
+
+ for ii in range(j):
+ used_idxs.append(ii)
+ i = j
+ if (i < len_l and (l[i] in ('+', '-') or l[i][0] in
+ "0123456789")):
+ if l[i] in ('+', '-'):
+ # Yes, that's right. See the TZ variable
+ # documentation.
+ signal = (1, -1)[l[i] == '+']
+ used_idxs.append(i)
+ i += 1
+ else:
+ signal = -1
+ len_li = len(l[i])
+ if len_li == 4:
+ # -0300
+ setattr(res, offattr, (int(l[i][:2]) * 3600 +
+ int(l[i][2:]) * 60) * signal)
+ elif i + 1 < len_l and l[i + 1] == ':':
+ # -03:00
+ setattr(res, offattr,
+ (int(l[i]) * 3600 +
+ int(l[i + 2]) * 60) * signal)
+ used_idxs.append(i)
+ i += 2
+ elif len_li <= 2:
+ # -[0]3
+ setattr(res, offattr,
+ int(l[i][:2]) * 3600 * signal)
+ else:
+ return None
+ used_idxs.append(i)
+ i += 1
+ if res.dstabbr:
+ break
+ else:
+ break
+
+
+ if i < len_l:
+ for j in range(i, len_l):
+ if l[j] == ';':
+ l[j] = ','
+
+ assert l[i] == ','
+
+ i += 1
+
+ if i >= len_l:
+ pass
+ elif (8 <= l.count(',') <= 9 and
+ not [y for x in l[i:] if x != ','
+ for y in x if y not in "0123456789+-"]):
+ # GMT0BST,3,0,30,3600,10,0,26,7200[,3600]
+ for x in (res.start, res.end):
+ x.month = int(l[i])
+ used_idxs.append(i)
+ i += 2
+ if l[i] == '-':
+ value = int(l[i + 1]) * -1
+ used_idxs.append(i)
+ i += 1
+ else:
+ value = int(l[i])
+ used_idxs.append(i)
+ i += 2
+ if value:
+ x.week = value
+ x.weekday = (int(l[i]) - 1) % 7
+ else:
+ x.day = int(l[i])
+ used_idxs.append(i)
+ i += 2
+ x.time = int(l[i])
+ used_idxs.append(i)
+ i += 2
+ if i < len_l:
+ if l[i] in ('-', '+'):
+ signal = (-1, 1)[l[i] == "+"]
+ used_idxs.append(i)
+ i += 1
+ else:
+ signal = 1
+ used_idxs.append(i)
+ res.dstoffset = (res.stdoffset + int(l[i]) * signal)
+
+ # This was a made-up format that is not in normal use
+ warn(('Parsed time zone "%s"' % tzstr) +
+ 'is in a non-standard dateutil-specific format, which ' +
+ 'is now deprecated; support for parsing this format ' +
+ 'will be removed in future versions. It is recommended ' +
+ 'that you switch to a standard format like the GNU ' +
+ 'TZ variable format.', tz.DeprecatedTzFormatWarning)
+ elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
+ not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
+ '.', '-', ':')
+ for y in x if y not in "0123456789"]):
+ for x in (res.start, res.end):
+ if l[i] == 'J':
+ # non-leap year day (1 based)
+ used_idxs.append(i)
+ i += 1
+ x.jyday = int(l[i])
+ elif l[i] == 'M':
+ # month[-.]week[-.]weekday
+ used_idxs.append(i)
+ i += 1
+ x.month = int(l[i])
+ used_idxs.append(i)
+ i += 1
+ assert l[i] in ('-', '.')
+ used_idxs.append(i)
+ i += 1
+ x.week = int(l[i])
+ if x.week == 5:
+ x.week = -1
+ used_idxs.append(i)
+ i += 1
+ assert l[i] in ('-', '.')
+ used_idxs.append(i)
+ i += 1
+ x.weekday = (int(l[i]) - 1) % 7
+ else:
+ # year day (zero based)
+ x.yday = int(l[i]) + 1
+
+ used_idxs.append(i)
+ i += 1
+
+ if i < len_l and l[i] == '/':
+ used_idxs.append(i)
+ i += 1
+ # start time
+ len_li = len(l[i])
+ if len_li == 4:
+ # -0300
+ x.time = (int(l[i][:2]) * 3600 +
+ int(l[i][2:]) * 60)
+ elif i + 1 < len_l and l[i + 1] == ':':
+ # -03:00
+ x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60
+ used_idxs.append(i)
+ i += 2
+ if i + 1 < len_l and l[i + 1] == ':':
+ used_idxs.append(i)
+ i += 2
+ x.time += int(l[i])
+ elif len_li <= 2:
+ # -[0]3
+ x.time = (int(l[i][:2]) * 3600)
+ else:
+ return None
+ used_idxs.append(i)
+ i += 1
+
+ assert i == len_l or l[i] == ','
+
+ i += 1
+
+ assert i >= len_l
+
+ except (IndexError, ValueError, AssertionError):
+ return None
+
+ unused_idxs = set(range(len_l)).difference(used_idxs)
+ res.any_unused_tokens = not {l[n] for n in unused_idxs}.issubset({",",":"})
+ return res
+
+
+DEFAULTTZPARSER = _tzparser()
+
+
+def _parsetz(tzstr):
+ return DEFAULTTZPARSER.parse(tzstr)
+
class ParserError(ValueError):
"""Exception subclass used for any failure to parse a datetime string.
@@ -1605,9 +1605,9 @@ class ParserError(ValueError):
return "%s(%s)" % (self.__class__.__name__, args)
-class UnknownTimezoneWarning(RuntimeWarning):
+class UnknownTimezoneWarning(RuntimeWarning):
"""Raised when the parser finds a timezone it cannot parse into a tzinfo.
.. versionadded:: 2.7.0
"""
-# vim:ts=4:sw=4:et
+# vim:ts=4:sw=4:et
diff --git a/contrib/python/dateutil/dateutil/parser/isoparser.py b/contrib/python/dateutil/dateutil/parser/isoparser.py
index f01a196757..5d7bee3800 100644
--- a/contrib/python/dateutil/dateutil/parser/isoparser.py
+++ b/contrib/python/dateutil/dateutil/parser/isoparser.py
@@ -1,352 +1,352 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers a parser for ISO-8601 strings
-
-It is intended to support all valid date, time and datetime formats per the
-ISO-8601 specification.
-
-..versionadded:: 2.7.0
-"""
-from datetime import datetime, timedelta, time, date
-import calendar
-from dateutil import tz
-
-from functools import wraps
-
-import re
-import six
-
-__all__ = ["isoparse", "isoparser"]
-
-
-def _takes_ascii(f):
- @wraps(f)
- def func(self, str_in, *args, **kwargs):
- # If it's a stream, read the whole thing
- str_in = getattr(str_in, 'read', lambda: str_in)()
-
- # If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII
- if isinstance(str_in, six.text_type):
- # ASCII is the same in UTF-8
- try:
- str_in = str_in.encode('ascii')
- except UnicodeEncodeError as e:
- msg = 'ISO-8601 strings should contain only ASCII characters'
- six.raise_from(ValueError(msg), e)
-
- return f(self, str_in, *args, **kwargs)
-
- return func
-
-
-class isoparser(object):
- def __init__(self, sep=None):
- """
- :param sep:
- A single character that separates date and time portions. If
- ``None``, the parser will accept any single character.
- For strict ISO-8601 adherence, pass ``'T'``.
- """
- if sep is not None:
- if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'):
- raise ValueError('Separator must be a single, non-numeric ' +
- 'ASCII character')
-
- sep = sep.encode('ascii')
-
- self._sep = sep
-
- @_takes_ascii
- def isoparse(self, dt_str):
- """
- Parse an ISO-8601 datetime string into a :class:`datetime.datetime`.
-
- An ISO-8601 datetime string consists of a date portion, followed
- optionally by a time portion - the date and time portions are separated
- by a single character separator, which is ``T`` in the official
- standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be
- combined with a time portion.
-
- Supported date formats are:
-
- Common:
-
- - ``YYYY``
- - ``YYYY-MM`` or ``YYYYMM``
- - ``YYYY-MM-DD`` or ``YYYYMMDD``
-
- Uncommon:
-
- - ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0)
- - ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day
-
- The ISO week and day numbering follows the same logic as
- :func:`datetime.date.isocalendar`.
-
- Supported time formats are:
-
- - ``hh``
- - ``hh:mm`` or ``hhmm``
- - ``hh:mm:ss`` or ``hhmmss``
+# -*- coding: utf-8 -*-
+"""
+This module offers a parser for ISO-8601 strings
+
+It is intended to support all valid date, time and datetime formats per the
+ISO-8601 specification.
+
+..versionadded:: 2.7.0
+"""
+from datetime import datetime, timedelta, time, date
+import calendar
+from dateutil import tz
+
+from functools import wraps
+
+import re
+import six
+
+__all__ = ["isoparse", "isoparser"]
+
+
+def _takes_ascii(f):
+ @wraps(f)
+ def func(self, str_in, *args, **kwargs):
+ # If it's a stream, read the whole thing
+ str_in = getattr(str_in, 'read', lambda: str_in)()
+
+ # If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII
+ if isinstance(str_in, six.text_type):
+ # ASCII is the same in UTF-8
+ try:
+ str_in = str_in.encode('ascii')
+ except UnicodeEncodeError as e:
+ msg = 'ISO-8601 strings should contain only ASCII characters'
+ six.raise_from(ValueError(msg), e)
+
+ return f(self, str_in, *args, **kwargs)
+
+ return func
+
+
+class isoparser(object):
+ def __init__(self, sep=None):
+ """
+ :param sep:
+ A single character that separates date and time portions. If
+ ``None``, the parser will accept any single character.
+ For strict ISO-8601 adherence, pass ``'T'``.
+ """
+ if sep is not None:
+ if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'):
+ raise ValueError('Separator must be a single, non-numeric ' +
+ 'ASCII character')
+
+ sep = sep.encode('ascii')
+
+ self._sep = sep
+
+ @_takes_ascii
+ def isoparse(self, dt_str):
+ """
+ Parse an ISO-8601 datetime string into a :class:`datetime.datetime`.
+
+ An ISO-8601 datetime string consists of a date portion, followed
+ optionally by a time portion - the date and time portions are separated
+ by a single character separator, which is ``T`` in the official
+ standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be
+ combined with a time portion.
+
+ Supported date formats are:
+
+ Common:
+
+ - ``YYYY``
+ - ``YYYY-MM`` or ``YYYYMM``
+ - ``YYYY-MM-DD`` or ``YYYYMMDD``
+
+ Uncommon:
+
+ - ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0)
+ - ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day
+
+ The ISO week and day numbering follows the same logic as
+ :func:`datetime.date.isocalendar`.
+
+ Supported time formats are:
+
+ - ``hh``
+ - ``hh:mm`` or ``hhmm``
+ - ``hh:mm:ss`` or ``hhmmss``
- ``hh:mm:ss.ssssss`` (Up to 6 sub-second digits)
-
- Midnight is a special case for `hh`, as the standard supports both
+
+ Midnight is a special case for `hh`, as the standard supports both
00:00 and 24:00 as a representation. The decimal separator can be
either a dot or a comma.
-
-
- .. caution::
-
- Support for fractional components other than seconds is part of the
- ISO-8601 standard, but is not currently implemented in this parser.
-
- Supported time zone offset formats are:
-
- - `Z` (UTC)
- - `±HH:MM`
- - `±HHMM`
- - `±HH`
-
- Offsets will be represented as :class:`dateutil.tz.tzoffset` objects,
- with the exception of UTC, which will be represented as
- :class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such
- as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`.
-
- :param dt_str:
- A string or stream containing only an ISO-8601 datetime string
-
- :return:
- Returns a :class:`datetime.datetime` representing the string.
- Unspecified components default to their lowest value.
-
- .. warning::
-
- As of version 2.7.0, the strictness of the parser should not be
- considered a stable part of the contract. Any valid ISO-8601 string
- that parses correctly with the default settings will continue to
- parse correctly in future versions, but invalid strings that
- currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not
- guaranteed to continue failing in future versions if they encode
- a valid date.
-
- .. versionadded:: 2.7.0
- """
- components, pos = self._parse_isodate(dt_str)
-
- if len(dt_str) > pos:
- if self._sep is None or dt_str[pos:pos + 1] == self._sep:
- components += self._parse_isotime(dt_str[pos + 1:])
- else:
- raise ValueError('String contains unknown ISO components')
-
+
+
+ .. caution::
+
+ Support for fractional components other than seconds is part of the
+ ISO-8601 standard, but is not currently implemented in this parser.
+
+ Supported time zone offset formats are:
+
+ - `Z` (UTC)
+ - `±HH:MM`
+ - `±HHMM`
+ - `±HH`
+
+ Offsets will be represented as :class:`dateutil.tz.tzoffset` objects,
+ with the exception of UTC, which will be represented as
+ :class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such
+ as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`.
+
+ :param dt_str:
+ A string or stream containing only an ISO-8601 datetime string
+
+ :return:
+ Returns a :class:`datetime.datetime` representing the string.
+ Unspecified components default to their lowest value.
+
+ .. warning::
+
+ As of version 2.7.0, the strictness of the parser should not be
+ considered a stable part of the contract. Any valid ISO-8601 string
+ that parses correctly with the default settings will continue to
+ parse correctly in future versions, but invalid strings that
+ currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not
+ guaranteed to continue failing in future versions if they encode
+ a valid date.
+
+ .. versionadded:: 2.7.0
+ """
+ components, pos = self._parse_isodate(dt_str)
+
+ if len(dt_str) > pos:
+ if self._sep is None or dt_str[pos:pos + 1] == self._sep:
+ components += self._parse_isotime(dt_str[pos + 1:])
+ else:
+ raise ValueError('String contains unknown ISO components')
+
if len(components) > 3 and components[3] == 24:
components[3] = 0
return datetime(*components) + timedelta(days=1)
- return datetime(*components)
-
- @_takes_ascii
- def parse_isodate(self, datestr):
- """
- Parse the date portion of an ISO string.
-
- :param datestr:
- The string portion of an ISO string, without a separator
-
- :return:
- Returns a :class:`datetime.date` object
- """
- components, pos = self._parse_isodate(datestr)
- if pos < len(datestr):
- raise ValueError('String contains unknown ISO ' +
+ return datetime(*components)
+
+ @_takes_ascii
+ def parse_isodate(self, datestr):
+ """
+ Parse the date portion of an ISO string.
+
+ :param datestr:
+ The string portion of an ISO string, without a separator
+
+ :return:
+ Returns a :class:`datetime.date` object
+ """
+ components, pos = self._parse_isodate(datestr)
+ if pos < len(datestr):
+ raise ValueError('String contains unknown ISO ' +
'components: {!r}'.format(datestr.decode('ascii')))
- return date(*components)
-
- @_takes_ascii
- def parse_isotime(self, timestr):
- """
- Parse the time portion of an ISO string.
-
- :param timestr:
- The time portion of an ISO string, without a separator
-
- :return:
- Returns a :class:`datetime.time` object
- """
+ return date(*components)
+
+ @_takes_ascii
+ def parse_isotime(self, timestr):
+ """
+ Parse the time portion of an ISO string.
+
+ :param timestr:
+ The time portion of an ISO string, without a separator
+
+ :return:
+ Returns a :class:`datetime.time` object
+ """
components = self._parse_isotime(timestr)
if components[0] == 24:
components[0] = 0
return time(*components)
-
- @_takes_ascii
- def parse_tzstr(self, tzstr, zero_as_utc=True):
- """
- Parse a valid ISO time zone string.
-
- See :func:`isoparser.isoparse` for details on supported formats.
-
- :param tzstr:
- A string representing an ISO time zone offset
-
- :param zero_as_utc:
- Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones
-
- :return:
- Returns :class:`dateutil.tz.tzoffset` for offsets and
- :class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is
- specified) offsets equivalent to UTC.
- """
- return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
-
- # Constants
- _DATE_SEP = b'-'
- _TIME_SEP = b':'
+
+ @_takes_ascii
+ def parse_tzstr(self, tzstr, zero_as_utc=True):
+ """
+ Parse a valid ISO time zone string.
+
+ See :func:`isoparser.isoparse` for details on supported formats.
+
+ :param tzstr:
+ A string representing an ISO time zone offset
+
+ :param zero_as_utc:
+ Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones
+
+ :return:
+ Returns :class:`dateutil.tz.tzoffset` for offsets and
+ :class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is
+ specified) offsets equivalent to UTC.
+ """
+ return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
+
+ # Constants
+ _DATE_SEP = b'-'
+ _TIME_SEP = b':'
_FRACTION_REGEX = re.compile(b'[\\.,]([0-9]+)')
-
- def _parse_isodate(self, dt_str):
- try:
- return self._parse_isodate_common(dt_str)
- except ValueError:
- return self._parse_isodate_uncommon(dt_str)
-
- def _parse_isodate_common(self, dt_str):
- len_str = len(dt_str)
- components = [1, 1, 1]
-
- if len_str < 4:
- raise ValueError('ISO string too short')
-
- # Year
- components[0] = int(dt_str[0:4])
- pos = 4
- if pos >= len_str:
- return components, pos
-
- has_sep = dt_str[pos:pos + 1] == self._DATE_SEP
- if has_sep:
- pos += 1
-
- # Month
- if len_str - pos < 2:
- raise ValueError('Invalid common month')
-
- components[1] = int(dt_str[pos:pos + 2])
- pos += 2
-
- if pos >= len_str:
- if has_sep:
- return components, pos
- else:
- raise ValueError('Invalid ISO format')
-
- if has_sep:
- if dt_str[pos:pos + 1] != self._DATE_SEP:
- raise ValueError('Invalid separator in ISO string')
- pos += 1
-
- # Day
- if len_str - pos < 2:
- raise ValueError('Invalid common day')
- components[2] = int(dt_str[pos:pos + 2])
- return components, pos + 2
-
- def _parse_isodate_uncommon(self, dt_str):
- if len(dt_str) < 4:
- raise ValueError('ISO string too short')
-
- # All ISO formats start with the year
- year = int(dt_str[0:4])
-
- has_sep = dt_str[4:5] == self._DATE_SEP
-
- pos = 4 + has_sep # Skip '-' if it's there
- if dt_str[pos:pos + 1] == b'W':
- # YYYY-?Www-?D?
- pos += 1
- weekno = int(dt_str[pos:pos + 2])
- pos += 2
-
- dayno = 1
- if len(dt_str) > pos:
- if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep:
- raise ValueError('Inconsistent use of dash separator')
-
- pos += has_sep
-
- dayno = int(dt_str[pos:pos + 1])
- pos += 1
-
- base_date = self._calculate_weekdate(year, weekno, dayno)
- else:
- # YYYYDDD or YYYY-DDD
- if len(dt_str) - pos < 3:
- raise ValueError('Invalid ordinal day')
-
- ordinal_day = int(dt_str[pos:pos + 3])
- pos += 3
-
- if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)):
- raise ValueError('Invalid ordinal day' +
- ' {} for year {}'.format(ordinal_day, year))
-
- base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1)
-
- components = [base_date.year, base_date.month, base_date.day]
- return components, pos
-
- def _calculate_weekdate(self, year, week, day):
- """
- Calculate the day of corresponding to the ISO year-week-day calendar.
-
- This function is effectively the inverse of
- :func:`datetime.date.isocalendar`.
-
- :param year:
- The year in the ISO calendar
-
- :param week:
- The week in the ISO calendar - range is [1, 53]
-
- :param day:
- The day in the ISO calendar - range is [1 (MON), 7 (SUN)]
-
- :return:
- Returns a :class:`datetime.date`
- """
- if not 0 < week < 54:
- raise ValueError('Invalid week: {}'.format(week))
-
- if not 0 < day < 8: # Range is 1-7
- raise ValueError('Invalid weekday: {}'.format(day))
-
- # Get week 1 for the specific year:
- jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it
- week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1)
-
- # Now add the specific number of weeks and days to get what we want
- week_offset = (week - 1) * 7 + (day - 1)
- return week_1 + timedelta(days=week_offset)
-
- def _parse_isotime(self, timestr):
- len_str = len(timestr)
- components = [0, 0, 0, 0, None]
- pos = 0
- comp = -1
-
+
+ def _parse_isodate(self, dt_str):
+ try:
+ return self._parse_isodate_common(dt_str)
+ except ValueError:
+ return self._parse_isodate_uncommon(dt_str)
+
+ def _parse_isodate_common(self, dt_str):
+ len_str = len(dt_str)
+ components = [1, 1, 1]
+
+ if len_str < 4:
+ raise ValueError('ISO string too short')
+
+ # Year
+ components[0] = int(dt_str[0:4])
+ pos = 4
+ if pos >= len_str:
+ return components, pos
+
+ has_sep = dt_str[pos:pos + 1] == self._DATE_SEP
+ if has_sep:
+ pos += 1
+
+ # Month
+ if len_str - pos < 2:
+ raise ValueError('Invalid common month')
+
+ components[1] = int(dt_str[pos:pos + 2])
+ pos += 2
+
+ if pos >= len_str:
+ if has_sep:
+ return components, pos
+ else:
+ raise ValueError('Invalid ISO format')
+
+ if has_sep:
+ if dt_str[pos:pos + 1] != self._DATE_SEP:
+ raise ValueError('Invalid separator in ISO string')
+ pos += 1
+
+ # Day
+ if len_str - pos < 2:
+ raise ValueError('Invalid common day')
+ components[2] = int(dt_str[pos:pos + 2])
+ return components, pos + 2
+
+ def _parse_isodate_uncommon(self, dt_str):
+ if len(dt_str) < 4:
+ raise ValueError('ISO string too short')
+
+ # All ISO formats start with the year
+ year = int(dt_str[0:4])
+
+ has_sep = dt_str[4:5] == self._DATE_SEP
+
+ pos = 4 + has_sep # Skip '-' if it's there
+ if dt_str[pos:pos + 1] == b'W':
+ # YYYY-?Www-?D?
+ pos += 1
+ weekno = int(dt_str[pos:pos + 2])
+ pos += 2
+
+ dayno = 1
+ if len(dt_str) > pos:
+ if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep:
+ raise ValueError('Inconsistent use of dash separator')
+
+ pos += has_sep
+
+ dayno = int(dt_str[pos:pos + 1])
+ pos += 1
+
+ base_date = self._calculate_weekdate(year, weekno, dayno)
+ else:
+ # YYYYDDD or YYYY-DDD
+ if len(dt_str) - pos < 3:
+ raise ValueError('Invalid ordinal day')
+
+ ordinal_day = int(dt_str[pos:pos + 3])
+ pos += 3
+
+ if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)):
+ raise ValueError('Invalid ordinal day' +
+ ' {} for year {}'.format(ordinal_day, year))
+
+ base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1)
+
+ components = [base_date.year, base_date.month, base_date.day]
+ return components, pos
+
+ def _calculate_weekdate(self, year, week, day):
+ """
+ Calculate the day of corresponding to the ISO year-week-day calendar.
+
+ This function is effectively the inverse of
+ :func:`datetime.date.isocalendar`.
+
+ :param year:
+ The year in the ISO calendar
+
+ :param week:
+ The week in the ISO calendar - range is [1, 53]
+
+ :param day:
+ The day in the ISO calendar - range is [1 (MON), 7 (SUN)]
+
+ :return:
+ Returns a :class:`datetime.date`
+ """
+ if not 0 < week < 54:
+ raise ValueError('Invalid week: {}'.format(week))
+
+ if not 0 < day < 8: # Range is 1-7
+ raise ValueError('Invalid weekday: {}'.format(day))
+
+ # Get week 1 for the specific year:
+ jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it
+ week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1)
+
+ # Now add the specific number of weeks and days to get what we want
+ week_offset = (week - 1) * 7 + (day - 1)
+ return week_1 + timedelta(days=week_offset)
+
+ def _parse_isotime(self, timestr):
+ len_str = len(timestr)
+ components = [0, 0, 0, 0, None]
+ pos = 0
+ comp = -1
+
if len_str < 2:
- raise ValueError('ISO time too short')
-
+ raise ValueError('ISO time too short')
+
has_sep = False
-
- while pos < len_str and comp < 5:
- comp += 1
-
+
+ while pos < len_str and comp < 5:
+ comp += 1
+
if timestr[pos:pos + 1] in b'-+Zz':
- # Detect time zone boundary
- components[-1] = self._parse_tzstr(timestr[pos:])
- pos = len_str
- break
-
+ # Detect time zone boundary
+ components[-1] = self._parse_tzstr(timestr[pos:])
+ pos = len_str
+ break
+
if comp == 1 and timestr[pos:pos+1] == self._TIME_SEP:
has_sep = True
pos += 1
@@ -355,62 +355,62 @@ class isoparser(object):
raise ValueError('Inconsistent use of colon separator')
pos += 1
- if comp < 3:
- # Hour, minute, second
- components[comp] = int(timestr[pos:pos + 2])
- pos += 2
-
- if comp == 3:
+ if comp < 3:
+ # Hour, minute, second
+ components[comp] = int(timestr[pos:pos + 2])
+ pos += 2
+
+ if comp == 3:
# Fraction of a second
frac = self._FRACTION_REGEX.match(timestr[pos:])
if not frac:
- continue
-
+ continue
+
us_str = frac.group(1)[:6] # Truncate to microseconds
- components[comp] = int(us_str) * 10**(6 - len(us_str))
+ components[comp] = int(us_str) * 10**(6 - len(us_str))
pos += len(frac.group())
-
- if pos < len_str:
- raise ValueError('Unused components in ISO string')
-
- if components[0] == 24:
- # Standard supports 00:00 and 24:00 as representations of midnight
- if any(component != 0 for component in components[1:4]):
- raise ValueError('Hour may only be 24 at 24:00:00.000')
-
- return components
-
- def _parse_tzstr(self, tzstr, zero_as_utc=True):
+
+ if pos < len_str:
+ raise ValueError('Unused components in ISO string')
+
+ if components[0] == 24:
+ # Standard supports 00:00 and 24:00 as representations of midnight
+ if any(component != 0 for component in components[1:4]):
+ raise ValueError('Hour may only be 24 at 24:00:00.000')
+
+ return components
+
+ def _parse_tzstr(self, tzstr, zero_as_utc=True):
if tzstr == b'Z' or tzstr == b'z':
return tz.UTC
-
- if len(tzstr) not in {3, 5, 6}:
- raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters')
-
- if tzstr[0:1] == b'-':
- mult = -1
- elif tzstr[0:1] == b'+':
- mult = 1
- else:
- raise ValueError('Time zone offset requires sign')
-
- hours = int(tzstr[1:3])
- if len(tzstr) == 3:
- minutes = 0
- else:
- minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):])
-
- if zero_as_utc and hours == 0 and minutes == 0:
+
+ if len(tzstr) not in {3, 5, 6}:
+ raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters')
+
+ if tzstr[0:1] == b'-':
+ mult = -1
+ elif tzstr[0:1] == b'+':
+ mult = 1
+ else:
+ raise ValueError('Time zone offset requires sign')
+
+ hours = int(tzstr[1:3])
+ if len(tzstr) == 3:
+ minutes = 0
+ else:
+ minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):])
+
+ if zero_as_utc and hours == 0 and minutes == 0:
return tz.UTC
- else:
- if minutes > 59:
- raise ValueError('Invalid minutes in time zone offset')
-
- if hours > 23:
- raise ValueError('Invalid hours in time zone offset')
-
- return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60)
-
-
-DEFAULT_ISOPARSER = isoparser()
-isoparse = DEFAULT_ISOPARSER.isoparse
+ else:
+ if minutes > 59:
+ raise ValueError('Invalid minutes in time zone offset')
+
+ if hours > 23:
+ raise ValueError('Invalid hours in time zone offset')
+
+ return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60)
+
+
+DEFAULT_ISOPARSER = isoparser()
+isoparse = DEFAULT_ISOPARSER.isoparse
diff --git a/contrib/python/dateutil/dateutil/relativedelta.py b/contrib/python/dateutil/dateutil/relativedelta.py
index 35c0ae546f..a9e85f7e6c 100644
--- a/contrib/python/dateutil/dateutil/relativedelta.py
+++ b/contrib/python/dateutil/dateutil/relativedelta.py
@@ -23,7 +23,7 @@ class relativedelta(object):
It is based on the specification of the excellent work done by M.-A. Lemburg
in his
- `mx.DateTime <https://www.egenix.com/products/python/mxBase/mxDateTime/>`_ extension.
+ `mx.DateTime <https://www.egenix.com/products/python/mxBase/mxDateTime/>`_ extension.
However, notice that this type does *NOT* implement the same algorithm as
his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
@@ -38,7 +38,7 @@ class relativedelta(object):
year, month, day, hour, minute, second, microsecond:
Absolute information (argument is singular); adding or subtracting a
- relativedelta with absolute information does not perform an arithmetic
+ relativedelta with absolute information does not perform an arithmetic
operation, but rather REPLACES the corresponding value in the
original datetime with the value(s) in relativedelta.
@@ -48,7 +48,7 @@ class relativedelta(object):
the corresponding arithmetic operation on the original datetime value
with the information in the relativedelta.
- weekday:
+ weekday:
One of the weekday instances (MO, TU, etc) available in the
relativedelta module. These instances may receive a parameter N,
specifying the Nth weekday, which could be positive or negative
@@ -67,38 +67,38 @@ class relativedelta(object):
Set the yearday or the non-leap year day (jump leap days).
These are converted to day/month/leapdays information.
- There are relative and absolute forms of the keyword
- arguments. The plural is relative, and the singular is
- absolute. For each argument in the order below, the absolute form
- is applied first (by setting each attribute to that value) and
- then the relative form (by adding the value to the attribute).
+ There are relative and absolute forms of the keyword
+ arguments. The plural is relative, and the singular is
+ absolute. For each argument in the order below, the absolute form
+ is applied first (by setting each attribute to that value) and
+ then the relative form (by adding the value to the attribute).
- The order of attributes considered when this relativedelta is
- added to a datetime is:
+ The order of attributes considered when this relativedelta is
+ added to a datetime is:
- 1. Year
- 2. Month
- 3. Day
- 4. Hours
- 5. Minutes
- 6. Seconds
- 7. Microseconds
+ 1. Year
+ 2. Month
+ 3. Day
+ 4. Hours
+ 5. Minutes
+ 6. Seconds
+ 7. Microseconds
- Finally, weekday is applied, using the rule described above.
+ Finally, weekday is applied, using the rule described above.
- For example
+ For example
>>> from datetime import datetime
>>> from dateutil.relativedelta import relativedelta, MO
- >>> dt = datetime(2018, 4, 9, 13, 37, 0)
- >>> delta = relativedelta(hours=25, day=1, weekday=MO(1))
+ >>> dt = datetime(2018, 4, 9, 13, 37, 0)
+ >>> delta = relativedelta(hours=25, day=1, weekday=MO(1))
>>> dt + delta
datetime.datetime(2018, 4, 2, 14, 37)
- First, the day is set to 1 (the first of the month), then 25 hours
- are added, to get to the 2nd day and 14th hour, finally the
- weekday is applied, but since the 2nd is already a Monday there is
- no effect.
+ First, the day is set to 1 (the first of the month), then 25 hours
+ are added, to get to the 2nd day and 14th hour, finally the
+ weekday is applied, but since the 2nd is already a Monday there is
+ no effect.
"""
@@ -168,14 +168,14 @@ class relativedelta(object):
self.seconds = delta.seconds + delta.days * 86400
self.microseconds = delta.microseconds
else:
- # Check for non-integer values in integer-only quantities
- if any(x is not None and x != int(x) for x in (years, months)):
- raise ValueError("Non-integer years and months are "
- "ambiguous and not currently supported.")
-
+ # Check for non-integer values in integer-only quantities
+ if any(x is not None and x != int(x) for x in (years, months)):
+ raise ValueError("Non-integer years and months are "
+ "ambiguous and not currently supported.")
+
# Relative information
- self.years = int(years)
- self.months = int(months)
+ self.years = int(years)
+ self.months = int(months)
self.days = days + weeks * 7
self.leapdays = leapdays
self.hours = hours
@@ -263,7 +263,7 @@ class relativedelta(object):
@property
def weeks(self):
- return int(self.days / 7.0)
+ return int(self.days / 7.0)
@weeks.setter
def weeks(self, value):
@@ -436,24 +436,24 @@ class relativedelta(object):
is not None else
other.microsecond))
- def __abs__(self):
- return self.__class__(years=abs(self.years),
- months=abs(self.months),
- days=abs(self.days),
- hours=abs(self.hours),
- minutes=abs(self.minutes),
- seconds=abs(self.seconds),
- microseconds=abs(self.microseconds),
- leapdays=self.leapdays,
- year=self.year,
- month=self.month,
- day=self.day,
- weekday=self.weekday,
- hour=self.hour,
- minute=self.minute,
- second=self.second,
- microsecond=self.microsecond)
-
+ def __abs__(self):
+ return self.__class__(years=abs(self.years),
+ months=abs(self.months),
+ days=abs(self.days),
+ hours=abs(self.hours),
+ minutes=abs(self.minutes),
+ seconds=abs(self.seconds),
+ microseconds=abs(self.microseconds),
+ leapdays=self.leapdays,
+ year=self.year,
+ month=self.month,
+ day=self.day,
+ weekday=self.weekday,
+ hour=self.hour,
+ minute=self.minute,
+ second=self.second,
+ microsecond=self.microsecond)
+
def __neg__(self):
return self.__class__(years=-self.years,
months=-self.months,
@@ -544,25 +544,25 @@ class relativedelta(object):
self.second == other.second and
self.microsecond == other.microsecond)
- def __hash__(self):
- return hash((
- self.weekday,
- self.years,
- self.months,
- self.days,
- self.hours,
- self.minutes,
- self.seconds,
- self.microseconds,
- self.leapdays,
- self.year,
- self.month,
- self.day,
- self.hour,
- self.minute,
- self.second,
- self.microsecond,
- ))
+ def __hash__(self):
+ return hash((
+ self.weekday,
+ self.years,
+ self.months,
+ self.days,
+ self.hours,
+ self.minutes,
+ self.seconds,
+ self.microseconds,
+ self.leapdays,
+ self.year,
+ self.month,
+ self.day,
+ self.hour,
+ self.minute,
+ self.second,
+ self.microsecond,
+ ))
def __ne__(self, other):
return not self.__eq__(other)
diff --git a/contrib/python/dateutil/dateutil/rrule.py b/contrib/python/dateutil/dateutil/rrule.py
index ad1c8b3dae..b3203393c6 100644
--- a/contrib/python/dateutil/dateutil/rrule.py
+++ b/contrib/python/dateutil/dateutil/rrule.py
@@ -2,14 +2,14 @@
"""
The rrule module offers a small, complete, and very fast, implementation of
the recurrence rules documented in the
-`iCalendar RFC <https://tools.ietf.org/html/rfc5545>`_,
+`iCalendar RFC <https://tools.ietf.org/html/rfc5545>`_,
including support for caching of results.
"""
import calendar
import datetime
import heapq
import itertools
-import re
+import re
import sys
from functools import wraps
# For warning about deprecation of until and count
@@ -390,11 +390,11 @@ class rrule(rrulebase):
:param byyearday:
If given, it must be either an integer, or a sequence of integers,
meaning the year days to apply the recurrence to.
- :param byeaster:
- If given, it must be either an integer, or a sequence of integers,
- positive or negative. Each integer will define an offset from the
- Easter Sunday. Passing the offset 0 to byeaster will yield the Easter
- Sunday itself. This is an extension to the RFC specification.
+ :param byeaster:
+ If given, it must be either an integer, or a sequence of integers,
+ positive or negative. Each integer will define an offset from the
+ Easter Sunday. Passing the offset 0 to byeaster will yield the Easter
+ Sunday itself. This is an extension to the RFC specification.
:param byweekno:
If given, it must be either an integer, or a sequence of integers,
meaning the week numbers to apply the recurrence to. Week numbers
@@ -420,10 +420,10 @@ class rrule(rrulebase):
:param bysecond:
If given, it must be either an integer, or a sequence of integers,
meaning the seconds to apply the recurrence to.
- :param cache:
- If given, it must be a boolean value specifying to enable or disable
- caching of results. If you will use the same rrule instance multiple
- times, enabling caching will improve the performance considerably.
+ :param cache:
+ If given, it must be a boolean value specifying to enable or disable
+ caching of results. If you will use the same rrule instance multiple
+ times, enabling caching will improve the performance considerably.
"""
def __init__(self, freq, dtstart=None,
interval=1, wkst=None, count=None, until=None, bysetpos=None,
@@ -434,10 +434,10 @@ class rrule(rrulebase):
super(rrule, self).__init__(cache)
global easter
if not dtstart:
- if until and until.tzinfo:
- dtstart = datetime.datetime.now(tz=until.tzinfo).replace(microsecond=0)
+ if until and until.tzinfo:
+ dtstart = datetime.datetime.now(tz=until.tzinfo).replace(microsecond=0)
else:
- dtstart = datetime.datetime.now().replace(microsecond=0)
+ dtstart = datetime.datetime.now().replace(microsecond=0)
elif not isinstance(dtstart, datetime.datetime):
dtstart = datetime.datetime.fromordinal(dtstart.toordinal())
else:
@@ -458,22 +458,22 @@ class rrule(rrulebase):
until = datetime.datetime.fromordinal(until.toordinal())
self._until = until
- if self._dtstart and self._until:
- if (self._dtstart.tzinfo is not None) != (self._until.tzinfo is not None):
- # According to RFC5545 Section 3.3.10:
- # https://tools.ietf.org/html/rfc5545#section-3.3.10
- #
- # > If the "DTSTART" property is specified as a date with UTC
- # > time or a date with local time and time zone reference,
- # > then the UNTIL rule part MUST be specified as a date with
- # > UTC time.
- raise ValueError(
- 'RRULE UNTIL values must be specified in UTC when DTSTART '
- 'is timezone-aware'
- )
-
+ if self._dtstart and self._until:
+ if (self._dtstart.tzinfo is not None) != (self._until.tzinfo is not None):
+ # According to RFC5545 Section 3.3.10:
+ # https://tools.ietf.org/html/rfc5545#section-3.3.10
+ #
+ # > If the "DTSTART" property is specified as a date with UTC
+ # > time or a date with local time and time zone reference,
+ # > then the UNTIL rule part MUST be specified as a date with
+ # > UTC time.
+ raise ValueError(
+ 'RRULE UNTIL values must be specified in UTC when DTSTART '
+ 'is timezone-aware'
+ )
+
if count is not None and until:
- warn("Using both 'count' and 'until' is inconsistent with RFC 5545"
+ warn("Using both 'count' and 'until' is inconsistent with RFC 5545"
" and has been deprecated in dateutil. Future versions will "
"raise an error.", DeprecationWarning)
@@ -610,13 +610,13 @@ class rrule(rrulebase):
self._byweekday = tuple(sorted(self._byweekday))
orig_byweekday = [weekday(x) for x in self._byweekday]
else:
- orig_byweekday = ()
+ orig_byweekday = ()
if self._bynweekday is not None:
self._bynweekday = tuple(sorted(self._bynweekday))
orig_bynweekday = [weekday(*x) for x in self._bynweekday]
else:
- orig_bynweekday = ()
+ orig_bynweekday = ()
if 'byweekday' not in self._original_rule:
self._original_rule['byweekday'] = tuple(itertools.chain(
@@ -625,7 +625,7 @@ class rrule(rrulebase):
# byhour
if byhour is None:
if freq < HOURLY:
- self._byhour = {dtstart.hour}
+ self._byhour = {dtstart.hour}
else:
self._byhour = None
else:
@@ -645,7 +645,7 @@ class rrule(rrulebase):
# byminute
if byminute is None:
if freq < MINUTELY:
- self._byminute = {dtstart.minute}
+ self._byminute = {dtstart.minute}
else:
self._byminute = None
else:
@@ -700,7 +700,7 @@ class rrule(rrulebase):
def __str__(self):
"""
Output a string that would generate this RRULE if passed to rrulestr.
- This is mostly compatible with RFC5545, except for the
+ This is mostly compatible with RFC5545, except for the
dateutil-specific extension BYEASTER.
"""
@@ -725,7 +725,7 @@ class rrule(rrulebase):
if self._original_rule.get('byweekday') is not None:
# The str() method on weekday objects doesn't generate
- # RFC5545-compliant strings, so we should modify that.
+ # RFC5545-compliant strings, so we should modify that.
original_rule = dict(self._original_rule)
wday_strings = []
for wday in original_rule['byweekday']:
@@ -756,7 +756,7 @@ class rrule(rrulebase):
parts.append(partfmt.format(name=name, vals=(','.join(str(v)
for v in value))))
- output.append('RRULE:' + ';'.join(parts))
+ output.append('RRULE:' + ';'.join(parts))
return '\n'.join(output)
def replace(self, **kwargs):
@@ -1619,17 +1619,17 @@ class _rrulestr(object):
forceset=False,
compatible=False,
ignoretz=False,
- tzids=None,
+ tzids=None,
tzinfos=None):
global parser
if compatible:
forceset = True
unfold = True
-
- TZID_NAMES = dict(map(
- lambda x: (x.upper(), x),
- re.findall('TZID=(?P<name>[^:]+):', s)
- ))
+
+ TZID_NAMES = dict(map(
+ lambda x: (x.upper(), x),
+ re.findall('TZID=(?P<name>[^:]+):', s)
+ ))
s = s.upper()
if not s.strip():
raise ValueError("empty string")
diff --git a/contrib/python/dateutil/dateutil/test/_common.py b/contrib/python/dateutil/dateutil/test/_common.py
index 3444ee9c9c..b8d2047374 100644
--- a/contrib/python/dateutil/dateutil/test/_common.py
+++ b/contrib/python/dateutil/dateutil/test/_common.py
@@ -1,233 +1,233 @@
-from __future__ import unicode_literals
-import os
-import time
-import subprocess
-import warnings
-import tempfile
-import pickle
-
+from __future__ import unicode_literals
+import os
+import time
+import subprocess
+import warnings
+import tempfile
+import pickle
+
import pytest
-
-
-class PicklableMixin(object):
- def _get_nobj_bytes(self, obj, dump_kwargs, load_kwargs):
- """
- Pickle and unpickle an object using ``pickle.dumps`` / ``pickle.loads``
- """
- pkl = pickle.dumps(obj, **dump_kwargs)
- return pickle.loads(pkl, **load_kwargs)
-
- def _get_nobj_file(self, obj, dump_kwargs, load_kwargs):
- """
- Pickle and unpickle an object using ``pickle.dump`` / ``pickle.load`` on
- a temporary file.
- """
- with tempfile.TemporaryFile('w+b') as pkl:
- pickle.dump(obj, pkl, **dump_kwargs)
- pkl.seek(0) # Reset the file to the beginning to read it
- nobj = pickle.load(pkl, **load_kwargs)
-
- return nobj
-
- def assertPicklable(self, obj, singleton=False, asfile=False,
- dump_kwargs=None, load_kwargs=None):
- """
- Assert that an object can be pickled and unpickled. This assertion
- assumes that the desired behavior is that the unpickled object compares
- equal to the original object, but is not the same object.
- """
- get_nobj = self._get_nobj_file if asfile else self._get_nobj_bytes
- dump_kwargs = dump_kwargs or {}
- load_kwargs = load_kwargs or {}
-
- nobj = get_nobj(obj, dump_kwargs, load_kwargs)
- if not singleton:
- self.assertIsNot(obj, nobj)
- self.assertEqual(obj, nobj)
-
-
-class TZContextBase(object):
- """
- Base class for a context manager which allows changing of time zones.
-
- Subclasses may define a guard variable to either block or or allow time
- zone changes by redefining ``_guard_var_name`` and ``_guard_allows_change``.
- The default is that the guard variable must be affirmatively set.
-
- Subclasses must define ``get_current_tz`` and ``set_current_tz``.
- """
- _guard_var_name = "DATEUTIL_MAY_CHANGE_TZ"
- _guard_allows_change = True
-
- def __init__(self, tzval):
- self.tzval = tzval
- self._old_tz = None
-
- @classmethod
- def tz_change_allowed(cls):
- """
- Class method used to query whether or not this class allows time zone
- changes.
- """
+
+
+class PicklableMixin(object):
+ def _get_nobj_bytes(self, obj, dump_kwargs, load_kwargs):
+ """
+ Pickle and unpickle an object using ``pickle.dumps`` / ``pickle.loads``
+ """
+ pkl = pickle.dumps(obj, **dump_kwargs)
+ return pickle.loads(pkl, **load_kwargs)
+
+ def _get_nobj_file(self, obj, dump_kwargs, load_kwargs):
+ """
+ Pickle and unpickle an object using ``pickle.dump`` / ``pickle.load`` on
+ a temporary file.
+ """
+ with tempfile.TemporaryFile('w+b') as pkl:
+ pickle.dump(obj, pkl, **dump_kwargs)
+ pkl.seek(0) # Reset the file to the beginning to read it
+ nobj = pickle.load(pkl, **load_kwargs)
+
+ return nobj
+
+ def assertPicklable(self, obj, singleton=False, asfile=False,
+ dump_kwargs=None, load_kwargs=None):
+ """
+ Assert that an object can be pickled and unpickled. This assertion
+ assumes that the desired behavior is that the unpickled object compares
+ equal to the original object, but is not the same object.
+ """
+ get_nobj = self._get_nobj_file if asfile else self._get_nobj_bytes
+ dump_kwargs = dump_kwargs or {}
+ load_kwargs = load_kwargs or {}
+
+ nobj = get_nobj(obj, dump_kwargs, load_kwargs)
+ if not singleton:
+ self.assertIsNot(obj, nobj)
+ self.assertEqual(obj, nobj)
+
+
+class TZContextBase(object):
+ """
+ Base class for a context manager which allows changing of time zones.
+
+ Subclasses may define a guard variable to either block or or allow time
+ zone changes by redefining ``_guard_var_name`` and ``_guard_allows_change``.
+ The default is that the guard variable must be affirmatively set.
+
+ Subclasses must define ``get_current_tz`` and ``set_current_tz``.
+ """
+ _guard_var_name = "DATEUTIL_MAY_CHANGE_TZ"
+ _guard_allows_change = True
+
+ def __init__(self, tzval):
+ self.tzval = tzval
+ self._old_tz = None
+
+ @classmethod
+ def tz_change_allowed(cls):
+ """
+ Class method used to query whether or not this class allows time zone
+ changes.
+ """
guard = bool(os.environ.get(cls._guard_var_name, False))
-
- # _guard_allows_change gives the "default" behavior - if True, the
- # guard is overcoming a block. If false, the guard is causing a block.
- # Whether tz_change is allowed is therefore the XNOR of the two.
+
+ # _guard_allows_change gives the "default" behavior - if True, the
+ # guard is overcoming a block. If false, the guard is causing a block.
+ # Whether tz_change is allowed is therefore the XNOR of the two.
return guard == cls._guard_allows_change
-
- @classmethod
- def tz_change_disallowed_message(cls):
- """ Generate instructions on how to allow tz changes """
- msg = ('Changing time zone not allowed. Set {envar} to {gval} '
- 'if you would like to allow this behavior')
-
- return msg.format(envar=cls._guard_var_name,
- gval=cls._guard_allows_change)
-
- def __enter__(self):
- if not self.tz_change_allowed():
+
+ @classmethod
+ def tz_change_disallowed_message(cls):
+ """ Generate instructions on how to allow tz changes """
+ msg = ('Changing time zone not allowed. Set {envar} to {gval} '
+ 'if you would like to allow this behavior')
+
+ return msg.format(envar=cls._guard_var_name,
+ gval=cls._guard_allows_change)
+
+ def __enter__(self):
+ if not self.tz_change_allowed():
msg = self.tz_change_disallowed_message()
pytest.skip(msg)
-
+
# If this is used outside of a test suite, we still want an error.
raise ValueError(msg) # pragma: no cover
- self._old_tz = self.get_current_tz()
- self.set_current_tz(self.tzval)
-
- def __exit__(self, type, value, traceback):
- if self._old_tz is not None:
- self.set_current_tz(self._old_tz)
-
- self._old_tz = None
-
- def get_current_tz(self):
- raise NotImplementedError
-
- def set_current_tz(self):
- raise NotImplementedError
-
-
-class TZEnvContext(TZContextBase):
- """
- Context manager that temporarily sets the `TZ` variable (for use on
- *nix-like systems). Because the effect is local to the shell anyway, this
- will apply *unless* a guard is set.
-
- If you do not want the TZ environment variable set, you may set the
- ``DATEUTIL_MAY_NOT_CHANGE_TZ_VAR`` variable to a truthy value.
- """
- _guard_var_name = "DATEUTIL_MAY_NOT_CHANGE_TZ_VAR"
- _guard_allows_change = False
-
- def get_current_tz(self):
- return os.environ.get('TZ', UnsetTz)
-
- def set_current_tz(self, tzval):
- if tzval is UnsetTz and 'TZ' in os.environ:
- del os.environ['TZ']
- else:
- os.environ['TZ'] = tzval
-
- time.tzset()
-
-
-class TZWinContext(TZContextBase):
- """
- Context manager for changing local time zone on Windows.
-
- Because the effect of this is system-wide and global, it may have
- unintended side effect. Set the ``DATEUTIL_MAY_CHANGE_TZ`` environment
- variable to a truthy value before using this context manager.
- """
- def get_current_tz(self):
- p = subprocess.Popen(['tzutil', '/g'], stdout=subprocess.PIPE)
-
- ctzname, err = p.communicate()
- ctzname = ctzname.decode() # Popen returns
-
- if p.returncode:
- raise OSError('Failed to get current time zone: ' + err)
-
- return ctzname
-
- def set_current_tz(self, tzname):
- p = subprocess.Popen('tzutil /s "' + tzname + '"')
-
- out, err = p.communicate()
-
- if p.returncode:
- raise OSError('Failed to set current time zone: ' +
- (err or 'Unknown error.'))
-
-
-###
-# Utility classes
-class NotAValueClass(object):
- """
- A class analogous to NaN that has operations defined for any type.
- """
- def _op(self, other):
- return self # Operation with NotAValue returns NotAValue
-
- def _cmp(self, other):
- return False
-
- __add__ = __radd__ = _op
- __sub__ = __rsub__ = _op
- __mul__ = __rmul__ = _op
- __div__ = __rdiv__ = _op
- __truediv__ = __rtruediv__ = _op
- __floordiv__ = __rfloordiv__ = _op
-
- __lt__ = __rlt__ = _op
- __gt__ = __rgt__ = _op
- __eq__ = __req__ = _op
- __le__ = __rle__ = _op
- __ge__ = __rge__ = _op
-
-
-NotAValue = NotAValueClass()
-
-
-class ComparesEqualClass(object):
- """
- A class that is always equal to whatever you compare it to.
- """
-
- def __eq__(self, other):
- return True
-
- def __ne__(self, other):
- return False
-
- def __le__(self, other):
- return True
-
- def __ge__(self, other):
- return True
-
- def __lt__(self, other):
- return False
-
- def __gt__(self, other):
- return False
-
- __req__ = __eq__
- __rne__ = __ne__
- __rle__ = __le__
- __rge__ = __ge__
- __rlt__ = __lt__
- __rgt__ = __gt__
-
-
-ComparesEqual = ComparesEqualClass()
-
-
-class UnsetTzClass(object):
- """ Sentinel class for unset time zone variable """
- pass
-
-
-UnsetTz = UnsetTzClass()
+ self._old_tz = self.get_current_tz()
+ self.set_current_tz(self.tzval)
+
+ def __exit__(self, type, value, traceback):
+ if self._old_tz is not None:
+ self.set_current_tz(self._old_tz)
+
+ self._old_tz = None
+
+ def get_current_tz(self):
+ raise NotImplementedError
+
+ def set_current_tz(self):
+ raise NotImplementedError
+
+
+class TZEnvContext(TZContextBase):
+ """
+ Context manager that temporarily sets the `TZ` variable (for use on
+ *nix-like systems). Because the effect is local to the shell anyway, this
+ will apply *unless* a guard is set.
+
+ If you do not want the TZ environment variable set, you may set the
+ ``DATEUTIL_MAY_NOT_CHANGE_TZ_VAR`` variable to a truthy value.
+ """
+ _guard_var_name = "DATEUTIL_MAY_NOT_CHANGE_TZ_VAR"
+ _guard_allows_change = False
+
+ def get_current_tz(self):
+ return os.environ.get('TZ', UnsetTz)
+
+ def set_current_tz(self, tzval):
+ if tzval is UnsetTz and 'TZ' in os.environ:
+ del os.environ['TZ']
+ else:
+ os.environ['TZ'] = tzval
+
+ time.tzset()
+
+
+class TZWinContext(TZContextBase):
+ """
+ Context manager for changing local time zone on Windows.
+
+ Because the effect of this is system-wide and global, it may have
+ unintended side effect. Set the ``DATEUTIL_MAY_CHANGE_TZ`` environment
+ variable to a truthy value before using this context manager.
+ """
+ def get_current_tz(self):
+ p = subprocess.Popen(['tzutil', '/g'], stdout=subprocess.PIPE)
+
+ ctzname, err = p.communicate()
+ ctzname = ctzname.decode() # Popen returns
+
+ if p.returncode:
+ raise OSError('Failed to get current time zone: ' + err)
+
+ return ctzname
+
+ def set_current_tz(self, tzname):
+ p = subprocess.Popen('tzutil /s "' + tzname + '"')
+
+ out, err = p.communicate()
+
+ if p.returncode:
+ raise OSError('Failed to set current time zone: ' +
+ (err or 'Unknown error.'))
+
+
+###
+# Utility classes
+class NotAValueClass(object):
+ """
+ A class analogous to NaN that has operations defined for any type.
+ """
+ def _op(self, other):
+ return self # Operation with NotAValue returns NotAValue
+
+ def _cmp(self, other):
+ return False
+
+ __add__ = __radd__ = _op
+ __sub__ = __rsub__ = _op
+ __mul__ = __rmul__ = _op
+ __div__ = __rdiv__ = _op
+ __truediv__ = __rtruediv__ = _op
+ __floordiv__ = __rfloordiv__ = _op
+
+ __lt__ = __rlt__ = _op
+ __gt__ = __rgt__ = _op
+ __eq__ = __req__ = _op
+ __le__ = __rle__ = _op
+ __ge__ = __rge__ = _op
+
+
+NotAValue = NotAValueClass()
+
+
+class ComparesEqualClass(object):
+ """
+ A class that is always equal to whatever you compare it to.
+ """
+
+ def __eq__(self, other):
+ return True
+
+ def __ne__(self, other):
+ return False
+
+ def __le__(self, other):
+ return True
+
+ def __ge__(self, other):
+ return True
+
+ def __lt__(self, other):
+ return False
+
+ def __gt__(self, other):
+ return False
+
+ __req__ = __eq__
+ __rne__ = __ne__
+ __rle__ = __le__
+ __rge__ = __ge__
+ __rlt__ = __lt__
+ __rgt__ = __gt__
+
+
+ComparesEqual = ComparesEqualClass()
+
+
+class UnsetTzClass(object):
+ """ Sentinel class for unset time zone variable """
+ pass
+
+
+UnsetTz = UnsetTzClass()
diff --git a/contrib/python/dateutil/dateutil/test/property/test_isoparse_prop.py b/contrib/python/dateutil/dateutil/test/property/test_isoparse_prop.py
index 9094886329..f8e288f3d6 100644
--- a/contrib/python/dateutil/dateutil/test/property/test_isoparse_prop.py
+++ b/contrib/python/dateutil/dateutil/test/property/test_isoparse_prop.py
@@ -1,27 +1,27 @@
-from hypothesis import given, assume
-from hypothesis import strategies as st
-
-from dateutil import tz
-from dateutil.parser import isoparse
-
-import pytest
-
-# Strategies
+from hypothesis import given, assume
+from hypothesis import strategies as st
+
+from dateutil import tz
+from dateutil.parser import isoparse
+
+import pytest
+
+# Strategies
TIME_ZONE_STRATEGY = st.sampled_from([None, tz.UTC] +
- [tz.gettz(zname) for zname in ('US/Eastern', 'US/Pacific',
- 'Australia/Sydney', 'Europe/London')])
-ASCII_STRATEGY = st.characters(max_codepoint=127)
-
-
-@pytest.mark.isoparser
-@given(dt=st.datetimes(timezones=TIME_ZONE_STRATEGY), sep=ASCII_STRATEGY)
-def test_timespec_auto(dt, sep):
- if dt.tzinfo is not None:
- # Assume offset has no sub-second components
- assume(dt.utcoffset().total_seconds() % 60 == 0)
-
- sep = str(sep) # Python 2.7 requires bytes
- dtstr = dt.isoformat(sep=sep)
- dt_rt = isoparse(dtstr)
-
- assert dt_rt == dt
+ [tz.gettz(zname) for zname in ('US/Eastern', 'US/Pacific',
+ 'Australia/Sydney', 'Europe/London')])
+ASCII_STRATEGY = st.characters(max_codepoint=127)
+
+
+@pytest.mark.isoparser
+@given(dt=st.datetimes(timezones=TIME_ZONE_STRATEGY), sep=ASCII_STRATEGY)
+def test_timespec_auto(dt, sep):
+ if dt.tzinfo is not None:
+ # Assume offset has no sub-second components
+ assume(dt.utcoffset().total_seconds() % 60 == 0)
+
+ sep = str(sep) # Python 2.7 requires bytes
+ dtstr = dt.isoformat(sep=sep)
+ dt_rt = isoparse(dtstr)
+
+ assert dt_rt == dt
diff --git a/contrib/python/dateutil/dateutil/test/property/test_parser_prop.py b/contrib/python/dateutil/dateutil/test/property/test_parser_prop.py
index f8f5769409..fdfd171e86 100644
--- a/contrib/python/dateutil/dateutil/test/property/test_parser_prop.py
+++ b/contrib/python/dateutil/dateutil/test/property/test_parser_prop.py
@@ -1,22 +1,22 @@
-from hypothesis.strategies import integers
-from hypothesis import given
-
-import pytest
-
-from dateutil.parser import parserinfo
-
-
-@pytest.mark.parserinfo
-@given(integers(min_value=100, max_value=9999))
-def test_convertyear(n):
- assert n == parserinfo().convertyear(n)
-
-
-@pytest.mark.parserinfo
-@given(integers(min_value=-50,
- max_value=49))
-def test_convertyear_no_specified_century(n):
- p = parserinfo()
- new_year = p._year + n
- result = p.convertyear(new_year % 100, century_specified=False)
- assert result == new_year
+from hypothesis.strategies import integers
+from hypothesis import given
+
+import pytest
+
+from dateutil.parser import parserinfo
+
+
+@pytest.mark.parserinfo
+@given(integers(min_value=100, max_value=9999))
+def test_convertyear(n):
+ assert n == parserinfo().convertyear(n)
+
+
+@pytest.mark.parserinfo
+@given(integers(min_value=-50,
+ max_value=49))
+def test_convertyear_no_specified_century(n):
+ p = parserinfo()
+ new_year = p._year + n
+ result = p.convertyear(new_year % 100, century_specified=False)
+ assert result == new_year
diff --git a/contrib/python/dateutil/dateutil/test/test_easter.py b/contrib/python/dateutil/dateutil/test/test_easter.py
index 646ff98d0a..cf2ec7f287 100644
--- a/contrib/python/dateutil/dateutil/test/test_easter.py
+++ b/contrib/python/dateutil/dateutil/test/test_easter.py
@@ -1,87 +1,87 @@
-from dateutil.easter import easter
-from dateutil.easter import EASTER_WESTERN, EASTER_ORTHODOX, EASTER_JULIAN
-
-from datetime import date
+from dateutil.easter import easter
+from dateutil.easter import EASTER_WESTERN, EASTER_ORTHODOX, EASTER_JULIAN
+
+from datetime import date
import pytest
-
-# List of easters between 1990 and 2050
-western_easter_dates = [
- date(1990, 4, 15), date(1991, 3, 31), date(1992, 4, 19), date(1993, 4, 11),
- date(1994, 4, 3), date(1995, 4, 16), date(1996, 4, 7), date(1997, 3, 30),
- date(1998, 4, 12), date(1999, 4, 4),
-
- date(2000, 4, 23), date(2001, 4, 15), date(2002, 3, 31), date(2003, 4, 20),
- date(2004, 4, 11), date(2005, 3, 27), date(2006, 4, 16), date(2007, 4, 8),
- date(2008, 3, 23), date(2009, 4, 12),
-
- date(2010, 4, 4), date(2011, 4, 24), date(2012, 4, 8), date(2013, 3, 31),
- date(2014, 4, 20), date(2015, 4, 5), date(2016, 3, 27), date(2017, 4, 16),
- date(2018, 4, 1), date(2019, 4, 21),
-
- date(2020, 4, 12), date(2021, 4, 4), date(2022, 4, 17), date(2023, 4, 9),
- date(2024, 3, 31), date(2025, 4, 20), date(2026, 4, 5), date(2027, 3, 28),
- date(2028, 4, 16), date(2029, 4, 1),
-
- date(2030, 4, 21), date(2031, 4, 13), date(2032, 3, 28), date(2033, 4, 17),
- date(2034, 4, 9), date(2035, 3, 25), date(2036, 4, 13), date(2037, 4, 5),
- date(2038, 4, 25), date(2039, 4, 10),
-
- date(2040, 4, 1), date(2041, 4, 21), date(2042, 4, 6), date(2043, 3, 29),
- date(2044, 4, 17), date(2045, 4, 9), date(2046, 3, 25), date(2047, 4, 14),
- date(2048, 4, 5), date(2049, 4, 18), date(2050, 4, 10)
- ]
-
-orthodox_easter_dates = [
- date(1990, 4, 15), date(1991, 4, 7), date(1992, 4, 26), date(1993, 4, 18),
- date(1994, 5, 1), date(1995, 4, 23), date(1996, 4, 14), date(1997, 4, 27),
- date(1998, 4, 19), date(1999, 4, 11),
-
- date(2000, 4, 30), date(2001, 4, 15), date(2002, 5, 5), date(2003, 4, 27),
- date(2004, 4, 11), date(2005, 5, 1), date(2006, 4, 23), date(2007, 4, 8),
- date(2008, 4, 27), date(2009, 4, 19),
-
- date(2010, 4, 4), date(2011, 4, 24), date(2012, 4, 15), date(2013, 5, 5),
- date(2014, 4, 20), date(2015, 4, 12), date(2016, 5, 1), date(2017, 4, 16),
- date(2018, 4, 8), date(2019, 4, 28),
-
- date(2020, 4, 19), date(2021, 5, 2), date(2022, 4, 24), date(2023, 4, 16),
- date(2024, 5, 5), date(2025, 4, 20), date(2026, 4, 12), date(2027, 5, 2),
- date(2028, 4, 16), date(2029, 4, 8),
-
- date(2030, 4, 28), date(2031, 4, 13), date(2032, 5, 2), date(2033, 4, 24),
- date(2034, 4, 9), date(2035, 4, 29), date(2036, 4, 20), date(2037, 4, 5),
- date(2038, 4, 25), date(2039, 4, 17),
-
- date(2040, 5, 6), date(2041, 4, 21), date(2042, 4, 13), date(2043, 5, 3),
- date(2044, 4, 24), date(2045, 4, 9), date(2046, 4, 29), date(2047, 4, 21),
- date(2048, 4, 5), date(2049, 4, 25), date(2050, 4, 17)
-]
-
-# A random smattering of Julian dates.
-# Pulled values from http://www.kevinlaughery.com/east4099.html
-julian_easter_dates = [
- date( 326, 4, 3), date( 375, 4, 5), date( 492, 4, 5), date( 552, 3, 31),
- date( 562, 4, 9), date( 569, 4, 21), date( 597, 4, 14), date( 621, 4, 19),
- date( 636, 3, 31), date( 655, 3, 29), date( 700, 4, 11), date( 725, 4, 8),
- date( 750, 3, 29), date( 782, 4, 7), date( 835, 4, 18), date( 849, 4, 14),
- date( 867, 3, 30), date( 890, 4, 12), date( 922, 4, 21), date( 934, 4, 6),
- date(1049, 3, 26), date(1058, 4, 19), date(1113, 4, 6), date(1119, 3, 30),
- date(1242, 4, 20), date(1255, 3, 28), date(1257, 4, 8), date(1258, 3, 24),
- date(1261, 4, 24), date(1278, 4, 17), date(1333, 4, 4), date(1351, 4, 17),
- date(1371, 4, 6), date(1391, 3, 26), date(1402, 3, 26), date(1412, 4, 3),
- date(1439, 4, 5), date(1445, 3, 28), date(1531, 4, 9), date(1555, 4, 14)
-]
-
-
+
+# List of easters between 1990 and 2050
+western_easter_dates = [
+ date(1990, 4, 15), date(1991, 3, 31), date(1992, 4, 19), date(1993, 4, 11),
+ date(1994, 4, 3), date(1995, 4, 16), date(1996, 4, 7), date(1997, 3, 30),
+ date(1998, 4, 12), date(1999, 4, 4),
+
+ date(2000, 4, 23), date(2001, 4, 15), date(2002, 3, 31), date(2003, 4, 20),
+ date(2004, 4, 11), date(2005, 3, 27), date(2006, 4, 16), date(2007, 4, 8),
+ date(2008, 3, 23), date(2009, 4, 12),
+
+ date(2010, 4, 4), date(2011, 4, 24), date(2012, 4, 8), date(2013, 3, 31),
+ date(2014, 4, 20), date(2015, 4, 5), date(2016, 3, 27), date(2017, 4, 16),
+ date(2018, 4, 1), date(2019, 4, 21),
+
+ date(2020, 4, 12), date(2021, 4, 4), date(2022, 4, 17), date(2023, 4, 9),
+ date(2024, 3, 31), date(2025, 4, 20), date(2026, 4, 5), date(2027, 3, 28),
+ date(2028, 4, 16), date(2029, 4, 1),
+
+ date(2030, 4, 21), date(2031, 4, 13), date(2032, 3, 28), date(2033, 4, 17),
+ date(2034, 4, 9), date(2035, 3, 25), date(2036, 4, 13), date(2037, 4, 5),
+ date(2038, 4, 25), date(2039, 4, 10),
+
+ date(2040, 4, 1), date(2041, 4, 21), date(2042, 4, 6), date(2043, 3, 29),
+ date(2044, 4, 17), date(2045, 4, 9), date(2046, 3, 25), date(2047, 4, 14),
+ date(2048, 4, 5), date(2049, 4, 18), date(2050, 4, 10)
+ ]
+
+orthodox_easter_dates = [
+ date(1990, 4, 15), date(1991, 4, 7), date(1992, 4, 26), date(1993, 4, 18),
+ date(1994, 5, 1), date(1995, 4, 23), date(1996, 4, 14), date(1997, 4, 27),
+ date(1998, 4, 19), date(1999, 4, 11),
+
+ date(2000, 4, 30), date(2001, 4, 15), date(2002, 5, 5), date(2003, 4, 27),
+ date(2004, 4, 11), date(2005, 5, 1), date(2006, 4, 23), date(2007, 4, 8),
+ date(2008, 4, 27), date(2009, 4, 19),
+
+ date(2010, 4, 4), date(2011, 4, 24), date(2012, 4, 15), date(2013, 5, 5),
+ date(2014, 4, 20), date(2015, 4, 12), date(2016, 5, 1), date(2017, 4, 16),
+ date(2018, 4, 8), date(2019, 4, 28),
+
+ date(2020, 4, 19), date(2021, 5, 2), date(2022, 4, 24), date(2023, 4, 16),
+ date(2024, 5, 5), date(2025, 4, 20), date(2026, 4, 12), date(2027, 5, 2),
+ date(2028, 4, 16), date(2029, 4, 8),
+
+ date(2030, 4, 28), date(2031, 4, 13), date(2032, 5, 2), date(2033, 4, 24),
+ date(2034, 4, 9), date(2035, 4, 29), date(2036, 4, 20), date(2037, 4, 5),
+ date(2038, 4, 25), date(2039, 4, 17),
+
+ date(2040, 5, 6), date(2041, 4, 21), date(2042, 4, 13), date(2043, 5, 3),
+ date(2044, 4, 24), date(2045, 4, 9), date(2046, 4, 29), date(2047, 4, 21),
+ date(2048, 4, 5), date(2049, 4, 25), date(2050, 4, 17)
+]
+
+# A random smattering of Julian dates.
+# Pulled values from http://www.kevinlaughery.com/east4099.html
+julian_easter_dates = [
+ date( 326, 4, 3), date( 375, 4, 5), date( 492, 4, 5), date( 552, 3, 31),
+ date( 562, 4, 9), date( 569, 4, 21), date( 597, 4, 14), date( 621, 4, 19),
+ date( 636, 3, 31), date( 655, 3, 29), date( 700, 4, 11), date( 725, 4, 8),
+ date( 750, 3, 29), date( 782, 4, 7), date( 835, 4, 18), date( 849, 4, 14),
+ date( 867, 3, 30), date( 890, 4, 12), date( 922, 4, 21), date( 934, 4, 6),
+ date(1049, 3, 26), date(1058, 4, 19), date(1113, 4, 6), date(1119, 3, 30),
+ date(1242, 4, 20), date(1255, 3, 28), date(1257, 4, 8), date(1258, 3, 24),
+ date(1261, 4, 24), date(1278, 4, 17), date(1333, 4, 4), date(1351, 4, 17),
+ date(1371, 4, 6), date(1391, 3, 26), date(1402, 3, 26), date(1412, 4, 3),
+ date(1439, 4, 5), date(1445, 3, 28), date(1531, 4, 9), date(1555, 4, 14)
+]
+
+
@pytest.mark.parametrize("easter_date", western_easter_dates)
def test_easter_western(easter_date):
assert easter_date == easter(easter_date.year, EASTER_WESTERN)
-
-
+
+
@pytest.mark.parametrize("easter_date", orthodox_easter_dates)
def test_easter_orthodox(easter_date):
assert easter_date == easter(easter_date.year, EASTER_ORTHODOX)
-
+
@pytest.mark.parametrize("easter_date", julian_easter_dates)
def test_easter_julian(easter_date):
diff --git a/contrib/python/dateutil/dateutil/test/test_import_star.py b/contrib/python/dateutil/dateutil/test/test_import_star.py
index 90ce0880c6..2fb7098128 100644
--- a/contrib/python/dateutil/dateutil/test/test_import_star.py
+++ b/contrib/python/dateutil/dateutil/test/test_import_star.py
@@ -1,16 +1,16 @@
-"""Test for the "import *" functionality.
-
+"""Test for the "import *" functionality.
+
As import * can be only done at module level, it has been added in a separate file
-"""
+"""
import pytest
-
-prev_locals = list(locals())
-from dateutil import *
-new_locals = {name:value for name,value in locals().items()
- if name not in prev_locals}
-new_locals.pop('prev_locals')
-
-
+
+prev_locals = list(locals())
+from dateutil import *
+new_locals = {name:value for name,value in locals().items()
+ if name not in prev_locals}
+new_locals.pop('prev_locals')
+
+
@pytest.mark.import_star
def test_imported_modules():
""" Test that `from dateutil import *` adds modules in __all__ locally """
@@ -21,7 +21,7 @@ def test_imported_modules():
import dateutil.tz
import dateutil.utils
import dateutil.zoneinfo
-
+
assert dateutil.easter == new_locals.pop("easter")
assert dateutil.parser == new_locals.pop("parser")
assert dateutil.relativedelta == new_locals.pop("relativedelta")
@@ -29,5 +29,5 @@ def test_imported_modules():
assert dateutil.tz == new_locals.pop("tz")
assert dateutil.utils == new_locals.pop("utils")
assert dateutil.zoneinfo == new_locals.pop("zoneinfo")
-
+
assert not new_locals
diff --git a/contrib/python/dateutil/dateutil/test/test_imports.py b/contrib/python/dateutil/dateutil/test/test_imports.py
index 38aad8da46..60b86005ca 100644
--- a/contrib/python/dateutil/dateutil/test/test_imports.py
+++ b/contrib/python/dateutil/dateutil/test/test_imports.py
@@ -1,83 +1,83 @@
-import sys
+import sys
import pytest
-
+
HOST_IS_WINDOWS = sys.platform.startswith('win')
def test_import_version_str():
- """ Test that dateutil.__version__ can be imported"""
+ """ Test that dateutil.__version__ can be imported"""
from dateutil import __version__
-
-
+
+
def test_import_version_root():
import dateutil
assert hasattr(dateutil, '__version__')
-
-
+
+
# Test that dateutil.easter-related imports work properly
def test_import_easter_direct():
import dateutil.easter
-
-
+
+
def test_import_easter_from():
from dateutil import easter
-
-
+
+
def test_import_easter_start():
from dateutil.easter import easter
-
-
+
+
# Test that dateutil.parser-related imports work properly
def test_import_parser_direct():
import dateutil.parser
-
-
+
+
def test_import_parser_from():
from dateutil import parser
-
-
+
+
def test_import_parser_all():
# All interface
from dateutil.parser import parse
from dateutil.parser import parserinfo
-
+
# Other public classes
from dateutil.parser import parser
-
+
for var in (parse, parserinfo, parser):
assert var is not None
-
-
+
+
# Test that dateutil.relativedelta-related imports work properly
def test_import_relative_delta_direct():
import dateutil.relativedelta
-
-
+
+
def test_import_relative_delta_from():
from dateutil import relativedelta
-
+
def test_import_relative_delta_all():
from dateutil.relativedelta import relativedelta
from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
-
+
for var in (relativedelta, MO, TU, WE, TH, FR, SA, SU):
assert var is not None
-
+
# In the public interface but not in all
from dateutil.relativedelta import weekday
assert weekday is not None
-
-
+
+
# Test that dateutil.rrule related imports work properly
def test_import_rrule_direct():
import dateutil.rrule
-
-
+
+
def test_import_rrule_from():
from dateutil import rrule
-
-
+
+
def test_import_rrule_all():
from dateutil.rrule import rrule
from dateutil.rrule import rruleset
@@ -85,29 +85,29 @@ def test_import_rrule_all():
from dateutil.rrule import YEARLY, MONTHLY, WEEKLY, DAILY
from dateutil.rrule import HOURLY, MINUTELY, SECONDLY
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
-
+
rr_all = (rrule, rruleset, rrulestr,
YEARLY, MONTHLY, WEEKLY, DAILY,
HOURLY, MINUTELY, SECONDLY,
MO, TU, WE, TH, FR, SA, SU)
-
+
for var in rr_all:
assert var is not None
-
+
# In the public interface but not in all
from dateutil.rrule import weekday
assert weekday is not None
-
-
+
+
# Test that dateutil.tz related imports work properly
def test_import_tztest_direct():
import dateutil.tz
-
-
+
+
def test_import_tz_from():
from dateutil import tz
-
-
+
+
def test_import_tz_all():
from dateutil.tz import tzutc
from dateutil.tz import tzoffset
@@ -123,27 +123,27 @@ def test_import_tz_all():
from dateutil.tz import datetime_ambiguous
from dateutil.tz import datetime_exists
from dateutil.tz import resolve_imaginary
-
+
tz_all = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
"tzstr", "tzical", "gettz", "datetime_ambiguous",
"datetime_exists", "resolve_imaginary", "UTC"]
-
+
tz_all += ["tzwin", "tzwinlocal"] if sys.platform.startswith("win") else []
lvars = locals()
-
+
for var in tz_all:
assert lvars[var] is not None
-
+
# Test that dateutil.tzwin related imports work properly
@pytest.mark.skipif(not HOST_IS_WINDOWS, reason="Requires Windows")
def test_import_tz_windows_direct():
import dateutil.tzwin
-
-
+
+
@pytest.mark.skipif(not HOST_IS_WINDOWS, reason="Requires Windows")
def test_import_tz_windows_from():
from dateutil import tzwin
-
+
@pytest.mark.skipif(not HOST_IS_WINDOWS, reason="Requires Windows")
def test_import_tz_windows_star():
diff --git a/contrib/python/dateutil/dateutil/test/test_internals.py b/contrib/python/dateutil/dateutil/test/test_internals.py
index c96776f14d..530813147d 100644
--- a/contrib/python/dateutil/dateutil/test/test_internals.py
+++ b/contrib/python/dateutil/dateutil/test/test_internals.py
@@ -1,91 +1,91 @@
-# -*- coding: utf-8 -*-
-"""
-Tests for implementation details, not necessarily part of the user-facing
-API.
-
-The motivating case for these tests is #483, where we want to smoke-test
-code that may be difficult to reach through the standard API calls.
-"""
-
-import sys
-import pytest
-
-from dateutil.parser._parser import _ymd
-from dateutil import tz
-
-IS_PY32 = sys.version_info[0:2] == (3, 2)
-
-
+# -*- coding: utf-8 -*-
+"""
+Tests for implementation details, not necessarily part of the user-facing
+API.
+
+The motivating case for these tests is #483, where we want to smoke-test
+code that may be difficult to reach through the standard API calls.
+"""
+
+import sys
+import pytest
+
+from dateutil.parser._parser import _ymd
+from dateutil import tz
+
+IS_PY32 = sys.version_info[0:2] == (3, 2)
+
+
@pytest.mark.smoke
def test_YMD_could_be_day():
ymd = _ymd('foo bar 124 baz')
-
+
ymd.append(2, 'M')
assert ymd.has_month
assert not ymd.has_year
assert ymd.could_be_day(4)
assert not ymd.could_be_day(-6)
assert not ymd.could_be_day(32)
-
+
# Assumes leap year
assert ymd.could_be_day(29)
-
+
ymd.append(1999)
assert ymd.has_year
assert not ymd.could_be_day(29)
-
+
ymd.append(16, 'D')
assert ymd.has_day
assert not ymd.could_be_day(1)
-
+
ymd = _ymd('foo bar 124 baz')
ymd.append(1999)
assert ymd.could_be_day(31)
-
-
-###
-# Test that private interfaces in _parser are deprecated properly
-@pytest.mark.skipif(IS_PY32, reason='pytest.warns not supported on Python 3.2')
-def test_parser_private_warns():
- from dateutil.parser import _timelex, _tzparser
- from dateutil.parser import _parsetz
-
- with pytest.warns(DeprecationWarning):
- _tzparser()
-
- with pytest.warns(DeprecationWarning):
- _timelex('2014-03-03')
-
- with pytest.warns(DeprecationWarning):
- _parsetz('+05:00')
-
-
-@pytest.mark.skipif(IS_PY32, reason='pytest.warns not supported on Python 3.2')
-def test_parser_parser_private_not_warns():
- from dateutil.parser._parser import _timelex, _tzparser
- from dateutil.parser._parser import _parsetz
-
- with pytest.warns(None) as recorder:
- _tzparser()
- assert len(recorder) == 0
-
- with pytest.warns(None) as recorder:
- _timelex('2014-03-03')
-
- assert len(recorder) == 0
-
- with pytest.warns(None) as recorder:
- _parsetz('+05:00')
- assert len(recorder) == 0
-
-
-@pytest.mark.tzstr
-def test_tzstr_internal_timedeltas():
- with pytest.warns(tz.DeprecatedTzFormatWarning):
- tz1 = tz.tzstr("EST5EDT,5,4,0,7200,11,-3,0,7200")
-
- with pytest.warns(tz.DeprecatedTzFormatWarning):
- tz2 = tz.tzstr("EST5EDT,4,1,0,7200,10,-1,0,7200")
-
- assert tz1._start_delta != tz2._start_delta
- assert tz1._end_delta != tz2._end_delta
+
+
+###
+# Test that private interfaces in _parser are deprecated properly
+@pytest.mark.skipif(IS_PY32, reason='pytest.warns not supported on Python 3.2')
+def test_parser_private_warns():
+ from dateutil.parser import _timelex, _tzparser
+ from dateutil.parser import _parsetz
+
+ with pytest.warns(DeprecationWarning):
+ _tzparser()
+
+ with pytest.warns(DeprecationWarning):
+ _timelex('2014-03-03')
+
+ with pytest.warns(DeprecationWarning):
+ _parsetz('+05:00')
+
+
+@pytest.mark.skipif(IS_PY32, reason='pytest.warns not supported on Python 3.2')
+def test_parser_parser_private_not_warns():
+ from dateutil.parser._parser import _timelex, _tzparser
+ from dateutil.parser._parser import _parsetz
+
+ with pytest.warns(None) as recorder:
+ _tzparser()
+ assert len(recorder) == 0
+
+ with pytest.warns(None) as recorder:
+ _timelex('2014-03-03')
+
+ assert len(recorder) == 0
+
+ with pytest.warns(None) as recorder:
+ _parsetz('+05:00')
+ assert len(recorder) == 0
+
+
+@pytest.mark.tzstr
+def test_tzstr_internal_timedeltas():
+ with pytest.warns(tz.DeprecatedTzFormatWarning):
+ tz1 = tz.tzstr("EST5EDT,5,4,0,7200,11,-3,0,7200")
+
+ with pytest.warns(tz.DeprecatedTzFormatWarning):
+ tz2 = tz.tzstr("EST5EDT,4,1,0,7200,10,-1,0,7200")
+
+ assert tz1._start_delta != tz2._start_delta
+ assert tz1._end_delta != tz2._end_delta
diff --git a/contrib/python/dateutil/dateutil/test/test_isoparser.py b/contrib/python/dateutil/dateutil/test/test_isoparser.py
index d58bdae5a3..35899ab9b1 100644
--- a/contrib/python/dateutil/dateutil/test/test_isoparser.py
+++ b/contrib/python/dateutil/dateutil/test/test_isoparser.py
@@ -1,135 +1,135 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from datetime import datetime, timedelta, date, time
-import itertools as it
-
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from datetime import datetime, timedelta, date, time
+import itertools as it
+
from dateutil import tz
from dateutil.tz import UTC
-from dateutil.parser import isoparser, isoparse
-
-import pytest
-import six
-
-
-def _generate_tzoffsets(limited):
- def _mkoffset(hmtuple, fmt):
- h, m = hmtuple
- m_td = (-1 if h < 0 else 1) * m
-
- tzo = tz.tzoffset(None, timedelta(hours=h, minutes=m_td))
- return tzo, fmt.format(h, m)
-
- out = []
- if not limited:
- # The subset that's just hours
- hm_out_h = [(h, 0) for h in (-23, -5, 0, 5, 23)]
- out.extend([_mkoffset(hm, '{:+03d}') for hm in hm_out_h])
-
- # Ones that have hours and minutes
- hm_out = [] + hm_out_h
- hm_out += [(-12, 15), (11, 30), (10, 2), (5, 15), (-5, 30)]
- else:
- hm_out = [(-5, -0)]
-
- fmts = ['{:+03d}:{:02d}', '{:+03d}{:02d}']
- out += [_mkoffset(hm, fmt) for hm in hm_out for fmt in fmts]
-
- # Also add in UTC and naive
+from dateutil.parser import isoparser, isoparse
+
+import pytest
+import six
+
+
+def _generate_tzoffsets(limited):
+ def _mkoffset(hmtuple, fmt):
+ h, m = hmtuple
+ m_td = (-1 if h < 0 else 1) * m
+
+ tzo = tz.tzoffset(None, timedelta(hours=h, minutes=m_td))
+ return tzo, fmt.format(h, m)
+
+ out = []
+ if not limited:
+ # The subset that's just hours
+ hm_out_h = [(h, 0) for h in (-23, -5, 0, 5, 23)]
+ out.extend([_mkoffset(hm, '{:+03d}') for hm in hm_out_h])
+
+ # Ones that have hours and minutes
+ hm_out = [] + hm_out_h
+ hm_out += [(-12, 15), (11, 30), (10, 2), (5, 15), (-5, 30)]
+ else:
+ hm_out = [(-5, -0)]
+
+ fmts = ['{:+03d}:{:02d}', '{:+03d}{:02d}']
+ out += [_mkoffset(hm, fmt) for hm in hm_out for fmt in fmts]
+
+ # Also add in UTC and naive
out.append((UTC, 'Z'))
- out.append((None, ''))
-
- return out
-
-FULL_TZOFFSETS = _generate_tzoffsets(False)
-FULL_TZOFFSETS_AWARE = [x for x in FULL_TZOFFSETS if x[1]]
-TZOFFSETS = _generate_tzoffsets(True)
-
-DATES = [datetime(1996, 1, 1), datetime(2017, 1, 1)]
-@pytest.mark.parametrize('dt', tuple(DATES))
-def test_year_only(dt):
- dtstr = dt.strftime('%Y')
-
- assert isoparse(dtstr) == dt
-
-DATES += [datetime(2000, 2, 1), datetime(2017, 4, 1)]
-@pytest.mark.parametrize('dt', tuple(DATES))
-def test_year_month(dt):
- fmt = '%Y-%m'
- dtstr = dt.strftime(fmt)
-
- assert isoparse(dtstr) == dt
-
-DATES += [datetime(2016, 2, 29), datetime(2018, 3, 15)]
-YMD_FMTS = ('%Y%m%d', '%Y-%m-%d')
-@pytest.mark.parametrize('dt', tuple(DATES))
-@pytest.mark.parametrize('fmt', YMD_FMTS)
-def test_year_month_day(dt, fmt):
- dtstr = dt.strftime(fmt)
-
- assert isoparse(dtstr) == dt
-
-def _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset,
- microsecond_precision=None):
- tzi, offset_str = tzoffset
- fmt = date_fmt + 'T' + time_fmt
- dt = dt.replace(tzinfo=tzi)
- dtstr = dt.strftime(fmt)
-
- if microsecond_precision is not None:
+ out.append((None, ''))
+
+ return out
+
+FULL_TZOFFSETS = _generate_tzoffsets(False)
+FULL_TZOFFSETS_AWARE = [x for x in FULL_TZOFFSETS if x[1]]
+TZOFFSETS = _generate_tzoffsets(True)
+
+DATES = [datetime(1996, 1, 1), datetime(2017, 1, 1)]
+@pytest.mark.parametrize('dt', tuple(DATES))
+def test_year_only(dt):
+ dtstr = dt.strftime('%Y')
+
+ assert isoparse(dtstr) == dt
+
+DATES += [datetime(2000, 2, 1), datetime(2017, 4, 1)]
+@pytest.mark.parametrize('dt', tuple(DATES))
+def test_year_month(dt):
+ fmt = '%Y-%m'
+ dtstr = dt.strftime(fmt)
+
+ assert isoparse(dtstr) == dt
+
+DATES += [datetime(2016, 2, 29), datetime(2018, 3, 15)]
+YMD_FMTS = ('%Y%m%d', '%Y-%m-%d')
+@pytest.mark.parametrize('dt', tuple(DATES))
+@pytest.mark.parametrize('fmt', YMD_FMTS)
+def test_year_month_day(dt, fmt):
+ dtstr = dt.strftime(fmt)
+
+ assert isoparse(dtstr) == dt
+
+def _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset,
+ microsecond_precision=None):
+ tzi, offset_str = tzoffset
+ fmt = date_fmt + 'T' + time_fmt
+ dt = dt.replace(tzinfo=tzi)
+ dtstr = dt.strftime(fmt)
+
+ if microsecond_precision is not None:
if not fmt.endswith('%f'): # pragma: nocover
- raise ValueError('Time format has no microseconds!')
-
+ raise ValueError('Time format has no microseconds!')
+
if microsecond_precision != 6:
- dtstr = dtstr[:-(6 - microsecond_precision)]
+ dtstr = dtstr[:-(6 - microsecond_precision)]
elif microsecond_precision > 6: # pragma: nocover
raise ValueError('Precision must be 1-6')
-
- dtstr += offset_str
-
- assert isoparse(dtstr) == dt
-
-DATETIMES = [datetime(1998, 4, 16, 12),
- datetime(2019, 11, 18, 23),
- datetime(2014, 12, 16, 4)]
-@pytest.mark.parametrize('dt', tuple(DATETIMES))
-@pytest.mark.parametrize('date_fmt', YMD_FMTS)
-@pytest.mark.parametrize('tzoffset', TZOFFSETS)
-def test_ymd_h(dt, date_fmt, tzoffset):
- _isoparse_date_and_time(dt, date_fmt, '%H', tzoffset)
-
-DATETIMES = [datetime(2012, 1, 6, 9, 37)]
-@pytest.mark.parametrize('dt', tuple(DATETIMES))
-@pytest.mark.parametrize('date_fmt', YMD_FMTS)
-@pytest.mark.parametrize('time_fmt', ('%H%M', '%H:%M'))
-@pytest.mark.parametrize('tzoffset', TZOFFSETS)
-def test_ymd_hm(dt, date_fmt, time_fmt, tzoffset):
- _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
-
-DATETIMES = [datetime(2003, 9, 2, 22, 14, 2),
- datetime(2003, 8, 8, 14, 9, 14),
- datetime(2003, 4, 7, 6, 14, 59)]
-HMS_FMTS = ('%H%M%S', '%H:%M:%S')
-@pytest.mark.parametrize('dt', tuple(DATETIMES))
-@pytest.mark.parametrize('date_fmt', YMD_FMTS)
-@pytest.mark.parametrize('time_fmt', HMS_FMTS)
-@pytest.mark.parametrize('tzoffset', TZOFFSETS)
-def test_ymd_hms(dt, date_fmt, time_fmt, tzoffset):
- _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
-
-DATETIMES = [datetime(2017, 11, 27, 6, 14, 30, 123456)]
-@pytest.mark.parametrize('dt', tuple(DATETIMES))
-@pytest.mark.parametrize('date_fmt', YMD_FMTS)
+
+ dtstr += offset_str
+
+ assert isoparse(dtstr) == dt
+
+DATETIMES = [datetime(1998, 4, 16, 12),
+ datetime(2019, 11, 18, 23),
+ datetime(2014, 12, 16, 4)]
+@pytest.mark.parametrize('dt', tuple(DATETIMES))
+@pytest.mark.parametrize('date_fmt', YMD_FMTS)
+@pytest.mark.parametrize('tzoffset', TZOFFSETS)
+def test_ymd_h(dt, date_fmt, tzoffset):
+ _isoparse_date_and_time(dt, date_fmt, '%H', tzoffset)
+
+DATETIMES = [datetime(2012, 1, 6, 9, 37)]
+@pytest.mark.parametrize('dt', tuple(DATETIMES))
+@pytest.mark.parametrize('date_fmt', YMD_FMTS)
+@pytest.mark.parametrize('time_fmt', ('%H%M', '%H:%M'))
+@pytest.mark.parametrize('tzoffset', TZOFFSETS)
+def test_ymd_hm(dt, date_fmt, time_fmt, tzoffset):
+ _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
+
+DATETIMES = [datetime(2003, 9, 2, 22, 14, 2),
+ datetime(2003, 8, 8, 14, 9, 14),
+ datetime(2003, 4, 7, 6, 14, 59)]
+HMS_FMTS = ('%H%M%S', '%H:%M:%S')
+@pytest.mark.parametrize('dt', tuple(DATETIMES))
+@pytest.mark.parametrize('date_fmt', YMD_FMTS)
+@pytest.mark.parametrize('time_fmt', HMS_FMTS)
+@pytest.mark.parametrize('tzoffset', TZOFFSETS)
+def test_ymd_hms(dt, date_fmt, time_fmt, tzoffset):
+ _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
+
+DATETIMES = [datetime(2017, 11, 27, 6, 14, 30, 123456)]
+@pytest.mark.parametrize('dt', tuple(DATETIMES))
+@pytest.mark.parametrize('date_fmt', YMD_FMTS)
@pytest.mark.parametrize('time_fmt', (x + sep + '%f' for x in HMS_FMTS
for sep in '.,'))
-@pytest.mark.parametrize('tzoffset', TZOFFSETS)
-@pytest.mark.parametrize('precision', list(range(3, 7)))
-def test_ymd_hms_micro(dt, date_fmt, time_fmt, tzoffset, precision):
- # Truncate the microseconds to the desired precision for the representation
- dt = dt.replace(microsecond=int(round(dt.microsecond, precision-6)))
-
- _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset, precision)
-
+@pytest.mark.parametrize('tzoffset', TZOFFSETS)
+@pytest.mark.parametrize('precision', list(range(3, 7)))
+def test_ymd_hms_micro(dt, date_fmt, time_fmt, tzoffset, precision):
+ # Truncate the microseconds to the desired precision for the representation
+ dt = dt.replace(microsecond=int(round(dt.microsecond, precision-6)))
+
+ _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset, precision)
+
###
# Truncation of extra digits beyond microsecond precision
@pytest.mark.parametrize('dt_str', [
@@ -139,262 +139,262 @@ def test_ymd_hms_micro(dt, date_fmt, time_fmt, tzoffset, precision):
def test_extra_subsecond_digits(dt_str):
assert isoparse(dt_str) == datetime(2018, 7, 3, 14, 7, 0, 123456)
-@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS)
-def test_full_tzoffsets(tzoffset):
- dt = datetime(2017, 11, 27, 6, 14, 30, 123456)
- date_fmt = '%Y-%m-%d'
- time_fmt = '%H:%M:%S.%f'
-
- _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
-
-@pytest.mark.parametrize('dt_str', [
- '2014-04-11T00',
+@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS)
+def test_full_tzoffsets(tzoffset):
+ dt = datetime(2017, 11, 27, 6, 14, 30, 123456)
+ date_fmt = '%Y-%m-%d'
+ time_fmt = '%H:%M:%S.%f'
+
+ _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
+
+@pytest.mark.parametrize('dt_str', [
+ '2014-04-11T00',
'2014-04-10T24',
- '2014-04-11T00:00',
+ '2014-04-11T00:00',
'2014-04-10T24:00',
- '2014-04-11T00:00:00',
+ '2014-04-11T00:00:00',
'2014-04-10T24:00:00',
- '2014-04-11T00:00:00.000',
+ '2014-04-11T00:00:00.000',
'2014-04-10T24:00:00.000',
- '2014-04-11T00:00:00.000000',
+ '2014-04-11T00:00:00.000000',
'2014-04-10T24:00:00.000000']
-)
-def test_datetime_midnight(dt_str):
- assert isoparse(dt_str) == datetime(2014, 4, 11, 0, 0, 0, 0)
-
-@pytest.mark.parametrize('datestr', [
- '2014-01-01',
- '20140101',
-])
-@pytest.mark.parametrize('sep', [' ', 'a', 'T', '_', '-'])
-def test_isoparse_sep_none(datestr, sep):
- isostr = datestr + sep + '14:33:09'
- assert isoparse(isostr) == datetime(2014, 1, 1, 14, 33, 9)
-
-##
-# Uncommon date formats
-TIME_ARGS = ('time_args',
- ((None, time(0), None), ) + tuple(('%H:%M:%S.%f', _t, _tz)
- for _t, _tz in it.product([time(0), time(9, 30), time(14, 47)],
- TZOFFSETS)))
-
-@pytest.mark.parametrize('isocal,dt_expected',[
- ((2017, 10), datetime(2017, 3, 6)),
- ((2020, 1), datetime(2019, 12, 30)), # ISO year != Cal year
- ((2004, 53), datetime(2004, 12, 27)), # Only half the week is in 2014
-])
-def test_isoweek(isocal, dt_expected):
- # TODO: Figure out how to parametrize this on formats, too
- for fmt in ('{:04d}-W{:02d}', '{:04d}W{:02d}'):
- dtstr = fmt.format(*isocal)
- assert isoparse(dtstr) == dt_expected
-
-@pytest.mark.parametrize('isocal,dt_expected',[
- ((2016, 13, 7), datetime(2016, 4, 3)),
- ((2004, 53, 7), datetime(2005, 1, 2)), # ISO year != Cal year
- ((2009, 1, 2), datetime(2008, 12, 30)), # ISO year < Cal year
- ((2009, 53, 6), datetime(2010, 1, 2)) # ISO year > Cal year
-])
-def test_isoweek_day(isocal, dt_expected):
- # TODO: Figure out how to parametrize this on formats, too
- for fmt in ('{:04d}-W{:02d}-{:d}', '{:04d}W{:02d}{:d}'):
- dtstr = fmt.format(*isocal)
- assert isoparse(dtstr) == dt_expected
-
-@pytest.mark.parametrize('isoord,dt_expected', [
- ((2004, 1), datetime(2004, 1, 1)),
- ((2016, 60), datetime(2016, 2, 29)),
- ((2017, 60), datetime(2017, 3, 1)),
- ((2016, 366), datetime(2016, 12, 31)),
- ((2017, 365), datetime(2017, 12, 31))
-])
-def test_iso_ordinal(isoord, dt_expected):
- for fmt in ('{:04d}-{:03d}', '{:04d}{:03d}'):
- dtstr = fmt.format(*isoord)
-
- assert isoparse(dtstr) == dt_expected
-
-
-###
-# Acceptance of bytes
-@pytest.mark.parametrize('isostr,dt', [
- (b'2014', datetime(2014, 1, 1)),
- (b'20140204', datetime(2014, 2, 4)),
- (b'2014-02-04', datetime(2014, 2, 4)),
- (b'2014-02-04T12', datetime(2014, 2, 4, 12)),
- (b'2014-02-04T12:30', datetime(2014, 2, 4, 12, 30)),
- (b'2014-02-04T12:30:15', datetime(2014, 2, 4, 12, 30, 15)),
- (b'2014-02-04T12:30:15.224', datetime(2014, 2, 4, 12, 30, 15, 224000)),
- (b'20140204T123015.224', datetime(2014, 2, 4, 12, 30, 15, 224000)),
- (b'2014-02-04T12:30:15.224Z', datetime(2014, 2, 4, 12, 30, 15, 224000,
+)
+def test_datetime_midnight(dt_str):
+ assert isoparse(dt_str) == datetime(2014, 4, 11, 0, 0, 0, 0)
+
+@pytest.mark.parametrize('datestr', [
+ '2014-01-01',
+ '20140101',
+])
+@pytest.mark.parametrize('sep', [' ', 'a', 'T', '_', '-'])
+def test_isoparse_sep_none(datestr, sep):
+ isostr = datestr + sep + '14:33:09'
+ assert isoparse(isostr) == datetime(2014, 1, 1, 14, 33, 9)
+
+##
+# Uncommon date formats
+TIME_ARGS = ('time_args',
+ ((None, time(0), None), ) + tuple(('%H:%M:%S.%f', _t, _tz)
+ for _t, _tz in it.product([time(0), time(9, 30), time(14, 47)],
+ TZOFFSETS)))
+
+@pytest.mark.parametrize('isocal,dt_expected',[
+ ((2017, 10), datetime(2017, 3, 6)),
+ ((2020, 1), datetime(2019, 12, 30)), # ISO year != Cal year
+ ((2004, 53), datetime(2004, 12, 27)), # Only half the week is in 2014
+])
+def test_isoweek(isocal, dt_expected):
+ # TODO: Figure out how to parametrize this on formats, too
+ for fmt in ('{:04d}-W{:02d}', '{:04d}W{:02d}'):
+ dtstr = fmt.format(*isocal)
+ assert isoparse(dtstr) == dt_expected
+
+@pytest.mark.parametrize('isocal,dt_expected',[
+ ((2016, 13, 7), datetime(2016, 4, 3)),
+ ((2004, 53, 7), datetime(2005, 1, 2)), # ISO year != Cal year
+ ((2009, 1, 2), datetime(2008, 12, 30)), # ISO year < Cal year
+ ((2009, 53, 6), datetime(2010, 1, 2)) # ISO year > Cal year
+])
+def test_isoweek_day(isocal, dt_expected):
+ # TODO: Figure out how to parametrize this on formats, too
+ for fmt in ('{:04d}-W{:02d}-{:d}', '{:04d}W{:02d}{:d}'):
+ dtstr = fmt.format(*isocal)
+ assert isoparse(dtstr) == dt_expected
+
+@pytest.mark.parametrize('isoord,dt_expected', [
+ ((2004, 1), datetime(2004, 1, 1)),
+ ((2016, 60), datetime(2016, 2, 29)),
+ ((2017, 60), datetime(2017, 3, 1)),
+ ((2016, 366), datetime(2016, 12, 31)),
+ ((2017, 365), datetime(2017, 12, 31))
+])
+def test_iso_ordinal(isoord, dt_expected):
+ for fmt in ('{:04d}-{:03d}', '{:04d}{:03d}'):
+ dtstr = fmt.format(*isoord)
+
+ assert isoparse(dtstr) == dt_expected
+
+
+###
+# Acceptance of bytes
+@pytest.mark.parametrize('isostr,dt', [
+ (b'2014', datetime(2014, 1, 1)),
+ (b'20140204', datetime(2014, 2, 4)),
+ (b'2014-02-04', datetime(2014, 2, 4)),
+ (b'2014-02-04T12', datetime(2014, 2, 4, 12)),
+ (b'2014-02-04T12:30', datetime(2014, 2, 4, 12, 30)),
+ (b'2014-02-04T12:30:15', datetime(2014, 2, 4, 12, 30, 15)),
+ (b'2014-02-04T12:30:15.224', datetime(2014, 2, 4, 12, 30, 15, 224000)),
+ (b'20140204T123015.224', datetime(2014, 2, 4, 12, 30, 15, 224000)),
+ (b'2014-02-04T12:30:15.224Z', datetime(2014, 2, 4, 12, 30, 15, 224000,
UTC)),
(b'2014-02-04T12:30:15.224z', datetime(2014, 2, 4, 12, 30, 15, 224000,
UTC)),
- (b'2014-02-04T12:30:15.224+05:00',
- datetime(2014, 2, 4, 12, 30, 15, 224000,
- tzinfo=tz.tzoffset(None, timedelta(hours=5))))])
-def test_bytes(isostr, dt):
- assert isoparse(isostr) == dt
-
-
-###
-# Invalid ISO strings
-@pytest.mark.parametrize('isostr,exception', [
- ('201', ValueError), # ISO string too short
- ('2012-0425', ValueError), # Inconsistent date separators
- ('201204-25', ValueError), # Inconsistent date separators
- ('20120425T0120:00', ValueError), # Inconsistent time separators
+ (b'2014-02-04T12:30:15.224+05:00',
+ datetime(2014, 2, 4, 12, 30, 15, 224000,
+ tzinfo=tz.tzoffset(None, timedelta(hours=5))))])
+def test_bytes(isostr, dt):
+ assert isoparse(isostr) == dt
+
+
+###
+# Invalid ISO strings
+@pytest.mark.parametrize('isostr,exception', [
+ ('201', ValueError), # ISO string too short
+ ('2012-0425', ValueError), # Inconsistent date separators
+ ('201204-25', ValueError), # Inconsistent date separators
+ ('20120425T0120:00', ValueError), # Inconsistent time separators
('20120425T01:2000', ValueError), # Inconsistent time separators
('14:3015', ValueError), # Inconsistent time separator
- ('20120425T012500-334', ValueError), # Wrong microsecond separator
- ('2001-1', ValueError), # YYYY-M not valid
- ('2012-04-9', ValueError), # YYYY-MM-D not valid
- ('201204', ValueError), # YYYYMM not valid
- ('20120411T03:30+', ValueError), # Time zone too short
- ('20120411T03:30+1234567', ValueError), # Time zone too long
- ('20120411T03:30-25:40', ValueError), # Time zone invalid
- ('2012-1a', ValueError), # Invalid month
- ('20120411T03:30+00:60', ValueError), # Time zone invalid minutes
- ('20120411T03:30+00:61', ValueError), # Time zone invalid minutes
- ('20120411T033030.123456012:00', # No sign in time zone
- ValueError),
- ('2012-W00', ValueError), # Invalid ISO week
- ('2012-W55', ValueError), # Invalid ISO week
- ('2012-W01-0', ValueError), # Invalid ISO week day
- ('2012-W01-8', ValueError), # Invalid ISO week day
- ('2013-000', ValueError), # Invalid ordinal day
- ('2013-366', ValueError), # Invalid ordinal day
- ('2013366', ValueError), # Invalid ordinal day
- ('2014-03-12Т12:30:14', ValueError), # Cyrillic T
- ('2014-04-21T24:00:01', ValueError), # Invalid use of 24 for midnight
- ('2014_W01-1', ValueError), # Invalid separator
- ('2014W01-1', ValueError), # Inconsistent use of dashes
- ('2014-W011', ValueError), # Inconsistent use of dashes
-
-])
-def test_iso_raises(isostr, exception):
- with pytest.raises(exception):
- isoparse(isostr)
-
-
+ ('20120425T012500-334', ValueError), # Wrong microsecond separator
+ ('2001-1', ValueError), # YYYY-M not valid
+ ('2012-04-9', ValueError), # YYYY-MM-D not valid
+ ('201204', ValueError), # YYYYMM not valid
+ ('20120411T03:30+', ValueError), # Time zone too short
+ ('20120411T03:30+1234567', ValueError), # Time zone too long
+ ('20120411T03:30-25:40', ValueError), # Time zone invalid
+ ('2012-1a', ValueError), # Invalid month
+ ('20120411T03:30+00:60', ValueError), # Time zone invalid minutes
+ ('20120411T03:30+00:61', ValueError), # Time zone invalid minutes
+ ('20120411T033030.123456012:00', # No sign in time zone
+ ValueError),
+ ('2012-W00', ValueError), # Invalid ISO week
+ ('2012-W55', ValueError), # Invalid ISO week
+ ('2012-W01-0', ValueError), # Invalid ISO week day
+ ('2012-W01-8', ValueError), # Invalid ISO week day
+ ('2013-000', ValueError), # Invalid ordinal day
+ ('2013-366', ValueError), # Invalid ordinal day
+ ('2013366', ValueError), # Invalid ordinal day
+ ('2014-03-12Т12:30:14', ValueError), # Cyrillic T
+ ('2014-04-21T24:00:01', ValueError), # Invalid use of 24 for midnight
+ ('2014_W01-1', ValueError), # Invalid separator
+ ('2014W01-1', ValueError), # Inconsistent use of dashes
+ ('2014-W011', ValueError), # Inconsistent use of dashes
+
+])
+def test_iso_raises(isostr, exception):
+ with pytest.raises(exception):
+ isoparse(isostr)
+
+
@pytest.mark.parametrize('sep_act, valid_sep, exception', [
('T', 'C', ValueError),
('C', 'T', ValueError),
-])
+])
def test_iso_with_sep_raises(sep_act, valid_sep, exception):
parser = isoparser(sep=valid_sep)
- isostr = '2012-04-25' + sep_act + '01:25:00'
+ isostr = '2012-04-25' + sep_act + '01:25:00'
with pytest.raises(exception):
parser.isoparse(isostr)
-
-
-###
-# Test ISOParser constructor
-@pytest.mark.parametrize('sep', [' ', '9', '🍛'])
-def test_isoparser_invalid_sep(sep):
- with pytest.raises(ValueError):
- isoparser(sep=sep)
-
-
-# This only fails on Python 3
+
+
+###
+# Test ISOParser constructor
+@pytest.mark.parametrize('sep', [' ', '9', '🍛'])
+def test_isoparser_invalid_sep(sep):
+ with pytest.raises(ValueError):
+ isoparser(sep=sep)
+
+
+# This only fails on Python 3
@pytest.mark.xfail(not six.PY2, reason="Fails on Python 3 only")
-def test_isoparser_byte_sep():
- dt = datetime(2017, 12, 6, 12, 30, 45)
- dt_str = dt.isoformat(sep=str('T'))
-
- dt_rt = isoparser(sep=b'T').isoparse(dt_str)
-
- assert dt == dt_rt
-
-
-###
-# Test parse_tzstr
-@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS)
-def test_parse_tzstr(tzoffset):
- dt = datetime(2017, 11, 27, 6, 14, 30, 123456)
- date_fmt = '%Y-%m-%d'
- time_fmt = '%H:%M:%S.%f'
-
- _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
-
-
-@pytest.mark.parametrize('tzstr', [
- '-00:00', '+00:00', '+00', '-00', '+0000', '-0000'
-])
-@pytest.mark.parametrize('zero_as_utc', [True, False])
-def test_parse_tzstr_zero_as_utc(tzstr, zero_as_utc):
- tzi = isoparser().parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
+def test_isoparser_byte_sep():
+ dt = datetime(2017, 12, 6, 12, 30, 45)
+ dt_str = dt.isoformat(sep=str('T'))
+
+ dt_rt = isoparser(sep=b'T').isoparse(dt_str)
+
+ assert dt == dt_rt
+
+
+###
+# Test parse_tzstr
+@pytest.mark.parametrize('tzoffset', FULL_TZOFFSETS)
+def test_parse_tzstr(tzoffset):
+ dt = datetime(2017, 11, 27, 6, 14, 30, 123456)
+ date_fmt = '%Y-%m-%d'
+ time_fmt = '%H:%M:%S.%f'
+
+ _isoparse_date_and_time(dt, date_fmt, time_fmt, tzoffset)
+
+
+@pytest.mark.parametrize('tzstr', [
+ '-00:00', '+00:00', '+00', '-00', '+0000', '-0000'
+])
+@pytest.mark.parametrize('zero_as_utc', [True, False])
+def test_parse_tzstr_zero_as_utc(tzstr, zero_as_utc):
+ tzi = isoparser().parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
assert tzi == UTC
- assert (type(tzi) == tz.tzutc) == zero_as_utc
-
-
-@pytest.mark.parametrize('tzstr,exception', [
- ('00:00', ValueError), # No sign
- ('05:00', ValueError), # No sign
- ('_00:00', ValueError), # Invalid sign
- ('+25:00', ValueError), # Offset too large
- ('00:0000', ValueError), # String too long
-])
-def test_parse_tzstr_fails(tzstr, exception):
- with pytest.raises(exception):
- isoparser().parse_tzstr(tzstr)
-
-###
-# Test parse_isodate
-def __make_date_examples():
- dates_no_day = [
- date(1999, 12, 1),
- date(2016, 2, 1)
- ]
-
+ assert (type(tzi) == tz.tzutc) == zero_as_utc
+
+
+@pytest.mark.parametrize('tzstr,exception', [
+ ('00:00', ValueError), # No sign
+ ('05:00', ValueError), # No sign
+ ('_00:00', ValueError), # Invalid sign
+ ('+25:00', ValueError), # Offset too large
+ ('00:0000', ValueError), # String too long
+])
+def test_parse_tzstr_fails(tzstr, exception):
+ with pytest.raises(exception):
+ isoparser().parse_tzstr(tzstr)
+
+###
+# Test parse_isodate
+def __make_date_examples():
+ dates_no_day = [
+ date(1999, 12, 1),
+ date(2016, 2, 1)
+ ]
+
if not six.PY2:
- # strftime does not support dates before 1900 in Python 2
- dates_no_day.append(date(1000, 11, 1))
-
- # Only one supported format for dates with no day
- o = zip(dates_no_day, it.repeat('%Y-%m'))
-
- dates_w_day = [
- date(1969, 12, 31),
- date(1900, 1, 1),
- date(2016, 2, 29),
- date(2017, 11, 14)
- ]
-
- dates_w_day_fmts = ('%Y%m%d', '%Y-%m-%d')
- o = it.chain(o, it.product(dates_w_day, dates_w_day_fmts))
-
- return list(o)
-
-
-@pytest.mark.parametrize('d,dt_fmt', __make_date_examples())
-@pytest.mark.parametrize('as_bytes', [True, False])
-def test_parse_isodate(d, dt_fmt, as_bytes):
- d_str = d.strftime(dt_fmt)
- if isinstance(d_str, six.text_type) and as_bytes:
- d_str = d_str.encode('ascii')
+ # strftime does not support dates before 1900 in Python 2
+ dates_no_day.append(date(1000, 11, 1))
+
+ # Only one supported format for dates with no day
+ o = zip(dates_no_day, it.repeat('%Y-%m'))
+
+ dates_w_day = [
+ date(1969, 12, 31),
+ date(1900, 1, 1),
+ date(2016, 2, 29),
+ date(2017, 11, 14)
+ ]
+
+ dates_w_day_fmts = ('%Y%m%d', '%Y-%m-%d')
+ o = it.chain(o, it.product(dates_w_day, dates_w_day_fmts))
+
+ return list(o)
+
+
+@pytest.mark.parametrize('d,dt_fmt', __make_date_examples())
+@pytest.mark.parametrize('as_bytes', [True, False])
+def test_parse_isodate(d, dt_fmt, as_bytes):
+ d_str = d.strftime(dt_fmt)
+ if isinstance(d_str, six.text_type) and as_bytes:
+ d_str = d_str.encode('ascii')
elif isinstance(d_str, bytes) and not as_bytes:
- d_str = d_str.decode('ascii')
-
- iparser = isoparser()
- assert iparser.parse_isodate(d_str) == d
-
-
-@pytest.mark.parametrize('isostr,exception', [
- ('243', ValueError), # ISO string too short
- ('2014-0423', ValueError), # Inconsistent date separators
- ('201404-23', ValueError), # Inconsistent date separators
- ('2014日03月14', ValueError), # Not ASCII
- ('2013-02-29', ValueError), # Not a leap year
- ('2014/12/03', ValueError), # Wrong separators
- ('2014-04-19T', ValueError), # Unknown components
+ d_str = d_str.decode('ascii')
+
+ iparser = isoparser()
+ assert iparser.parse_isodate(d_str) == d
+
+
+@pytest.mark.parametrize('isostr,exception', [
+ ('243', ValueError), # ISO string too short
+ ('2014-0423', ValueError), # Inconsistent date separators
+ ('201404-23', ValueError), # Inconsistent date separators
+ ('2014日03月14', ValueError), # Not ASCII
+ ('2013-02-29', ValueError), # Not a leap year
+ ('2014/12/03', ValueError), # Wrong separators
+ ('2014-04-19T', ValueError), # Unknown components
('201202', ValueError), # Invalid format
-])
-def test_isodate_raises(isostr, exception):
- with pytest.raises(exception):
- isoparser().parse_isodate(isostr)
-
-
+])
+def test_isodate_raises(isostr, exception):
+ with pytest.raises(exception):
+ isoparser().parse_isodate(isostr)
+
+
def test_parse_isodate_error_text():
with pytest.raises(ValueError) as excinfo:
isoparser().parse_isodate('2014-0423')
@@ -407,66 +407,66 @@ def test_parse_isodate_error_text():
assert expected_error == str(excinfo.value)
-###
-# Test parse_isotime
-def __make_time_examples():
- outputs = []
-
- # HH
- time_h = [time(0), time(8), time(22)]
- time_h_fmts = ['%H']
-
- outputs.append(it.product(time_h, time_h_fmts))
-
- # HHMM / HH:MM
- time_hm = [time(0, 0), time(0, 30), time(8, 47), time(16, 1)]
- time_hm_fmts = ['%H%M', '%H:%M']
-
- outputs.append(it.product(time_hm, time_hm_fmts))
-
- # HHMMSS / HH:MM:SS
- time_hms = [time(0, 0, 0), time(0, 15, 30),
- time(8, 2, 16), time(12, 0), time(16, 2), time(20, 45)]
-
- time_hms_fmts = ['%H%M%S', '%H:%M:%S']
-
- outputs.append(it.product(time_hms, time_hms_fmts))
-
- # HHMMSS.ffffff / HH:MM:SS.ffffff
- time_hmsu = [time(0, 0, 0, 0), time(4, 15, 3, 247993),
- time(14, 21, 59, 948730),
- time(23, 59, 59, 999999)]
-
- time_hmsu_fmts = ['%H%M%S.%f', '%H:%M:%S.%f']
-
- outputs.append(it.product(time_hmsu, time_hmsu_fmts))
-
- outputs = list(map(list, outputs))
-
- # Time zones
- ex_naive = list(it.chain.from_iterable(x[0:2] for x in outputs))
- o = it.product(ex_naive, TZOFFSETS) # ((time, fmt), (tzinfo, offsetstr))
- o = ((t.replace(tzinfo=tzi), fmt + off_str)
- for (t, fmt), (tzi, off_str) in o)
-
- outputs.append(o)
-
- return list(it.chain.from_iterable(outputs))
-
-
-@pytest.mark.parametrize('time_val,time_fmt', __make_time_examples())
-@pytest.mark.parametrize('as_bytes', [True, False])
-def test_isotime(time_val, time_fmt, as_bytes):
- tstr = time_val.strftime(time_fmt)
+###
+# Test parse_isotime
+def __make_time_examples():
+ outputs = []
+
+ # HH
+ time_h = [time(0), time(8), time(22)]
+ time_h_fmts = ['%H']
+
+ outputs.append(it.product(time_h, time_h_fmts))
+
+ # HHMM / HH:MM
+ time_hm = [time(0, 0), time(0, 30), time(8, 47), time(16, 1)]
+ time_hm_fmts = ['%H%M', '%H:%M']
+
+ outputs.append(it.product(time_hm, time_hm_fmts))
+
+ # HHMMSS / HH:MM:SS
+ time_hms = [time(0, 0, 0), time(0, 15, 30),
+ time(8, 2, 16), time(12, 0), time(16, 2), time(20, 45)]
+
+ time_hms_fmts = ['%H%M%S', '%H:%M:%S']
+
+ outputs.append(it.product(time_hms, time_hms_fmts))
+
+ # HHMMSS.ffffff / HH:MM:SS.ffffff
+ time_hmsu = [time(0, 0, 0, 0), time(4, 15, 3, 247993),
+ time(14, 21, 59, 948730),
+ time(23, 59, 59, 999999)]
+
+ time_hmsu_fmts = ['%H%M%S.%f', '%H:%M:%S.%f']
+
+ outputs.append(it.product(time_hmsu, time_hmsu_fmts))
+
+ outputs = list(map(list, outputs))
+
+ # Time zones
+ ex_naive = list(it.chain.from_iterable(x[0:2] for x in outputs))
+ o = it.product(ex_naive, TZOFFSETS) # ((time, fmt), (tzinfo, offsetstr))
+ o = ((t.replace(tzinfo=tzi), fmt + off_str)
+ for (t, fmt), (tzi, off_str) in o)
+
+ outputs.append(o)
+
+ return list(it.chain.from_iterable(outputs))
+
+
+@pytest.mark.parametrize('time_val,time_fmt', __make_time_examples())
+@pytest.mark.parametrize('as_bytes', [True, False])
+def test_isotime(time_val, time_fmt, as_bytes):
+ tstr = time_val.strftime(time_fmt)
if isinstance(tstr, six.text_type) and as_bytes:
- tstr = tstr.encode('ascii')
+ tstr = tstr.encode('ascii')
elif isinstance(tstr, bytes) and not as_bytes:
- tstr = tstr.decode('ascii')
-
- iparser = isoparser()
-
- assert iparser.parse_isotime(tstr) == time_val
-
+ tstr = tstr.decode('ascii')
+
+ iparser = isoparser()
+
+ assert iparser.parse_isotime(tstr) == time_val
+
@pytest.mark.parametrize('isostr', [
'24:00',
@@ -483,27 +483,27 @@ def test_isotime_midnight(isostr):
assert iparser.parse_isotime(isostr) == time(0, 0, 0, 0)
-@pytest.mark.parametrize('isostr,exception', [
- ('3', ValueError), # ISO string too short
- ('14時30分15秒', ValueError), # Not ASCII
- ('14_30_15', ValueError), # Invalid separators
- ('1430:15', ValueError), # Inconsistent separator use
- ('25', ValueError), # Invalid hours
- ('25:15', ValueError), # Invalid hours
- ('14:60', ValueError), # Invalid minutes
- ('14:59:61', ValueError), # Invalid seconds
+@pytest.mark.parametrize('isostr,exception', [
+ ('3', ValueError), # ISO string too short
+ ('14時30分15秒', ValueError), # Not ASCII
+ ('14_30_15', ValueError), # Invalid separators
+ ('1430:15', ValueError), # Inconsistent separator use
+ ('25', ValueError), # Invalid hours
+ ('25:15', ValueError), # Invalid hours
+ ('14:60', ValueError), # Invalid minutes
+ ('14:59:61', ValueError), # Invalid seconds
('14:30:15.34468305:00', ValueError), # No sign in time zone
- ('14:30:15+', ValueError), # Time zone too short
- ('14:30:15+1234567', ValueError), # Time zone invalid
- ('14:59:59+25:00', ValueError), # Invalid tz hours
- ('14:59:59+12:62', ValueError), # Invalid tz minutes
- ('14:59:30_344583', ValueError), # Invalid microsecond separator
+ ('14:30:15+', ValueError), # Time zone too short
+ ('14:30:15+1234567', ValueError), # Time zone invalid
+ ('14:59:59+25:00', ValueError), # Invalid tz hours
+ ('14:59:59+12:62', ValueError), # Invalid tz minutes
+ ('14:59:30_344583', ValueError), # Invalid microsecond separator
('24:01', ValueError), # 24 used for non-midnight time
('24:00:01', ValueError), # 24 used for non-midnight time
('24:00:00.001', ValueError), # 24 used for non-midnight time
('24:00:00.000001', ValueError), # 24 used for non-midnight time
-])
-def test_isotime_raises(isostr, exception):
- iparser = isoparser()
- with pytest.raises(exception):
- iparser.parse_isotime(isostr)
+])
+def test_isotime_raises(isostr, exception):
+ iparser = isoparser()
+ with pytest.raises(exception):
+ iparser.parse_isotime(isostr)
diff --git a/contrib/python/dateutil/dateutil/test/test_parser.py b/contrib/python/dateutil/dateutil/test/test_parser.py
index bfdb7b1aeb..08a34dafbc 100644
--- a/contrib/python/dateutil/dateutil/test/test_parser.py
+++ b/contrib/python/dateutil/dateutil/test/test_parser.py
@@ -1,34 +1,34 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-import itertools
-from datetime import datetime, timedelta
-import unittest
-import sys
-
-from dateutil import tz
-from dateutil.tz import tzoffset
-from dateutil.parser import parse, parserinfo
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import itertools
+from datetime import datetime, timedelta
+import unittest
+import sys
+
+from dateutil import tz
+from dateutil.tz import tzoffset
+from dateutil.parser import parse, parserinfo
from dateutil.parser import ParserError
-from dateutil.parser import UnknownTimezoneWarning
-
-from ._common import TZEnvContext
-
+from dateutil.parser import UnknownTimezoneWarning
+
+from ._common import TZEnvContext
+
from six import assertRaisesRegex, PY2
from io import StringIO
-
-import pytest
-
-# Platform info
-IS_WIN = sys.platform.startswith('win')
-
+
+import pytest
+
+# Platform info
+IS_WIN = sys.platform.startswith('win')
+
PLATFORM_HAS_DASH_D = False
-try:
+try:
if datetime.now().strftime('%-d'):
PLATFORM_HAS_DASH_D = True
-except ValueError:
+except ValueError:
pass
-
+
@pytest.fixture(params=[True, False])
def fuzzy(request):
@@ -103,7 +103,7 @@ PARSER_TEST_CASES = [
]
# Check that we don't have any duplicates
assert len(set([x[0] for x in PARSER_TEST_CASES])) == len(PARSER_TEST_CASES)
-
+
@pytest.mark.parametrize("parsable_text,expected_datetime,assertion_message", PARSER_TEST_CASES)
def test_parser(parsable_text, expected_datetime, assertion_message):
@@ -174,7 +174,7 @@ def test_parse_dayfirst(sep):
dstr = expected.strftime(fmt)
result = parse(dstr, dayfirst=True)
assert result == expected
-
+
@pytest.mark.parametrize('sep', ['-', '.', '/', ' '])
def test_parse_yearfirst(sep):
@@ -225,31 +225,31 @@ def test_parse_with_tzoffset(dstr, expected):
class TestFormat(object):
- def test_ybd(self):
- # If we have a 4-digit year, a non-numeric month (abbreviated or not),
- # and a day (1 or 2 digits), then there is no ambiguity as to which
- # token is a year/month/day. This holds regardless of what order the
- # terms are in and for each of the separators below.
-
- seps = ['-', ' ', '/', '.']
-
- year_tokens = ['%Y']
- month_tokens = ['%b', '%B']
- day_tokens = ['%d']
- if PLATFORM_HAS_DASH_D:
- day_tokens.append('%-d')
-
- prods = itertools.product(year_tokens, month_tokens, day_tokens)
- perms = [y for x in prods for y in itertools.permutations(x)]
- unambig_fmts = [sep.join(perm) for sep in seps for perm in perms]
-
- actual = datetime(2003, 9, 25)
-
- for fmt in unambig_fmts:
- dstr = actual.strftime(fmt)
- res = parse(dstr)
+ def test_ybd(self):
+ # If we have a 4-digit year, a non-numeric month (abbreviated or not),
+ # and a day (1 or 2 digits), then there is no ambiguity as to which
+ # token is a year/month/day. This holds regardless of what order the
+ # terms are in and for each of the separators below.
+
+ seps = ['-', ' ', '/', '.']
+
+ year_tokens = ['%Y']
+ month_tokens = ['%b', '%B']
+ day_tokens = ['%d']
+ if PLATFORM_HAS_DASH_D:
+ day_tokens.append('%-d')
+
+ prods = itertools.product(year_tokens, month_tokens, day_tokens)
+ perms = [y for x in prods for y in itertools.permutations(x)]
+ unambig_fmts = [sep.join(perm) for sep in seps for perm in perms]
+
+ actual = datetime(2003, 9, 25)
+
+ for fmt in unambig_fmts:
+ dstr = actual.strftime(fmt)
+ res = parse(dstr)
assert res == actual
-
+
# TODO: some redundancy with PARSER_TEST_CASES cases
@pytest.mark.parametrize("fmt,dstr", [
("%a %b %d %Y", "Thu Sep 25 2003"),
@@ -282,7 +282,7 @@ class TestFormat(object):
])
def test_strftime_formats_2003Sep25(self, fmt, dstr):
expected = datetime(2003, 9, 25)
-
+
# First check that the format strings behave as expected
# (not strictly necessary, but nice to have)
assert expected.strftime(fmt) == dstr
@@ -294,54 +294,54 @@ class TestFormat(object):
class TestInputTypes(object):
def test_empty_string_invalid(self):
with pytest.raises(ParserError):
- parse('')
-
+ parse('')
+
def test_none_invalid(self):
with pytest.raises(TypeError):
- parse(None)
-
+ parse(None)
+
def test_int_invalid(self):
with pytest.raises(TypeError):
- parse(13)
-
+ parse(13)
+
def test_duck_typing(self):
- # We want to support arbitrary classes that implement the stream
- # interface.
-
- class StringPassThrough(object):
- def __init__(self, stream):
- self.stream = stream
-
- def read(self, *args, **kwargs):
- return self.stream.read(*args, **kwargs)
-
- dstr = StringPassThrough(StringIO('2014 January 19'))
-
+ # We want to support arbitrary classes that implement the stream
+ # interface.
+
+ class StringPassThrough(object):
+ def __init__(self, stream):
+ self.stream = stream
+
+ def read(self, *args, **kwargs):
+ return self.stream.read(*args, **kwargs)
+
+ dstr = StringPassThrough(StringIO('2014 January 19'))
+
res = parse(dstr)
expected = datetime(2014, 1, 19)
assert res == expected
-
+
def test_parse_stream(self):
- dstr = StringIO('2014 January 19')
-
+ dstr = StringIO('2014 January 19')
+
res = parse(dstr)
expected = datetime(2014, 1, 19)
assert res == expected
-
+
def test_parse_str(self):
# Parser should be able to handle bytestring and unicode
uni_str = '2014-05-01 08:00:00'
bytes_str = uni_str.encode()
-
+
res = parse(bytes_str)
expected = parse(uni_str)
assert res == expected
-
+
def test_parse_bytes(self):
res = parse(b'2014 January 19')
expected = datetime(2014, 1, 19)
assert res == expected
-
+
def test_parse_bytearray(self):
# GH#417
res = parse(bytearray(b'2014 January 19'))
@@ -417,315 +417,315 @@ class ParserTest(unittest.TestCase):
cls.uni_str = '2014-05-01 08:00:00'
cls.str_str = cls.uni_str.encode()
- def testParserParseStr(self):
- from dateutil.parser import parser
-
+ def testParserParseStr(self):
+ from dateutil.parser import parser
+
assert parser().parse(self.str_str) == parser().parse(self.uni_str)
-
- def testParseUnicodeWords(self):
-
- class rus_parserinfo(parserinfo):
- MONTHS = [("янв", "Январь"),
- ("фев", "Февраль"),
- ("мар", "Март"),
- ("апр", "Апрель"),
- ("май", "Май"),
- ("июн", "Июнь"),
- ("июл", "Июль"),
- ("авг", "Август"),
- ("сен", "Сентябрь"),
- ("окт", "Октябрь"),
- ("ноя", "Ноябрь"),
- ("дек", "Декабрь")]
-
+
+ def testParseUnicodeWords(self):
+
+ class rus_parserinfo(parserinfo):
+ MONTHS = [("янв", "Январь"),
+ ("фев", "Февраль"),
+ ("мар", "Март"),
+ ("апр", "Апрель"),
+ ("май", "Май"),
+ ("июн", "Июнь"),
+ ("июл", "Июль"),
+ ("авг", "Август"),
+ ("сен", "Сентябрь"),
+ ("окт", "Октябрь"),
+ ("ноя", "Ноябрь"),
+ ("дек", "Декабрь")]
+
expected = datetime(2015, 9, 10, 10, 20)
res = parse('10 Сентябрь 2015 10:20', parserinfo=rus_parserinfo())
assert res == expected
-
- def testParseWithNulls(self):
- # This relies on the from __future__ import unicode_literals, because
- # explicitly specifying a unicode literal is a syntax error in Py 3.2
- # May want to switch to u'...' if we ever drop Python 3.2 support.
- pstring = '\x00\x00August 29, 1924'
-
+
+ def testParseWithNulls(self):
+ # This relies on the from __future__ import unicode_literals, because
+ # explicitly specifying a unicode literal is a syntax error in Py 3.2
+ # May want to switch to u'...' if we ever drop Python 3.2 support.
+ pstring = '\x00\x00August 29, 1924'
+
assert parse(pstring) == datetime(1924, 8, 29)
-
- def testDateCommandFormat(self):
- self.assertEqual(parse("Thu Sep 25 10:36:28 BRST 2003",
- tzinfos=self.tzinfos),
- datetime(2003, 9, 25, 10, 36, 28,
- tzinfo=self.brsttz))
-
- def testDateCommandFormatReversed(self):
- self.assertEqual(parse("2003 10:36:28 BRST 25 Sep Thu",
- tzinfos=self.tzinfos),
- datetime(2003, 9, 25, 10, 36, 28,
- tzinfo=self.brsttz))
-
- def testDateCommandFormatWithLong(self):
+
+ def testDateCommandFormat(self):
+ self.assertEqual(parse("Thu Sep 25 10:36:28 BRST 2003",
+ tzinfos=self.tzinfos),
+ datetime(2003, 9, 25, 10, 36, 28,
+ tzinfo=self.brsttz))
+
+ def testDateCommandFormatReversed(self):
+ self.assertEqual(parse("2003 10:36:28 BRST 25 Sep Thu",
+ tzinfos=self.tzinfos),
+ datetime(2003, 9, 25, 10, 36, 28,
+ tzinfo=self.brsttz))
+
+ def testDateCommandFormatWithLong(self):
if PY2:
- self.assertEqual(parse("Thu Sep 25 10:36:28 BRST 2003",
- tzinfos={"BRST": long(-10800)}),
- datetime(2003, 9, 25, 10, 36, 28,
- tzinfo=self.brsttz))
+ self.assertEqual(parse("Thu Sep 25 10:36:28 BRST 2003",
+ tzinfos={"BRST": long(-10800)}),
+ datetime(2003, 9, 25, 10, 36, 28,
+ tzinfo=self.brsttz))
- def testISOFormatStrip2(self):
+ def testISOFormatStrip2(self):
self.assertEqual(parse("2003-09-25T10:49:41+03:00"),
datetime(2003, 9, 25, 10, 49, 41,
tzinfo=tzoffset(None, 10800)))
-
- def testISOStrippedFormatStrip2(self):
+
+ def testISOStrippedFormatStrip2(self):
self.assertEqual(parse("20030925T104941+0300"),
datetime(2003, 9, 25, 10, 49, 41,
tzinfo=tzoffset(None, 10800)))
-
- def testAMPMNoHour(self):
+
+ def testAMPMNoHour(self):
with pytest.raises(ParserError):
- parse("AM")
-
+ parse("AM")
+
with pytest.raises(ParserError):
- parse("Jan 20, 2015 PM")
-
- def testAMPMRange(self):
+ parse("Jan 20, 2015 PM")
+
+ def testAMPMRange(self):
with pytest.raises(ParserError):
- parse("13:44 AM")
-
+ parse("13:44 AM")
+
with pytest.raises(ParserError):
- parse("January 25, 1921 23:13 PM")
-
- def testPertain(self):
- self.assertEqual(parse("Sep 03", default=self.default),
- datetime(2003, 9, 3))
- self.assertEqual(parse("Sep of 03", default=self.default),
- datetime(2003, 9, 25))
-
- def testFuzzy(self):
- s = "Today is 25 of September of 2003, exactly " \
- "at 10:49:41 with timezone -03:00."
- self.assertEqual(parse(s, fuzzy=True),
- datetime(2003, 9, 25, 10, 49, 41,
- tzinfo=self.brsttz))
-
- def testFuzzyWithTokens(self):
- s1 = "Today is 25 of September of 2003, exactly " \
- "at 10:49:41 with timezone -03:00."
- self.assertEqual(parse(s1, fuzzy_with_tokens=True),
- (datetime(2003, 9, 25, 10, 49, 41,
- tzinfo=self.brsttz),
- ('Today is ', 'of ', ', exactly at ',
- ' with timezone ', '.')))
-
- s2 = "http://biz.yahoo.com/ipo/p/600221.html"
- self.assertEqual(parse(s2, fuzzy_with_tokens=True),
- (datetime(2060, 2, 21, 0, 0, 0),
- ('http://biz.yahoo.com/ipo/p/', '.html')))
-
- def testFuzzyAMPMProblem(self):
- # Sometimes fuzzy parsing results in AM/PM flag being set without
- # hours - if it's fuzzy it should ignore that.
- s1 = "I have a meeting on March 1, 1974."
- s2 = "On June 8th, 2020, I am going to be the first man on Mars"
-
- # Also don't want any erroneous AM or PMs changing the parsed time
- s3 = "Meet me at the AM/PM on Sunset at 3:00 AM on December 3rd, 2003"
- s4 = "Meet me at 3:00AM on December 3rd, 2003 at the AM/PM on Sunset"
-
- self.assertEqual(parse(s1, fuzzy=True), datetime(1974, 3, 1))
- self.assertEqual(parse(s2, fuzzy=True), datetime(2020, 6, 8))
- self.assertEqual(parse(s3, fuzzy=True), datetime(2003, 12, 3, 3))
- self.assertEqual(parse(s4, fuzzy=True), datetime(2003, 12, 3, 3))
-
- def testFuzzyIgnoreAMPM(self):
- s1 = "Jan 29, 1945 14:45 AM I going to see you there?"
- with pytest.warns(UnknownTimezoneWarning):
- res = parse(s1, fuzzy=True)
- self.assertEqual(res, datetime(1945, 1, 29, 14, 45))
-
- def testRandomFormat24(self):
- self.assertEqual(parse("0:00 PM, PST", default=self.default,
- ignoretz=True),
- datetime(2003, 9, 25, 12, 0))
-
- def testRandomFormat26(self):
- with pytest.warns(UnknownTimezoneWarning):
- res = parse("5:50 A.M. on June 13, 1990")
-
- self.assertEqual(res, datetime(1990, 6, 13, 5, 50))
-
- def testUnspecifiedDayFallback(self):
- # Test that for an unspecified day, the fallback behavior is correct.
- self.assertEqual(parse("April 2009", default=datetime(2010, 1, 31)),
- datetime(2009, 4, 30))
-
- def testUnspecifiedDayFallbackFebNoLeapYear(self):
- self.assertEqual(parse("Feb 2007", default=datetime(2010, 1, 31)),
- datetime(2007, 2, 28))
-
- def testUnspecifiedDayFallbackFebLeapYear(self):
- self.assertEqual(parse("Feb 2008", default=datetime(2010, 1, 31)),
- datetime(2008, 2, 29))
-
- def testErrorType01(self):
+ parse("January 25, 1921 23:13 PM")
+
+ def testPertain(self):
+ self.assertEqual(parse("Sep 03", default=self.default),
+ datetime(2003, 9, 3))
+ self.assertEqual(parse("Sep of 03", default=self.default),
+ datetime(2003, 9, 25))
+
+ def testFuzzy(self):
+ s = "Today is 25 of September of 2003, exactly " \
+ "at 10:49:41 with timezone -03:00."
+ self.assertEqual(parse(s, fuzzy=True),
+ datetime(2003, 9, 25, 10, 49, 41,
+ tzinfo=self.brsttz))
+
+ def testFuzzyWithTokens(self):
+ s1 = "Today is 25 of September of 2003, exactly " \
+ "at 10:49:41 with timezone -03:00."
+ self.assertEqual(parse(s1, fuzzy_with_tokens=True),
+ (datetime(2003, 9, 25, 10, 49, 41,
+ tzinfo=self.brsttz),
+ ('Today is ', 'of ', ', exactly at ',
+ ' with timezone ', '.')))
+
+ s2 = "http://biz.yahoo.com/ipo/p/600221.html"
+ self.assertEqual(parse(s2, fuzzy_with_tokens=True),
+ (datetime(2060, 2, 21, 0, 0, 0),
+ ('http://biz.yahoo.com/ipo/p/', '.html')))
+
+ def testFuzzyAMPMProblem(self):
+ # Sometimes fuzzy parsing results in AM/PM flag being set without
+ # hours - if it's fuzzy it should ignore that.
+ s1 = "I have a meeting on March 1, 1974."
+ s2 = "On June 8th, 2020, I am going to be the first man on Mars"
+
+ # Also don't want any erroneous AM or PMs changing the parsed time
+ s3 = "Meet me at the AM/PM on Sunset at 3:00 AM on December 3rd, 2003"
+ s4 = "Meet me at 3:00AM on December 3rd, 2003 at the AM/PM on Sunset"
+
+ self.assertEqual(parse(s1, fuzzy=True), datetime(1974, 3, 1))
+ self.assertEqual(parse(s2, fuzzy=True), datetime(2020, 6, 8))
+ self.assertEqual(parse(s3, fuzzy=True), datetime(2003, 12, 3, 3))
+ self.assertEqual(parse(s4, fuzzy=True), datetime(2003, 12, 3, 3))
+
+ def testFuzzyIgnoreAMPM(self):
+ s1 = "Jan 29, 1945 14:45 AM I going to see you there?"
+ with pytest.warns(UnknownTimezoneWarning):
+ res = parse(s1, fuzzy=True)
+ self.assertEqual(res, datetime(1945, 1, 29, 14, 45))
+
+ def testRandomFormat24(self):
+ self.assertEqual(parse("0:00 PM, PST", default=self.default,
+ ignoretz=True),
+ datetime(2003, 9, 25, 12, 0))
+
+ def testRandomFormat26(self):
+ with pytest.warns(UnknownTimezoneWarning):
+ res = parse("5:50 A.M. on June 13, 1990")
+
+ self.assertEqual(res, datetime(1990, 6, 13, 5, 50))
+
+ def testUnspecifiedDayFallback(self):
+ # Test that for an unspecified day, the fallback behavior is correct.
+ self.assertEqual(parse("April 2009", default=datetime(2010, 1, 31)),
+ datetime(2009, 4, 30))
+
+ def testUnspecifiedDayFallbackFebNoLeapYear(self):
+ self.assertEqual(parse("Feb 2007", default=datetime(2010, 1, 31)),
+ datetime(2007, 2, 28))
+
+ def testUnspecifiedDayFallbackFebLeapYear(self):
+ self.assertEqual(parse("Feb 2008", default=datetime(2010, 1, 31)),
+ datetime(2008, 2, 29))
+
+ def testErrorType01(self):
with pytest.raises(ParserError):
parse('shouldfail')
-
- def testCorrectErrorOnFuzzyWithTokens(self):
+
+ def testCorrectErrorOnFuzzyWithTokens(self):
assertRaisesRegex(self, ParserError, 'Unknown string format',
- parse, '04/04/32/423', fuzzy_with_tokens=True)
+ parse, '04/04/32/423', fuzzy_with_tokens=True)
assertRaisesRegex(self, ParserError, 'Unknown string format',
- parse, '04/04/04 +32423', fuzzy_with_tokens=True)
+ parse, '04/04/04 +32423', fuzzy_with_tokens=True)
assertRaisesRegex(self, ParserError, 'Unknown string format',
- parse, '04/04/0d4', fuzzy_with_tokens=True)
-
- def testIncreasingCTime(self):
- # This test will check 200 different years, every month, every day,
- # every hour, every minute, every second, and every weekday, using
- # a delta of more or less 1 year, 1 month, 1 day, 1 minute and
- # 1 second.
- delta = timedelta(days=365+31+1, seconds=1+60+60*60)
- dt = datetime(1900, 1, 1, 0, 0, 0, 0)
- for i in range(200):
+ parse, '04/04/0d4', fuzzy_with_tokens=True)
+
+ def testIncreasingCTime(self):
+ # This test will check 200 different years, every month, every day,
+ # every hour, every minute, every second, and every weekday, using
+ # a delta of more or less 1 year, 1 month, 1 day, 1 minute and
+ # 1 second.
+ delta = timedelta(days=365+31+1, seconds=1+60+60*60)
+ dt = datetime(1900, 1, 1, 0, 0, 0, 0)
+ for i in range(200):
assert parse(dt.ctime()) == dt
- dt += delta
-
- def testIncreasingISOFormat(self):
- delta = timedelta(days=365+31+1, seconds=1+60+60*60)
- dt = datetime(1900, 1, 1, 0, 0, 0, 0)
- for i in range(200):
+ dt += delta
+
+ def testIncreasingISOFormat(self):
+ delta = timedelta(days=365+31+1, seconds=1+60+60*60)
+ dt = datetime(1900, 1, 1, 0, 0, 0, 0)
+ for i in range(200):
assert parse(dt.isoformat()) == dt
- dt += delta
-
- def testMicrosecondsPrecisionError(self):
- # Skip found out that sad precision problem. :-(
- dt1 = parse("00:11:25.01")
- dt2 = parse("00:12:10.01")
+ dt += delta
+
+ def testMicrosecondsPrecisionError(self):
+ # Skip found out that sad precision problem. :-(
+ dt1 = parse("00:11:25.01")
+ dt2 = parse("00:12:10.01")
assert dt1.microsecond == 10000
assert dt2.microsecond == 10000
-
- def testMicrosecondPrecisionErrorReturns(self):
- # One more precision issue, discovered by Eric Brown. This should
- # be the last one, as we're no longer using floating points.
- for ms in [100001, 100000, 99999, 99998,
- 10001, 10000, 9999, 9998,
- 1001, 1000, 999, 998,
- 101, 100, 99, 98]:
- dt = datetime(2008, 2, 27, 21, 26, 1, ms)
+
+ def testMicrosecondPrecisionErrorReturns(self):
+ # One more precision issue, discovered by Eric Brown. This should
+ # be the last one, as we're no longer using floating points.
+ for ms in [100001, 100000, 99999, 99998,
+ 10001, 10000, 9999, 9998,
+ 1001, 1000, 999, 998,
+ 101, 100, 99, 98]:
+ dt = datetime(2008, 2, 27, 21, 26, 1, ms)
assert parse(dt.isoformat()) == dt
-
- def testCustomParserInfo(self):
- # Custom parser info wasn't working, as Michael Elsdörfer discovered.
- from dateutil.parser import parserinfo, parser
-
- class myparserinfo(parserinfo):
- MONTHS = parserinfo.MONTHS[:]
- MONTHS[0] = ("Foo", "Foo")
- myparser = parser(myparserinfo())
- dt = myparser.parse("01/Foo/2007")
+
+ def testCustomParserInfo(self):
+ # Custom parser info wasn't working, as Michael Elsdörfer discovered.
+ from dateutil.parser import parserinfo, parser
+
+ class myparserinfo(parserinfo):
+ MONTHS = parserinfo.MONTHS[:]
+ MONTHS[0] = ("Foo", "Foo")
+ myparser = parser(myparserinfo())
+ dt = myparser.parse("01/Foo/2007")
assert dt == datetime(2007, 1, 1)
-
- def testCustomParserShortDaynames(self):
- # Horacio Hoyos discovered that day names shorter than 3 characters,
- # for example two letter German day name abbreviations, don't work:
- # https://github.com/dateutil/dateutil/issues/343
- from dateutil.parser import parserinfo, parser
-
- class GermanParserInfo(parserinfo):
- WEEKDAYS = [("Mo", "Montag"),
- ("Di", "Dienstag"),
- ("Mi", "Mittwoch"),
- ("Do", "Donnerstag"),
- ("Fr", "Freitag"),
- ("Sa", "Samstag"),
- ("So", "Sonntag")]
-
- myparser = parser(GermanParserInfo())
- dt = myparser.parse("Sa 21. Jan 2017")
- self.assertEqual(dt, datetime(2017, 1, 21))
-
- def testNoYearFirstNoDayFirst(self):
- dtstr = '090107'
-
- # Should be MMDDYY
- self.assertEqual(parse(dtstr),
- datetime(2007, 9, 1))
-
- self.assertEqual(parse(dtstr, yearfirst=False, dayfirst=False),
- datetime(2007, 9, 1))
-
- def testYearFirst(self):
- dtstr = '090107'
-
- # Should be MMDDYY
- self.assertEqual(parse(dtstr, yearfirst=True),
- datetime(2009, 1, 7))
-
- self.assertEqual(parse(dtstr, yearfirst=True, dayfirst=False),
- datetime(2009, 1, 7))
-
- def testDayFirst(self):
- dtstr = '090107'
-
- # Should be DDMMYY
- self.assertEqual(parse(dtstr, dayfirst=True),
- datetime(2007, 1, 9))
-
- self.assertEqual(parse(dtstr, yearfirst=False, dayfirst=True),
- datetime(2007, 1, 9))
-
- def testDayFirstYearFirst(self):
- dtstr = '090107'
- # Should be YYDDMM
- self.assertEqual(parse(dtstr, yearfirst=True, dayfirst=True),
- datetime(2009, 7, 1))
-
- def testUnambiguousYearFirst(self):
- dtstr = '2015 09 25'
- self.assertEqual(parse(dtstr, yearfirst=True),
- datetime(2015, 9, 25))
-
- def testUnambiguousDayFirst(self):
- dtstr = '2015 09 25'
- self.assertEqual(parse(dtstr, dayfirst=True),
- datetime(2015, 9, 25))
-
- def testUnambiguousDayFirstYearFirst(self):
- dtstr = '2015 09 25'
- self.assertEqual(parse(dtstr, dayfirst=True, yearfirst=True),
- datetime(2015, 9, 25))
-
- def test_mstridx(self):
- # See GH408
- dtstr = '2015-15-May'
- self.assertEqual(parse(dtstr),
- datetime(2015, 5, 15))
-
- def test_idx_check(self):
- dtstr = '2017-07-17 06:15:'
- # Pre-PR, the trailing colon will cause an IndexError at 824-825
- # when checking `i < len_l` and then accessing `l[i+1]`
- res = parse(dtstr, fuzzy=True)
+
+ def testCustomParserShortDaynames(self):
+ # Horacio Hoyos discovered that day names shorter than 3 characters,
+ # for example two letter German day name abbreviations, don't work:
+ # https://github.com/dateutil/dateutil/issues/343
+ from dateutil.parser import parserinfo, parser
+
+ class GermanParserInfo(parserinfo):
+ WEEKDAYS = [("Mo", "Montag"),
+ ("Di", "Dienstag"),
+ ("Mi", "Mittwoch"),
+ ("Do", "Donnerstag"),
+ ("Fr", "Freitag"),
+ ("Sa", "Samstag"),
+ ("So", "Sonntag")]
+
+ myparser = parser(GermanParserInfo())
+ dt = myparser.parse("Sa 21. Jan 2017")
+ self.assertEqual(dt, datetime(2017, 1, 21))
+
+ def testNoYearFirstNoDayFirst(self):
+ dtstr = '090107'
+
+ # Should be MMDDYY
+ self.assertEqual(parse(dtstr),
+ datetime(2007, 9, 1))
+
+ self.assertEqual(parse(dtstr, yearfirst=False, dayfirst=False),
+ datetime(2007, 9, 1))
+
+ def testYearFirst(self):
+ dtstr = '090107'
+
+ # Should be MMDDYY
+ self.assertEqual(parse(dtstr, yearfirst=True),
+ datetime(2009, 1, 7))
+
+ self.assertEqual(parse(dtstr, yearfirst=True, dayfirst=False),
+ datetime(2009, 1, 7))
+
+ def testDayFirst(self):
+ dtstr = '090107'
+
+ # Should be DDMMYY
+ self.assertEqual(parse(dtstr, dayfirst=True),
+ datetime(2007, 1, 9))
+
+ self.assertEqual(parse(dtstr, yearfirst=False, dayfirst=True),
+ datetime(2007, 1, 9))
+
+ def testDayFirstYearFirst(self):
+ dtstr = '090107'
+ # Should be YYDDMM
+ self.assertEqual(parse(dtstr, yearfirst=True, dayfirst=True),
+ datetime(2009, 7, 1))
+
+ def testUnambiguousYearFirst(self):
+ dtstr = '2015 09 25'
+ self.assertEqual(parse(dtstr, yearfirst=True),
+ datetime(2015, 9, 25))
+
+ def testUnambiguousDayFirst(self):
+ dtstr = '2015 09 25'
+ self.assertEqual(parse(dtstr, dayfirst=True),
+ datetime(2015, 9, 25))
+
+ def testUnambiguousDayFirstYearFirst(self):
+ dtstr = '2015 09 25'
+ self.assertEqual(parse(dtstr, dayfirst=True, yearfirst=True),
+ datetime(2015, 9, 25))
+
+ def test_mstridx(self):
+ # See GH408
+ dtstr = '2015-15-May'
+ self.assertEqual(parse(dtstr),
+ datetime(2015, 5, 15))
+
+ def test_idx_check(self):
+ dtstr = '2017-07-17 06:15:'
+ # Pre-PR, the trailing colon will cause an IndexError at 824-825
+ # when checking `i < len_l` and then accessing `l[i+1]`
+ res = parse(dtstr, fuzzy=True)
assert res == datetime(2017, 7, 17, 6, 15)
-
- def test_hmBY(self):
- # See GH#483
- dtstr = '02:17NOV2017'
- res = parse(dtstr, default=self.default)
+
+ def test_hmBY(self):
+ # See GH#483
+ dtstr = '02:17NOV2017'
+ res = parse(dtstr, default=self.default)
assert res == datetime(2017, 11, self.default.day, 2, 17)
-
- def test_validate_hour(self):
- # See GH353
- invalid = "201A-01-01T23:58:39.239769+03:00"
+
+ def test_validate_hour(self):
+ # See GH353
+ invalid = "201A-01-01T23:58:39.239769+03:00"
with pytest.raises(ParserError):
- parse(invalid)
-
- def test_era_trailing_year(self):
- dstr = 'AD2001'
- res = parse(dstr)
- assert res.year == 2001, res
-
+ parse(invalid)
+
+ def test_era_trailing_year(self):
+ dstr = 'AD2001'
+ res = parse(dstr)
+ assert res.year == 2001, res
+
def test_includes_timestr(self):
timestr = "2020-13-97T44:61:83"
-
+
try:
parse(timestr)
except ParserError as e:
@@ -769,113 +769,113 @@ class TestOutOfBounds(object):
parse(dstr, fuzzy=fuzzy)
-class TestParseUnimplementedCases(object):
- @pytest.mark.xfail
- def test_somewhat_ambiguous_string(self):
- # Ref: github issue #487
- # The parser is choosing the wrong part for hour
- # causing datetime to raise an exception.
- dtstr = '1237 PM BRST Mon Oct 30 2017'
- res = parse(dtstr, tzinfo=self.tzinfos)
- assert res == datetime(2017, 10, 30, 12, 37, tzinfo=self.tzinfos)
-
- @pytest.mark.xfail
- def test_YmdH_M_S(self):
- # found in nasdaq's ftp data
- dstr = '1991041310:19:24'
- expected = datetime(1991, 4, 13, 10, 19, 24)
- res = parse(dstr)
- assert res == expected, (res, expected)
-
- @pytest.mark.xfail
- def test_first_century(self):
- dstr = '0031 Nov 03'
- expected = datetime(31, 11, 3)
- res = parse(dstr)
- assert res == expected, res
-
- @pytest.mark.xfail
- def test_era_trailing_year_with_dots(self):
- dstr = 'A.D.2001'
- res = parse(dstr)
- assert res.year == 2001, res
-
- @pytest.mark.xfail
- def test_ad_nospace(self):
- expected = datetime(6, 5, 19)
- for dstr in [' 6AD May 19', ' 06AD May 19',
- ' 006AD May 19', ' 0006AD May 19']:
- res = parse(dstr)
- assert res == expected, (dstr, res)
-
- @pytest.mark.xfail
- def test_four_letter_day(self):
- dstr = 'Frid Dec 30, 2016'
- expected = datetime(2016, 12, 30)
- res = parse(dstr)
- assert res == expected
-
- @pytest.mark.xfail
- def test_non_date_number(self):
- dstr = '1,700'
+class TestParseUnimplementedCases(object):
+ @pytest.mark.xfail
+ def test_somewhat_ambiguous_string(self):
+ # Ref: github issue #487
+ # The parser is choosing the wrong part for hour
+ # causing datetime to raise an exception.
+ dtstr = '1237 PM BRST Mon Oct 30 2017'
+ res = parse(dtstr, tzinfo=self.tzinfos)
+ assert res == datetime(2017, 10, 30, 12, 37, tzinfo=self.tzinfos)
+
+ @pytest.mark.xfail
+ def test_YmdH_M_S(self):
+ # found in nasdaq's ftp data
+ dstr = '1991041310:19:24'
+ expected = datetime(1991, 4, 13, 10, 19, 24)
+ res = parse(dstr)
+ assert res == expected, (res, expected)
+
+ @pytest.mark.xfail
+ def test_first_century(self):
+ dstr = '0031 Nov 03'
+ expected = datetime(31, 11, 3)
+ res = parse(dstr)
+ assert res == expected, res
+
+ @pytest.mark.xfail
+ def test_era_trailing_year_with_dots(self):
+ dstr = 'A.D.2001'
+ res = parse(dstr)
+ assert res.year == 2001, res
+
+ @pytest.mark.xfail
+ def test_ad_nospace(self):
+ expected = datetime(6, 5, 19)
+ for dstr in [' 6AD May 19', ' 06AD May 19',
+ ' 006AD May 19', ' 0006AD May 19']:
+ res = parse(dstr)
+ assert res == expected, (dstr, res)
+
+ @pytest.mark.xfail
+ def test_four_letter_day(self):
+ dstr = 'Frid Dec 30, 2016'
+ expected = datetime(2016, 12, 30)
+ res = parse(dstr)
+ assert res == expected
+
+ @pytest.mark.xfail
+ def test_non_date_number(self):
+ dstr = '1,700'
with pytest.raises(ParserError):
- parse(dstr)
-
- @pytest.mark.xfail
- def test_on_era(self):
- # This could be classified as an "eras" test, but the relevant part
- # about this is the ` on `
- dstr = '2:15 PM on January 2nd 1973 A.D.'
- expected = datetime(1973, 1, 2, 14, 15)
- res = parse(dstr)
- assert res == expected
-
- @pytest.mark.xfail
- def test_extraneous_year(self):
- # This was found in the wild at insidertrading.org
- dstr = "2011 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d NOVEMBER 7, 2012"
- res = parse(dstr, fuzzy_with_tokens=True)
- expected = datetime(2012, 11, 7)
- assert res == expected
-
- @pytest.mark.xfail
- def test_extraneous_year_tokens(self):
- # This was found in the wild at insidertrading.org
- # Unlike in the case above, identifying the first "2012" as the year
+ parse(dstr)
+
+ @pytest.mark.xfail
+ def test_on_era(self):
+ # This could be classified as an "eras" test, but the relevant part
+ # about this is the ` on `
+ dstr = '2:15 PM on January 2nd 1973 A.D.'
+ expected = datetime(1973, 1, 2, 14, 15)
+ res = parse(dstr)
+ assert res == expected
+
+ @pytest.mark.xfail
+ def test_extraneous_year(self):
+ # This was found in the wild at insidertrading.org
+ dstr = "2011 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d NOVEMBER 7, 2012"
+ res = parse(dstr, fuzzy_with_tokens=True)
+ expected = datetime(2012, 11, 7)
+ assert res == expected
+
+ @pytest.mark.xfail
+ def test_extraneous_year_tokens(self):
+ # This was found in the wild at insidertrading.org
+ # Unlike in the case above, identifying the first "2012" as the year
# would not be a problem, but inferring that the latter 2012 is hhmm
- # is a problem.
- dstr = "2012 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d NOVEMBER 7, 2012"
- expected = datetime(2012, 11, 7)
- (res, tokens) = parse(dstr, fuzzy_with_tokens=True)
- assert res == expected
- assert tokens == ("2012 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d ",)
-
- @pytest.mark.xfail
- def test_extraneous_year2(self):
- # This was found in the wild at insidertrading.org
- dstr = ("Berylson Amy Smith 1998 Grantor Retained Annuity Trust "
- "u/d/t November 2, 1998 f/b/o Jennifer L Berylson")
- res = parse(dstr, fuzzy_with_tokens=True)
- expected = datetime(1998, 11, 2)
- assert res == expected
-
- @pytest.mark.xfail
- def test_extraneous_year3(self):
- # This was found in the wild at insidertrading.org
- dstr = "SMITH R & WEISS D 94 CHILD TR FBO M W SMITH UDT 12/1/1994"
- res = parse(dstr, fuzzy_with_tokens=True)
- expected = datetime(1994, 12, 1)
- assert res == expected
-
- @pytest.mark.xfail
- def test_unambiguous_YYYYMM(self):
- # 171206 can be parsed as YYMMDD. However, 201712 cannot be parsed
- # as instance of YYMMDD and parser could fallback to YYYYMM format.
- dstr = "201712"
- res = parse(dstr)
- expected = datetime(2017, 12, 1)
- assert res == expected
-
+ # is a problem.
+ dstr = "2012 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d NOVEMBER 7, 2012"
+ expected = datetime(2012, 11, 7)
+ (res, tokens) = parse(dstr, fuzzy_with_tokens=True)
+ assert res == expected
+ assert tokens == ("2012 MARTIN CHILDREN'S IRREVOCABLE TRUST u/a/d ",)
+
+ @pytest.mark.xfail
+ def test_extraneous_year2(self):
+ # This was found in the wild at insidertrading.org
+ dstr = ("Berylson Amy Smith 1998 Grantor Retained Annuity Trust "
+ "u/d/t November 2, 1998 f/b/o Jennifer L Berylson")
+ res = parse(dstr, fuzzy_with_tokens=True)
+ expected = datetime(1998, 11, 2)
+ assert res == expected
+
+ @pytest.mark.xfail
+ def test_extraneous_year3(self):
+ # This was found in the wild at insidertrading.org
+ dstr = "SMITH R & WEISS D 94 CHILD TR FBO M W SMITH UDT 12/1/1994"
+ res = parse(dstr, fuzzy_with_tokens=True)
+ expected = datetime(1994, 12, 1)
+ assert res == expected
+
+ @pytest.mark.xfail
+ def test_unambiguous_YYYYMM(self):
+ # 171206 can be parsed as YYMMDD. However, 201712 cannot be parsed
+ # as instance of YYMMDD and parser could fallback to YYYYMM format.
+ dstr = "201712"
+ res = parse(dstr)
+ expected = datetime(2017, 12, 1)
+ assert res == expected
+
@pytest.mark.xfail
def test_extraneous_numerical_content(self):
# ref: https://github.com/dateutil/dateutil/issues/1029
@@ -884,7 +884,7 @@ class TestParseUnimplementedCases(object):
res = parse(dstr, fuzzy=True, default=datetime(2000, 1, 1))
expected = datetime(2000, 4, 20)
assert res == expected
-
+
@pytest.mark.skipif(IS_WIN, reason="Windows does not use TZ var")
class TestTZVar(object):
@@ -894,10 +894,10 @@ class TestTZVar(object):
with TZEnvContext('EST+5EDT,M3.2.0/2,M11.1.0/2'):
dt_exp = datetime(2011, 8, 1, 12, 30, tzinfo=tz.tzlocal())
dt = parse('2011-08-01T12:30 EST')
-
+
assert dt.tzname() == 'EDT'
assert dt == dt_exp
-
+
def test_tzlocal_in_gmt(self):
# GH #318
with TZEnvContext('GMT0BST,M3.5.0,M10.5.0'):
@@ -905,16 +905,16 @@ class TestTZVar(object):
# parse using the GMT-as-alias-for-UTC rule
dt = parse('2004-05-01T12:00 GMT')
dt_exp = datetime(2004, 5, 1, 12, tzinfo=tz.UTC)
-
+
assert dt == dt_exp
-
+
def test_tzlocal_parse_fold(self):
# One manifestion of GH #318
with TZEnvContext('EST+5EDT,M3.2.0/2,M11.1.0/2'):
dt_exp = datetime(2011, 11, 6, 1, 30, tzinfo=tz.tzlocal())
dt_exp = tz.enfold(dt_exp, fold=1)
dt = parse('2011-11-06T01:30 EST')
-
+
# Because this is ambiguous, until `tz.tzlocal() is tz.tzlocal()`
# we'll just check the attributes we care about rather than
# dt == dt_exp
@@ -922,37 +922,37 @@ class TestTZVar(object):
assert dt.replace(tzinfo=None) == dt_exp.replace(tzinfo=None)
assert getattr(dt, 'fold') == getattr(dt_exp, 'fold')
assert dt.astimezone(tz.UTC) == dt_exp.astimezone(tz.UTC)
-
-
-def test_parse_tzinfos_fold():
- NYC = tz.gettz('America/New_York')
- tzinfos = {'EST': NYC, 'EDT': NYC}
-
- dt_exp = tz.enfold(datetime(2011, 11, 6, 1, 30, tzinfo=NYC), fold=1)
- dt = parse('2011-11-06T01:30 EST', tzinfos=tzinfos)
-
- assert dt == dt_exp
- assert dt.tzinfo is dt_exp.tzinfo
- assert getattr(dt, 'fold') == getattr(dt_exp, 'fold')
+
+
+def test_parse_tzinfos_fold():
+ NYC = tz.gettz('America/New_York')
+ tzinfos = {'EST': NYC, 'EDT': NYC}
+
+ dt_exp = tz.enfold(datetime(2011, 11, 6, 1, 30, tzinfo=NYC), fold=1)
+ dt = parse('2011-11-06T01:30 EST', tzinfos=tzinfos)
+
+ assert dt == dt_exp
+ assert dt.tzinfo is dt_exp.tzinfo
+ assert getattr(dt, 'fold') == getattr(dt_exp, 'fold')
assert dt.astimezone(tz.UTC) == dt_exp.astimezone(tz.UTC)
-
-
-@pytest.mark.parametrize('dtstr,dt', [
- ('5.6h', datetime(2003, 9, 25, 5, 36)),
- ('5.6m', datetime(2003, 9, 25, 0, 5, 36)),
- # '5.6s' never had a rounding problem, test added for completeness
- ('5.6s', datetime(2003, 9, 25, 0, 0, 5, 600000))
-])
-def test_rounding_floatlike_strings(dtstr, dt):
- assert parse(dtstr, default=datetime(2003, 9, 25)) == dt
-
-
-@pytest.mark.parametrize('value', ['1: test', 'Nan'])
-def test_decimal_error(value):
+
+
+@pytest.mark.parametrize('dtstr,dt', [
+ ('5.6h', datetime(2003, 9, 25, 5, 36)),
+ ('5.6m', datetime(2003, 9, 25, 0, 5, 36)),
+ # '5.6s' never had a rounding problem, test added for completeness
+ ('5.6s', datetime(2003, 9, 25, 0, 0, 5, 600000))
+])
+def test_rounding_floatlike_strings(dtstr, dt):
+ assert parse(dtstr, default=datetime(2003, 9, 25)) == dt
+
+
+@pytest.mark.parametrize('value', ['1: test', 'Nan'])
+def test_decimal_error(value):
# GH 632, GH 662 - decimal.Decimal raises some non-ParserError exception
# when constructed with an invalid value
with pytest.raises(ParserError):
- parse(value)
+ parse(value)
def test_parsererror_repr():
# GH 991 — the __repr__ was not properly indented and so was never defined.
diff --git a/contrib/python/dateutil/dateutil/test/test_relativedelta.py b/contrib/python/dateutil/dateutil/test/test_relativedelta.py
index 0fecdd7823..1e5d170449 100644
--- a/contrib/python/dateutil/dateutil/test/test_relativedelta.py
+++ b/contrib/python/dateutil/dateutil/test/test_relativedelta.py
@@ -1,124 +1,124 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
from ._common import NotAValue
-
-import calendar
-from datetime import datetime, date, timedelta
-import unittest
-
+
+import calendar
+from datetime import datetime, date, timedelta
+import unittest
+
import pytest
-from dateutil.relativedelta import relativedelta, MO, TU, WE, FR, SU
-
-
+from dateutil.relativedelta import relativedelta, MO, TU, WE, FR, SU
+
+
class RelativeDeltaTest(unittest.TestCase):
- now = datetime(2003, 9, 17, 20, 54, 47, 282310)
- today = date(2003, 9, 17)
-
- def testInheritance(self):
- # Ensure that relativedelta is inheritance-friendly.
- class rdChildClass(relativedelta):
- pass
-
- ccRD = rdChildClass(years=1, months=1, days=1, leapdays=1, weeks=1,
- hours=1, minutes=1, seconds=1, microseconds=1)
-
- rd = relativedelta(years=1, months=1, days=1, leapdays=1, weeks=1,
- hours=1, minutes=1, seconds=1, microseconds=1)
-
- self.assertEqual(type(ccRD + rd), type(ccRD),
- msg='Addition does not inherit type.')
-
- self.assertEqual(type(ccRD - rd), type(ccRD),
- msg='Subtraction does not inherit type.')
-
- self.assertEqual(type(-ccRD), type(ccRD),
- msg='Negation does not inherit type.')
-
- self.assertEqual(type(ccRD * 5.0), type(ccRD),
- msg='Multiplication does not inherit type.')
-
- self.assertEqual(type(ccRD / 5.0), type(ccRD),
- msg='Division does not inherit type.')
-
- def testMonthEndMonthBeginning(self):
- self.assertEqual(relativedelta(datetime(2003, 1, 31, 23, 59, 59),
- datetime(2003, 3, 1, 0, 0, 0)),
- relativedelta(months=-1, seconds=-1))
-
- self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
- datetime(2003, 1, 31, 23, 59, 59)),
- relativedelta(months=1, seconds=1))
-
- def testMonthEndMonthBeginningLeapYear(self):
- self.assertEqual(relativedelta(datetime(2012, 1, 31, 23, 59, 59),
- datetime(2012, 3, 1, 0, 0, 0)),
- relativedelta(months=-1, seconds=-1))
-
- self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
- datetime(2003, 1, 31, 23, 59, 59)),
- relativedelta(months=1, seconds=1))
-
- def testNextMonth(self):
- self.assertEqual(self.now+relativedelta(months=+1),
- datetime(2003, 10, 17, 20, 54, 47, 282310))
-
- def testNextMonthPlusOneWeek(self):
- self.assertEqual(self.now+relativedelta(months=+1, weeks=+1),
- datetime(2003, 10, 24, 20, 54, 47, 282310))
-
- def testNextMonthPlusOneWeek10am(self):
- self.assertEqual(self.today +
- relativedelta(months=+1, weeks=+1, hour=10),
- datetime(2003, 10, 24, 10, 0))
-
- def testNextMonthPlusOneWeek10amDiff(self):
- self.assertEqual(relativedelta(datetime(2003, 10, 24, 10, 0),
- self.today),
- relativedelta(months=+1, days=+7, hours=+10))
-
- def testOneMonthBeforeOneYear(self):
- self.assertEqual(self.now+relativedelta(years=+1, months=-1),
- datetime(2004, 8, 17, 20, 54, 47, 282310))
-
- def testMonthsOfDiffNumOfDays(self):
- self.assertEqual(date(2003, 1, 27)+relativedelta(months=+1),
- date(2003, 2, 27))
- self.assertEqual(date(2003, 1, 31)+relativedelta(months=+1),
- date(2003, 2, 28))
- self.assertEqual(date(2003, 1, 31)+relativedelta(months=+2),
- date(2003, 3, 31))
-
- def testMonthsOfDiffNumOfDaysWithYears(self):
- self.assertEqual(date(2000, 2, 28)+relativedelta(years=+1),
- date(2001, 2, 28))
- self.assertEqual(date(2000, 2, 29)+relativedelta(years=+1),
- date(2001, 2, 28))
-
- self.assertEqual(date(1999, 2, 28)+relativedelta(years=+1),
- date(2000, 2, 28))
- self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
- date(2000, 3, 1))
- self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
- date(2000, 3, 1))
-
- self.assertEqual(date(2001, 2, 28)+relativedelta(years=-1),
- date(2000, 2, 28))
- self.assertEqual(date(2001, 3, 1)+relativedelta(years=-1),
- date(2000, 3, 1))
-
- def testNextFriday(self):
- self.assertEqual(self.today+relativedelta(weekday=FR),
- date(2003, 9, 19))
-
- def testNextFridayInt(self):
- self.assertEqual(self.today+relativedelta(weekday=calendar.FRIDAY),
- date(2003, 9, 19))
-
- def testLastFridayInThisMonth(self):
- self.assertEqual(self.today+relativedelta(day=31, weekday=FR(-1)),
- date(2003, 9, 26))
-
+ now = datetime(2003, 9, 17, 20, 54, 47, 282310)
+ today = date(2003, 9, 17)
+
+ def testInheritance(self):
+ # Ensure that relativedelta is inheritance-friendly.
+ class rdChildClass(relativedelta):
+ pass
+
+ ccRD = rdChildClass(years=1, months=1, days=1, leapdays=1, weeks=1,
+ hours=1, minutes=1, seconds=1, microseconds=1)
+
+ rd = relativedelta(years=1, months=1, days=1, leapdays=1, weeks=1,
+ hours=1, minutes=1, seconds=1, microseconds=1)
+
+ self.assertEqual(type(ccRD + rd), type(ccRD),
+ msg='Addition does not inherit type.')
+
+ self.assertEqual(type(ccRD - rd), type(ccRD),
+ msg='Subtraction does not inherit type.')
+
+ self.assertEqual(type(-ccRD), type(ccRD),
+ msg='Negation does not inherit type.')
+
+ self.assertEqual(type(ccRD * 5.0), type(ccRD),
+ msg='Multiplication does not inherit type.')
+
+ self.assertEqual(type(ccRD / 5.0), type(ccRD),
+ msg='Division does not inherit type.')
+
+ def testMonthEndMonthBeginning(self):
+ self.assertEqual(relativedelta(datetime(2003, 1, 31, 23, 59, 59),
+ datetime(2003, 3, 1, 0, 0, 0)),
+ relativedelta(months=-1, seconds=-1))
+
+ self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
+ datetime(2003, 1, 31, 23, 59, 59)),
+ relativedelta(months=1, seconds=1))
+
+ def testMonthEndMonthBeginningLeapYear(self):
+ self.assertEqual(relativedelta(datetime(2012, 1, 31, 23, 59, 59),
+ datetime(2012, 3, 1, 0, 0, 0)),
+ relativedelta(months=-1, seconds=-1))
+
+ self.assertEqual(relativedelta(datetime(2003, 3, 1, 0, 0, 0),
+ datetime(2003, 1, 31, 23, 59, 59)),
+ relativedelta(months=1, seconds=1))
+
+ def testNextMonth(self):
+ self.assertEqual(self.now+relativedelta(months=+1),
+ datetime(2003, 10, 17, 20, 54, 47, 282310))
+
+ def testNextMonthPlusOneWeek(self):
+ self.assertEqual(self.now+relativedelta(months=+1, weeks=+1),
+ datetime(2003, 10, 24, 20, 54, 47, 282310))
+
+ def testNextMonthPlusOneWeek10am(self):
+ self.assertEqual(self.today +
+ relativedelta(months=+1, weeks=+1, hour=10),
+ datetime(2003, 10, 24, 10, 0))
+
+ def testNextMonthPlusOneWeek10amDiff(self):
+ self.assertEqual(relativedelta(datetime(2003, 10, 24, 10, 0),
+ self.today),
+ relativedelta(months=+1, days=+7, hours=+10))
+
+ def testOneMonthBeforeOneYear(self):
+ self.assertEqual(self.now+relativedelta(years=+1, months=-1),
+ datetime(2004, 8, 17, 20, 54, 47, 282310))
+
+ def testMonthsOfDiffNumOfDays(self):
+ self.assertEqual(date(2003, 1, 27)+relativedelta(months=+1),
+ date(2003, 2, 27))
+ self.assertEqual(date(2003, 1, 31)+relativedelta(months=+1),
+ date(2003, 2, 28))
+ self.assertEqual(date(2003, 1, 31)+relativedelta(months=+2),
+ date(2003, 3, 31))
+
+ def testMonthsOfDiffNumOfDaysWithYears(self):
+ self.assertEqual(date(2000, 2, 28)+relativedelta(years=+1),
+ date(2001, 2, 28))
+ self.assertEqual(date(2000, 2, 29)+relativedelta(years=+1),
+ date(2001, 2, 28))
+
+ self.assertEqual(date(1999, 2, 28)+relativedelta(years=+1),
+ date(2000, 2, 28))
+ self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
+ date(2000, 3, 1))
+ self.assertEqual(date(1999, 3, 1)+relativedelta(years=+1),
+ date(2000, 3, 1))
+
+ self.assertEqual(date(2001, 2, 28)+relativedelta(years=-1),
+ date(2000, 2, 28))
+ self.assertEqual(date(2001, 3, 1)+relativedelta(years=-1),
+ date(2000, 3, 1))
+
+ def testNextFriday(self):
+ self.assertEqual(self.today+relativedelta(weekday=FR),
+ date(2003, 9, 19))
+
+ def testNextFridayInt(self):
+ self.assertEqual(self.today+relativedelta(weekday=calendar.FRIDAY),
+ date(2003, 9, 19))
+
+ def testLastFridayInThisMonth(self):
+ self.assertEqual(self.today+relativedelta(day=31, weekday=FR(-1)),
+ date(2003, 9, 26))
+
def testLastDayOfFebruary(self):
self.assertEqual(date(2021, 2, 1) + relativedelta(day=31),
date(2021, 2, 28))
@@ -127,14 +127,14 @@ class RelativeDeltaTest(unittest.TestCase):
self.assertEqual(date(2020, 2, 1) + relativedelta(day=31),
date(2020, 2, 29))
- def testNextWednesdayIsToday(self):
- self.assertEqual(self.today+relativedelta(weekday=WE),
- date(2003, 9, 17))
-
+ def testNextWednesdayIsToday(self):
+ self.assertEqual(self.today+relativedelta(weekday=WE),
+ date(2003, 9, 17))
+
def testNextWednesdayNotToday(self):
- self.assertEqual(self.today+relativedelta(days=+1, weekday=WE),
- date(2003, 9, 24))
-
+ self.assertEqual(self.today+relativedelta(days=+1, weekday=WE),
+ date(2003, 9, 24))
+
def testAddMoreThan12Months(self):
self.assertEqual(date(2003, 12, 1) + relativedelta(months=+13),
date(2005, 1, 1))
@@ -143,231 +143,231 @@ class RelativeDeltaTest(unittest.TestCase):
self.assertEqual(date(2003, 1, 1) + relativedelta(months=-2),
date(2002, 11, 1))
- def test15thISOYearWeek(self):
- self.assertEqual(date(2003, 1, 1) +
- relativedelta(day=4, weeks=+14, weekday=MO(-1)),
- date(2003, 4, 7))
-
- def testMillenniumAge(self):
- self.assertEqual(relativedelta(self.now, date(2001, 1, 1)),
- relativedelta(years=+2, months=+8, days=+16,
- hours=+20, minutes=+54, seconds=+47,
- microseconds=+282310))
-
- def testJohnAge(self):
- self.assertEqual(relativedelta(self.now,
- datetime(1978, 4, 5, 12, 0)),
- relativedelta(years=+25, months=+5, days=+12,
- hours=+8, minutes=+54, seconds=+47,
- microseconds=+282310))
-
- def testJohnAgeWithDate(self):
- self.assertEqual(relativedelta(self.today,
- datetime(1978, 4, 5, 12, 0)),
- relativedelta(years=+25, months=+5, days=+11,
- hours=+12))
-
- def testYearDay(self):
- self.assertEqual(date(2003, 1, 1)+relativedelta(yearday=260),
- date(2003, 9, 17))
- self.assertEqual(date(2002, 1, 1)+relativedelta(yearday=260),
- date(2002, 9, 17))
- self.assertEqual(date(2000, 1, 1)+relativedelta(yearday=260),
- date(2000, 9, 16))
- self.assertEqual(self.today+relativedelta(yearday=261),
- date(2003, 9, 18))
-
- def testYearDayBug(self):
- # Tests a problem reported by Adam Ryan.
- self.assertEqual(date(2010, 1, 1)+relativedelta(yearday=15),
- date(2010, 1, 15))
-
- def testNonLeapYearDay(self):
- self.assertEqual(date(2003, 1, 1)+relativedelta(nlyearday=260),
- date(2003, 9, 17))
- self.assertEqual(date(2002, 1, 1)+relativedelta(nlyearday=260),
- date(2002, 9, 17))
- self.assertEqual(date(2000, 1, 1)+relativedelta(nlyearday=260),
- date(2000, 9, 17))
- self.assertEqual(self.today+relativedelta(yearday=261),
- date(2003, 9, 18))
-
- def testAddition(self):
- self.assertEqual(relativedelta(days=10) +
- relativedelta(years=1, months=2, days=3, hours=4,
- minutes=5, microseconds=6),
- relativedelta(years=1, months=2, days=13, hours=4,
- minutes=5, microseconds=6))
-
- def testAbsoluteAddition(self):
- self.assertEqual(relativedelta() + relativedelta(day=0, hour=0),
- relativedelta(day=0, hour=0))
- self.assertEqual(relativedelta(day=0, hour=0) + relativedelta(),
- relativedelta(day=0, hour=0))
-
- def testAdditionToDatetime(self):
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1),
- datetime(2000, 1, 2))
-
- def testRightAdditionToDatetime(self):
- self.assertEqual(relativedelta(days=1) + datetime(2000, 1, 1),
- datetime(2000, 1, 2))
-
- def testAdditionInvalidType(self):
- with self.assertRaises(TypeError):
- relativedelta(days=3) + 9
-
- def testAdditionUnsupportedType(self):
- # For unsupported types that define their own comparators, etc.
- self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
-
- def testAdditionFloatValue(self):
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=float(1)),
- datetime(2000, 1, 2))
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(months=float(1)),
- datetime(2000, 2, 1))
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(years=float(1)),
- datetime(2001, 1, 1))
-
- def testAdditionFloatFractionals(self):
- self.assertEqual(datetime(2000, 1, 1, 0) +
- relativedelta(days=float(0.5)),
- datetime(2000, 1, 1, 12))
- self.assertEqual(datetime(2000, 1, 1, 0, 0) +
- relativedelta(hours=float(0.5)),
- datetime(2000, 1, 1, 0, 30))
- self.assertEqual(datetime(2000, 1, 1, 0, 0, 0) +
- relativedelta(minutes=float(0.5)),
- datetime(2000, 1, 1, 0, 0, 30))
- self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
- relativedelta(seconds=float(0.5)),
- datetime(2000, 1, 1, 0, 0, 0, 500000))
- self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
- relativedelta(microseconds=float(500000.25)),
- datetime(2000, 1, 1, 0, 0, 0, 500000))
-
- def testSubtraction(self):
- self.assertEqual(relativedelta(days=10) -
- relativedelta(years=1, months=2, days=3, hours=4,
- minutes=5, microseconds=6),
- relativedelta(years=-1, months=-2, days=7, hours=-4,
- minutes=-5, microseconds=-6))
-
- def testRightSubtractionFromDatetime(self):
- self.assertEqual(datetime(2000, 1, 2) - relativedelta(days=1),
- datetime(2000, 1, 1))
-
- def testSubractionWithDatetime(self):
- self.assertRaises(TypeError, lambda x, y: x - y,
- (relativedelta(days=1), datetime(2000, 1, 1)))
-
- def testSubtractionInvalidType(self):
- with self.assertRaises(TypeError):
- relativedelta(hours=12) - 14
-
- def testSubtractionUnsupportedType(self):
- self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
-
- def testMultiplication(self):
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1) * 28,
- datetime(2000, 1, 29))
- self.assertEqual(datetime(2000, 1, 1) + 28 * relativedelta(days=1),
- datetime(2000, 1, 29))
-
- def testMultiplicationUnsupportedType(self):
- self.assertIs(relativedelta(days=1) * NotAValue, NotAValue)
-
- def testDivision(self):
- self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=28) / 28,
- datetime(2000, 1, 2))
-
- def testDivisionUnsupportedType(self):
- self.assertIs(relativedelta(days=1) / NotAValue, NotAValue)
-
- def testBoolean(self):
- self.assertFalse(relativedelta(days=0))
- self.assertTrue(relativedelta(days=1))
-
- def testAbsoluteValueNegative(self):
- rd_base = relativedelta(years=-1, months=-5, days=-2, hours=-3,
- minutes=-5, seconds=-2, microseconds=-12)
- rd_expected = relativedelta(years=1, months=5, days=2, hours=3,
- minutes=5, seconds=2, microseconds=12)
- self.assertEqual(abs(rd_base), rd_expected)
-
- def testAbsoluteValuePositive(self):
- rd_base = relativedelta(years=1, months=5, days=2, hours=3,
- minutes=5, seconds=2, microseconds=12)
- rd_expected = rd_base
-
- self.assertEqual(abs(rd_base), rd_expected)
-
- def testComparison(self):
- d1 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
- minutes=1, seconds=1, microseconds=1)
- d2 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
- minutes=1, seconds=1, microseconds=1)
- d3 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
- minutes=1, seconds=1, microseconds=2)
-
- self.assertEqual(d1, d2)
- self.assertNotEqual(d1, d3)
-
- def testInequalityTypeMismatch(self):
- # Different type
- self.assertFalse(relativedelta(year=1) == 19)
-
- def testInequalityUnsupportedType(self):
- self.assertIs(relativedelta(hours=3) == NotAValue, NotAValue)
-
- def testInequalityWeekdays(self):
- # Different weekdays
- no_wday = relativedelta(year=1997, month=4)
- wday_mo_1 = relativedelta(year=1997, month=4, weekday=MO(+1))
- wday_mo_2 = relativedelta(year=1997, month=4, weekday=MO(+2))
- wday_tu = relativedelta(year=1997, month=4, weekday=TU)
-
- self.assertTrue(wday_mo_1 == wday_mo_1)
-
- self.assertFalse(no_wday == wday_mo_1)
- self.assertFalse(wday_mo_1 == no_wday)
-
- self.assertFalse(wday_mo_1 == wday_mo_2)
- self.assertFalse(wday_mo_2 == wday_mo_1)
-
- self.assertFalse(wday_mo_1 == wday_tu)
- self.assertFalse(wday_tu == wday_mo_1)
-
- def testMonthOverflow(self):
- self.assertEqual(relativedelta(months=273),
- relativedelta(years=22, months=9))
-
- def testWeeks(self):
- # Test that the weeks property is working properly.
- rd = relativedelta(years=4, months=2, weeks=8, days=6)
- self.assertEqual((rd.weeks, rd.days), (8, 8 * 7 + 6))
-
- rd.weeks = 3
- self.assertEqual((rd.weeks, rd.days), (3, 3 * 7 + 6))
-
- def testRelativeDeltaRepr(self):
- self.assertEqual(repr(relativedelta(years=1, months=-1, days=15)),
- 'relativedelta(years=+1, months=-1, days=+15)')
-
- self.assertEqual(repr(relativedelta(months=14, seconds=-25)),
- 'relativedelta(years=+1, months=+2, seconds=-25)')
-
- self.assertEqual(repr(relativedelta(month=3, hour=3, weekday=SU(3))),
- 'relativedelta(month=3, weekday=SU(+3), hour=3)')
-
- def testRelativeDeltaFractionalYear(self):
- with self.assertRaises(ValueError):
- relativedelta(years=1.5)
-
- def testRelativeDeltaFractionalMonth(self):
- with self.assertRaises(ValueError):
- relativedelta(months=1.5)
-
+ def test15thISOYearWeek(self):
+ self.assertEqual(date(2003, 1, 1) +
+ relativedelta(day=4, weeks=+14, weekday=MO(-1)),
+ date(2003, 4, 7))
+
+ def testMillenniumAge(self):
+ self.assertEqual(relativedelta(self.now, date(2001, 1, 1)),
+ relativedelta(years=+2, months=+8, days=+16,
+ hours=+20, minutes=+54, seconds=+47,
+ microseconds=+282310))
+
+ def testJohnAge(self):
+ self.assertEqual(relativedelta(self.now,
+ datetime(1978, 4, 5, 12, 0)),
+ relativedelta(years=+25, months=+5, days=+12,
+ hours=+8, minutes=+54, seconds=+47,
+ microseconds=+282310))
+
+ def testJohnAgeWithDate(self):
+ self.assertEqual(relativedelta(self.today,
+ datetime(1978, 4, 5, 12, 0)),
+ relativedelta(years=+25, months=+5, days=+11,
+ hours=+12))
+
+ def testYearDay(self):
+ self.assertEqual(date(2003, 1, 1)+relativedelta(yearday=260),
+ date(2003, 9, 17))
+ self.assertEqual(date(2002, 1, 1)+relativedelta(yearday=260),
+ date(2002, 9, 17))
+ self.assertEqual(date(2000, 1, 1)+relativedelta(yearday=260),
+ date(2000, 9, 16))
+ self.assertEqual(self.today+relativedelta(yearday=261),
+ date(2003, 9, 18))
+
+ def testYearDayBug(self):
+ # Tests a problem reported by Adam Ryan.
+ self.assertEqual(date(2010, 1, 1)+relativedelta(yearday=15),
+ date(2010, 1, 15))
+
+ def testNonLeapYearDay(self):
+ self.assertEqual(date(2003, 1, 1)+relativedelta(nlyearday=260),
+ date(2003, 9, 17))
+ self.assertEqual(date(2002, 1, 1)+relativedelta(nlyearday=260),
+ date(2002, 9, 17))
+ self.assertEqual(date(2000, 1, 1)+relativedelta(nlyearday=260),
+ date(2000, 9, 17))
+ self.assertEqual(self.today+relativedelta(yearday=261),
+ date(2003, 9, 18))
+
+ def testAddition(self):
+ self.assertEqual(relativedelta(days=10) +
+ relativedelta(years=1, months=2, days=3, hours=4,
+ minutes=5, microseconds=6),
+ relativedelta(years=1, months=2, days=13, hours=4,
+ minutes=5, microseconds=6))
+
+ def testAbsoluteAddition(self):
+ self.assertEqual(relativedelta() + relativedelta(day=0, hour=0),
+ relativedelta(day=0, hour=0))
+ self.assertEqual(relativedelta(day=0, hour=0) + relativedelta(),
+ relativedelta(day=0, hour=0))
+
+ def testAdditionToDatetime(self):
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1),
+ datetime(2000, 1, 2))
+
+ def testRightAdditionToDatetime(self):
+ self.assertEqual(relativedelta(days=1) + datetime(2000, 1, 1),
+ datetime(2000, 1, 2))
+
+ def testAdditionInvalidType(self):
+ with self.assertRaises(TypeError):
+ relativedelta(days=3) + 9
+
+ def testAdditionUnsupportedType(self):
+ # For unsupported types that define their own comparators, etc.
+ self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
+
+ def testAdditionFloatValue(self):
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=float(1)),
+ datetime(2000, 1, 2))
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(months=float(1)),
+ datetime(2000, 2, 1))
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(years=float(1)),
+ datetime(2001, 1, 1))
+
+ def testAdditionFloatFractionals(self):
+ self.assertEqual(datetime(2000, 1, 1, 0) +
+ relativedelta(days=float(0.5)),
+ datetime(2000, 1, 1, 12))
+ self.assertEqual(datetime(2000, 1, 1, 0, 0) +
+ relativedelta(hours=float(0.5)),
+ datetime(2000, 1, 1, 0, 30))
+ self.assertEqual(datetime(2000, 1, 1, 0, 0, 0) +
+ relativedelta(minutes=float(0.5)),
+ datetime(2000, 1, 1, 0, 0, 30))
+ self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
+ relativedelta(seconds=float(0.5)),
+ datetime(2000, 1, 1, 0, 0, 0, 500000))
+ self.assertEqual(datetime(2000, 1, 1, 0, 0, 0, 0) +
+ relativedelta(microseconds=float(500000.25)),
+ datetime(2000, 1, 1, 0, 0, 0, 500000))
+
+ def testSubtraction(self):
+ self.assertEqual(relativedelta(days=10) -
+ relativedelta(years=1, months=2, days=3, hours=4,
+ minutes=5, microseconds=6),
+ relativedelta(years=-1, months=-2, days=7, hours=-4,
+ minutes=-5, microseconds=-6))
+
+ def testRightSubtractionFromDatetime(self):
+ self.assertEqual(datetime(2000, 1, 2) - relativedelta(days=1),
+ datetime(2000, 1, 1))
+
+ def testSubractionWithDatetime(self):
+ self.assertRaises(TypeError, lambda x, y: x - y,
+ (relativedelta(days=1), datetime(2000, 1, 1)))
+
+ def testSubtractionInvalidType(self):
+ with self.assertRaises(TypeError):
+ relativedelta(hours=12) - 14
+
+ def testSubtractionUnsupportedType(self):
+ self.assertIs(relativedelta(days=1) + NotAValue, NotAValue)
+
+ def testMultiplication(self):
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=1) * 28,
+ datetime(2000, 1, 29))
+ self.assertEqual(datetime(2000, 1, 1) + 28 * relativedelta(days=1),
+ datetime(2000, 1, 29))
+
+ def testMultiplicationUnsupportedType(self):
+ self.assertIs(relativedelta(days=1) * NotAValue, NotAValue)
+
+ def testDivision(self):
+ self.assertEqual(datetime(2000, 1, 1) + relativedelta(days=28) / 28,
+ datetime(2000, 1, 2))
+
+ def testDivisionUnsupportedType(self):
+ self.assertIs(relativedelta(days=1) / NotAValue, NotAValue)
+
+ def testBoolean(self):
+ self.assertFalse(relativedelta(days=0))
+ self.assertTrue(relativedelta(days=1))
+
+ def testAbsoluteValueNegative(self):
+ rd_base = relativedelta(years=-1, months=-5, days=-2, hours=-3,
+ minutes=-5, seconds=-2, microseconds=-12)
+ rd_expected = relativedelta(years=1, months=5, days=2, hours=3,
+ minutes=5, seconds=2, microseconds=12)
+ self.assertEqual(abs(rd_base), rd_expected)
+
+ def testAbsoluteValuePositive(self):
+ rd_base = relativedelta(years=1, months=5, days=2, hours=3,
+ minutes=5, seconds=2, microseconds=12)
+ rd_expected = rd_base
+
+ self.assertEqual(abs(rd_base), rd_expected)
+
+ def testComparison(self):
+ d1 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
+ minutes=1, seconds=1, microseconds=1)
+ d2 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
+ minutes=1, seconds=1, microseconds=1)
+ d3 = relativedelta(years=1, months=1, days=1, leapdays=0, hours=1,
+ minutes=1, seconds=1, microseconds=2)
+
+ self.assertEqual(d1, d2)
+ self.assertNotEqual(d1, d3)
+
+ def testInequalityTypeMismatch(self):
+ # Different type
+ self.assertFalse(relativedelta(year=1) == 19)
+
+ def testInequalityUnsupportedType(self):
+ self.assertIs(relativedelta(hours=3) == NotAValue, NotAValue)
+
+ def testInequalityWeekdays(self):
+ # Different weekdays
+ no_wday = relativedelta(year=1997, month=4)
+ wday_mo_1 = relativedelta(year=1997, month=4, weekday=MO(+1))
+ wday_mo_2 = relativedelta(year=1997, month=4, weekday=MO(+2))
+ wday_tu = relativedelta(year=1997, month=4, weekday=TU)
+
+ self.assertTrue(wday_mo_1 == wday_mo_1)
+
+ self.assertFalse(no_wday == wday_mo_1)
+ self.assertFalse(wday_mo_1 == no_wday)
+
+ self.assertFalse(wday_mo_1 == wday_mo_2)
+ self.assertFalse(wday_mo_2 == wday_mo_1)
+
+ self.assertFalse(wday_mo_1 == wday_tu)
+ self.assertFalse(wday_tu == wday_mo_1)
+
+ def testMonthOverflow(self):
+ self.assertEqual(relativedelta(months=273),
+ relativedelta(years=22, months=9))
+
+ def testWeeks(self):
+ # Test that the weeks property is working properly.
+ rd = relativedelta(years=4, months=2, weeks=8, days=6)
+ self.assertEqual((rd.weeks, rd.days), (8, 8 * 7 + 6))
+
+ rd.weeks = 3
+ self.assertEqual((rd.weeks, rd.days), (3, 3 * 7 + 6))
+
+ def testRelativeDeltaRepr(self):
+ self.assertEqual(repr(relativedelta(years=1, months=-1, days=15)),
+ 'relativedelta(years=+1, months=-1, days=+15)')
+
+ self.assertEqual(repr(relativedelta(months=14, seconds=-25)),
+ 'relativedelta(years=+1, months=+2, seconds=-25)')
+
+ self.assertEqual(repr(relativedelta(month=3, hour=3, weekday=SU(3))),
+ 'relativedelta(month=3, weekday=SU(+3), hour=3)')
+
+ def testRelativeDeltaFractionalYear(self):
+ with self.assertRaises(ValueError):
+ relativedelta(years=1.5)
+
+ def testRelativeDeltaFractionalMonth(self):
+ with self.assertRaises(ValueError):
+ relativedelta(months=1.5)
+
def testRelativeDeltaInvalidDatetimeObject(self):
with self.assertRaises(TypeError):
relativedelta(dt1='2018-01-01', dt2='2018-01-02')
@@ -378,329 +378,329 @@ class RelativeDeltaTest(unittest.TestCase):
with self.assertRaises(TypeError):
relativedelta(dt1='2018-01-01', dt2=datetime(2018, 1, 2))
- def testRelativeDeltaFractionalAbsolutes(self):
- # Fractional absolute values will soon be unsupported,
- # check for the deprecation warning.
+ def testRelativeDeltaFractionalAbsolutes(self):
+ # Fractional absolute values will soon be unsupported,
+ # check for the deprecation warning.
with pytest.warns(DeprecationWarning):
- relativedelta(year=2.86)
-
+ relativedelta(year=2.86)
+
with pytest.warns(DeprecationWarning):
- relativedelta(month=1.29)
-
+ relativedelta(month=1.29)
+
with pytest.warns(DeprecationWarning):
- relativedelta(day=0.44)
-
+ relativedelta(day=0.44)
+
with pytest.warns(DeprecationWarning):
- relativedelta(hour=23.98)
-
+ relativedelta(hour=23.98)
+
with pytest.warns(DeprecationWarning):
- relativedelta(minute=45.21)
-
+ relativedelta(minute=45.21)
+
with pytest.warns(DeprecationWarning):
- relativedelta(second=13.2)
-
+ relativedelta(second=13.2)
+
with pytest.warns(DeprecationWarning):
- relativedelta(microsecond=157221.93)
-
- def testRelativeDeltaFractionalRepr(self):
- rd = relativedelta(years=3, months=-2, days=1.25)
-
- self.assertEqual(repr(rd),
- 'relativedelta(years=+3, months=-2, days=+1.25)')
-
- rd = relativedelta(hours=0.5, seconds=9.22)
- self.assertEqual(repr(rd),
- 'relativedelta(hours=+0.5, seconds=+9.22)')
-
- def testRelativeDeltaFractionalWeeks(self):
- # Equivalent to days=8, hours=18
- rd = relativedelta(weeks=1.25)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd,
- datetime(2009, 9, 11, 18))
-
- def testRelativeDeltaFractionalDays(self):
- rd1 = relativedelta(days=1.48)
-
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd1,
- datetime(2009, 9, 4, 11, 31, 12))
-
- rd2 = relativedelta(days=1.5)
- self.assertEqual(d1 + rd2,
- datetime(2009, 9, 4, 12, 0, 0))
-
- def testRelativeDeltaFractionalHours(self):
- rd = relativedelta(days=1, hours=12.5)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd,
- datetime(2009, 9, 4, 12, 30, 0))
-
- def testRelativeDeltaFractionalMinutes(self):
- rd = relativedelta(hours=1, minutes=30.5)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd,
- datetime(2009, 9, 3, 1, 30, 30))
-
- def testRelativeDeltaFractionalSeconds(self):
- rd = relativedelta(hours=5, minutes=30, seconds=30.5)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd,
- datetime(2009, 9, 3, 5, 30, 30, 500000))
-
- def testRelativeDeltaFractionalPositiveOverflow(self):
- # Equivalent to (days=1, hours=14)
- rd1 = relativedelta(days=1.5, hours=2)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd1,
- datetime(2009, 9, 4, 14, 0, 0))
-
- # Equivalent to (days=1, hours=14, minutes=45)
- rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
- d1 = datetime(2009, 9, 3, 0, 0)
- self.assertEqual(d1 + rd2,
- datetime(2009, 9, 4, 14, 45))
-
- # Carry back up - equivalent to (days=2, hours=2, minutes=0, seconds=1)
- rd3 = relativedelta(days=1.5, hours=13, minutes=59.5, seconds=31)
- self.assertEqual(d1 + rd3,
- datetime(2009, 9, 5, 2, 0, 1))
-
- def testRelativeDeltaFractionalNegativeDays(self):
- # Equivalent to (days=-1, hours=-1)
- rd1 = relativedelta(days=-1.5, hours=11)
- d1 = datetime(2009, 9, 3, 12, 0)
- self.assertEqual(d1 + rd1,
- datetime(2009, 9, 2, 11, 0, 0))
-
- # Equivalent to (days=-1, hours=-9)
- rd2 = relativedelta(days=-1.25, hours=-3)
- self.assertEqual(d1 + rd2,
- datetime(2009, 9, 2, 3))
-
- def testRelativeDeltaNormalizeFractionalDays(self):
- # Equivalent to (days=2, hours=18)
- rd1 = relativedelta(days=2.75)
-
- self.assertEqual(rd1.normalized(), relativedelta(days=2, hours=18))
-
+ relativedelta(microsecond=157221.93)
+
+ def testRelativeDeltaFractionalRepr(self):
+ rd = relativedelta(years=3, months=-2, days=1.25)
+
+ self.assertEqual(repr(rd),
+ 'relativedelta(years=+3, months=-2, days=+1.25)')
+
+ rd = relativedelta(hours=0.5, seconds=9.22)
+ self.assertEqual(repr(rd),
+ 'relativedelta(hours=+0.5, seconds=+9.22)')
+
+ def testRelativeDeltaFractionalWeeks(self):
+ # Equivalent to days=8, hours=18
+ rd = relativedelta(weeks=1.25)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd,
+ datetime(2009, 9, 11, 18))
+
+ def testRelativeDeltaFractionalDays(self):
+ rd1 = relativedelta(days=1.48)
+
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd1,
+ datetime(2009, 9, 4, 11, 31, 12))
+
+ rd2 = relativedelta(days=1.5)
+ self.assertEqual(d1 + rd2,
+ datetime(2009, 9, 4, 12, 0, 0))
+
+ def testRelativeDeltaFractionalHours(self):
+ rd = relativedelta(days=1, hours=12.5)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd,
+ datetime(2009, 9, 4, 12, 30, 0))
+
+ def testRelativeDeltaFractionalMinutes(self):
+ rd = relativedelta(hours=1, minutes=30.5)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd,
+ datetime(2009, 9, 3, 1, 30, 30))
+
+ def testRelativeDeltaFractionalSeconds(self):
+ rd = relativedelta(hours=5, minutes=30, seconds=30.5)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd,
+ datetime(2009, 9, 3, 5, 30, 30, 500000))
+
+ def testRelativeDeltaFractionalPositiveOverflow(self):
+ # Equivalent to (days=1, hours=14)
+ rd1 = relativedelta(days=1.5, hours=2)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd1,
+ datetime(2009, 9, 4, 14, 0, 0))
+
+ # Equivalent to (days=1, hours=14, minutes=45)
+ rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
+ d1 = datetime(2009, 9, 3, 0, 0)
+ self.assertEqual(d1 + rd2,
+ datetime(2009, 9, 4, 14, 45))
+
+ # Carry back up - equivalent to (days=2, hours=2, minutes=0, seconds=1)
+ rd3 = relativedelta(days=1.5, hours=13, minutes=59.5, seconds=31)
+ self.assertEqual(d1 + rd3,
+ datetime(2009, 9, 5, 2, 0, 1))
+
+ def testRelativeDeltaFractionalNegativeDays(self):
+ # Equivalent to (days=-1, hours=-1)
+ rd1 = relativedelta(days=-1.5, hours=11)
+ d1 = datetime(2009, 9, 3, 12, 0)
+ self.assertEqual(d1 + rd1,
+ datetime(2009, 9, 2, 11, 0, 0))
+
+ # Equivalent to (days=-1, hours=-9)
+ rd2 = relativedelta(days=-1.25, hours=-3)
+ self.assertEqual(d1 + rd2,
+ datetime(2009, 9, 2, 3))
+
+ def testRelativeDeltaNormalizeFractionalDays(self):
+ # Equivalent to (days=2, hours=18)
+ rd1 = relativedelta(days=2.75)
+
+ self.assertEqual(rd1.normalized(), relativedelta(days=2, hours=18))
+
# Equivalent to (days=1, hours=11, minutes=31, seconds=12)
- rd2 = relativedelta(days=1.48)
-
- self.assertEqual(rd2.normalized(),
- relativedelta(days=1, hours=11, minutes=31, seconds=12))
-
- def testRelativeDeltaNormalizeFractionalDays2(self):
- # Equivalent to (hours=1, minutes=30)
- rd1 = relativedelta(hours=1.5)
-
- self.assertEqual(rd1.normalized(), relativedelta(hours=1, minutes=30))
-
- # Equivalent to (hours=3, minutes=17, seconds=5, microseconds=100)
- rd2 = relativedelta(hours=3.28472225)
-
- self.assertEqual(rd2.normalized(),
- relativedelta(hours=3, minutes=17, seconds=5, microseconds=100))
-
- def testRelativeDeltaNormalizeFractionalMinutes(self):
- # Equivalent to (minutes=15, seconds=36)
- rd1 = relativedelta(minutes=15.6)
-
- self.assertEqual(rd1.normalized(),
- relativedelta(minutes=15, seconds=36))
-
- # Equivalent to (minutes=25, seconds=20, microseconds=25000)
- rd2 = relativedelta(minutes=25.33375)
-
- self.assertEqual(rd2.normalized(),
- relativedelta(minutes=25, seconds=20, microseconds=25000))
-
- def testRelativeDeltaNormalizeFractionalSeconds(self):
- # Equivalent to (seconds=45, microseconds=25000)
- rd1 = relativedelta(seconds=45.025)
- self.assertEqual(rd1.normalized(),
- relativedelta(seconds=45, microseconds=25000))
-
- def testRelativeDeltaFractionalPositiveOverflow2(self):
- # Equivalent to (days=1, hours=14)
- rd1 = relativedelta(days=1.5, hours=2)
- self.assertEqual(rd1.normalized(),
- relativedelta(days=1, hours=14))
-
- # Equivalent to (days=1, hours=14, minutes=45)
- rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
- self.assertEqual(rd2.normalized(),
- relativedelta(days=1, hours=14, minutes=45))
-
- # Carry back up - equivalent to:
- # (days=2, hours=2, minutes=0, seconds=2, microseconds=3)
- rd3 = relativedelta(days=1.5, hours=13, minutes=59.50045,
- seconds=31.473, microseconds=500003)
- self.assertEqual(rd3.normalized(),
- relativedelta(days=2, hours=2, minutes=0,
- seconds=2, microseconds=3))
-
- def testRelativeDeltaFractionalNegativeOverflow(self):
- # Equivalent to (days=-1)
- rd1 = relativedelta(days=-0.5, hours=-12)
- self.assertEqual(rd1.normalized(),
- relativedelta(days=-1))
-
- # Equivalent to (days=-1)
- rd2 = relativedelta(days=-1.5, hours=12)
- self.assertEqual(rd2.normalized(),
- relativedelta(days=-1))
-
- # Equivalent to (days=-1, hours=-14, minutes=-45)
- rd3 = relativedelta(days=-1.5, hours=-2.5, minutes=-15)
- self.assertEqual(rd3.normalized(),
- relativedelta(days=-1, hours=-14, minutes=-45))
-
- # Equivalent to (days=-1, hours=-14, minutes=+15)
- rd4 = relativedelta(days=-1.5, hours=-2.5, minutes=45)
- self.assertEqual(rd4.normalized(),
- relativedelta(days=-1, hours=-14, minutes=+15))
-
- # Carry back up - equivalent to:
- # (days=-2, hours=-2, minutes=0, seconds=-2, microseconds=-3)
- rd3 = relativedelta(days=-1.5, hours=-13, minutes=-59.50045,
- seconds=-31.473, microseconds=-500003)
- self.assertEqual(rd3.normalized(),
- relativedelta(days=-2, hours=-2, minutes=0,
- seconds=-2, microseconds=-3))
-
- def testInvalidYearDay(self):
- with self.assertRaises(ValueError):
- relativedelta(yearday=367)
-
- def testAddTimedeltaToUnpopulatedRelativedelta(self):
- td = timedelta(
- days=1,
- seconds=1,
- microseconds=1,
- milliseconds=1,
- minutes=1,
- hours=1,
- weeks=1
- )
-
- expected = relativedelta(
- weeks=1,
- days=1,
- hours=1,
- minutes=1,
- seconds=1,
- microseconds=1001
- )
-
- self.assertEqual(expected, relativedelta() + td)
-
- def testAddTimedeltaToPopulatedRelativeDelta(self):
- td = timedelta(
- days=1,
- seconds=1,
- microseconds=1,
- milliseconds=1,
- minutes=1,
- hours=1,
- weeks=1
- )
-
- rd = relativedelta(
- year=1,
- month=1,
- day=1,
- hour=1,
- minute=1,
- second=1,
- microsecond=1,
- years=1,
- months=1,
- days=1,
- weeks=1,
- hours=1,
- minutes=1,
- seconds=1,
- microseconds=1
- )
-
- expected = relativedelta(
- year=1,
- month=1,
- day=1,
- hour=1,
- minute=1,
- second=1,
- microsecond=1,
- years=1,
- months=1,
- weeks=2,
- days=2,
- hours=2,
- minutes=2,
- seconds=2,
- microseconds=1002,
- )
-
- self.assertEqual(expected, rd + td)
-
- def testHashable(self):
- try:
- {relativedelta(minute=1): 'test'}
- except:
- self.fail("relativedelta() failed to hash!")
-
-
-class RelativeDeltaWeeksPropertyGetterTest(unittest.TestCase):
- """Test the weeks property getter"""
-
- def test_one_day(self):
- rd = relativedelta(days=1)
- self.assertEqual(rd.days, 1)
- self.assertEqual(rd.weeks, 0)
-
- def test_minus_one_day(self):
- rd = relativedelta(days=-1)
- self.assertEqual(rd.days, -1)
- self.assertEqual(rd.weeks, 0)
-
- def test_height_days(self):
- rd = relativedelta(days=8)
- self.assertEqual(rd.days, 8)
- self.assertEqual(rd.weeks, 1)
-
- def test_minus_height_days(self):
- rd = relativedelta(days=-8)
- self.assertEqual(rd.days, -8)
- self.assertEqual(rd.weeks, -1)
-
-
-class RelativeDeltaWeeksPropertySetterTest(unittest.TestCase):
- """Test the weeks setter which makes a "smart" update of the days attribute"""
-
- def test_one_day_set_one_week(self):
- rd = relativedelta(days=1)
- rd.weeks = 1 # add 7 days
- self.assertEqual(rd.days, 8)
- self.assertEqual(rd.weeks, 1)
-
- def test_minus_one_day_set_one_week(self):
- rd = relativedelta(days=-1)
- rd.weeks = 1 # add 7 days
- self.assertEqual(rd.days, 6)
- self.assertEqual(rd.weeks, 0)
-
- def test_height_days_set_minus_one_week(self):
- rd = relativedelta(days=8)
- rd.weeks = -1 # change from 1 week, 1 day to -1 week, 1 day
- self.assertEqual(rd.days, -6)
- self.assertEqual(rd.weeks, 0)
-
- def test_minus_height_days_set_minus_one_week(self):
- rd = relativedelta(days=-8)
- rd.weeks = -1 # does not change anything
- self.assertEqual(rd.days, -8)
- self.assertEqual(rd.weeks, -1)
-
-
-# vim:ts=4:sw=4:et
+ rd2 = relativedelta(days=1.48)
+
+ self.assertEqual(rd2.normalized(),
+ relativedelta(days=1, hours=11, minutes=31, seconds=12))
+
+ def testRelativeDeltaNormalizeFractionalDays2(self):
+ # Equivalent to (hours=1, minutes=30)
+ rd1 = relativedelta(hours=1.5)
+
+ self.assertEqual(rd1.normalized(), relativedelta(hours=1, minutes=30))
+
+ # Equivalent to (hours=3, minutes=17, seconds=5, microseconds=100)
+ rd2 = relativedelta(hours=3.28472225)
+
+ self.assertEqual(rd2.normalized(),
+ relativedelta(hours=3, minutes=17, seconds=5, microseconds=100))
+
+ def testRelativeDeltaNormalizeFractionalMinutes(self):
+ # Equivalent to (minutes=15, seconds=36)
+ rd1 = relativedelta(minutes=15.6)
+
+ self.assertEqual(rd1.normalized(),
+ relativedelta(minutes=15, seconds=36))
+
+ # Equivalent to (minutes=25, seconds=20, microseconds=25000)
+ rd2 = relativedelta(minutes=25.33375)
+
+ self.assertEqual(rd2.normalized(),
+ relativedelta(minutes=25, seconds=20, microseconds=25000))
+
+ def testRelativeDeltaNormalizeFractionalSeconds(self):
+ # Equivalent to (seconds=45, microseconds=25000)
+ rd1 = relativedelta(seconds=45.025)
+ self.assertEqual(rd1.normalized(),
+ relativedelta(seconds=45, microseconds=25000))
+
+ def testRelativeDeltaFractionalPositiveOverflow2(self):
+ # Equivalent to (days=1, hours=14)
+ rd1 = relativedelta(days=1.5, hours=2)
+ self.assertEqual(rd1.normalized(),
+ relativedelta(days=1, hours=14))
+
+ # Equivalent to (days=1, hours=14, minutes=45)
+ rd2 = relativedelta(days=1.5, hours=2.5, minutes=15)
+ self.assertEqual(rd2.normalized(),
+ relativedelta(days=1, hours=14, minutes=45))
+
+ # Carry back up - equivalent to:
+ # (days=2, hours=2, minutes=0, seconds=2, microseconds=3)
+ rd3 = relativedelta(days=1.5, hours=13, minutes=59.50045,
+ seconds=31.473, microseconds=500003)
+ self.assertEqual(rd3.normalized(),
+ relativedelta(days=2, hours=2, minutes=0,
+ seconds=2, microseconds=3))
+
+ def testRelativeDeltaFractionalNegativeOverflow(self):
+ # Equivalent to (days=-1)
+ rd1 = relativedelta(days=-0.5, hours=-12)
+ self.assertEqual(rd1.normalized(),
+ relativedelta(days=-1))
+
+ # Equivalent to (days=-1)
+ rd2 = relativedelta(days=-1.5, hours=12)
+ self.assertEqual(rd2.normalized(),
+ relativedelta(days=-1))
+
+ # Equivalent to (days=-1, hours=-14, minutes=-45)
+ rd3 = relativedelta(days=-1.5, hours=-2.5, minutes=-15)
+ self.assertEqual(rd3.normalized(),
+ relativedelta(days=-1, hours=-14, minutes=-45))
+
+ # Equivalent to (days=-1, hours=-14, minutes=+15)
+ rd4 = relativedelta(days=-1.5, hours=-2.5, minutes=45)
+ self.assertEqual(rd4.normalized(),
+ relativedelta(days=-1, hours=-14, minutes=+15))
+
+ # Carry back up - equivalent to:
+ # (days=-2, hours=-2, minutes=0, seconds=-2, microseconds=-3)
+ rd3 = relativedelta(days=-1.5, hours=-13, minutes=-59.50045,
+ seconds=-31.473, microseconds=-500003)
+ self.assertEqual(rd3.normalized(),
+ relativedelta(days=-2, hours=-2, minutes=0,
+ seconds=-2, microseconds=-3))
+
+ def testInvalidYearDay(self):
+ with self.assertRaises(ValueError):
+ relativedelta(yearday=367)
+
+ def testAddTimedeltaToUnpopulatedRelativedelta(self):
+ td = timedelta(
+ days=1,
+ seconds=1,
+ microseconds=1,
+ milliseconds=1,
+ minutes=1,
+ hours=1,
+ weeks=1
+ )
+
+ expected = relativedelta(
+ weeks=1,
+ days=1,
+ hours=1,
+ minutes=1,
+ seconds=1,
+ microseconds=1001
+ )
+
+ self.assertEqual(expected, relativedelta() + td)
+
+ def testAddTimedeltaToPopulatedRelativeDelta(self):
+ td = timedelta(
+ days=1,
+ seconds=1,
+ microseconds=1,
+ milliseconds=1,
+ minutes=1,
+ hours=1,
+ weeks=1
+ )
+
+ rd = relativedelta(
+ year=1,
+ month=1,
+ day=1,
+ hour=1,
+ minute=1,
+ second=1,
+ microsecond=1,
+ years=1,
+ months=1,
+ days=1,
+ weeks=1,
+ hours=1,
+ minutes=1,
+ seconds=1,
+ microseconds=1
+ )
+
+ expected = relativedelta(
+ year=1,
+ month=1,
+ day=1,
+ hour=1,
+ minute=1,
+ second=1,
+ microsecond=1,
+ years=1,
+ months=1,
+ weeks=2,
+ days=2,
+ hours=2,
+ minutes=2,
+ seconds=2,
+ microseconds=1002,
+ )
+
+ self.assertEqual(expected, rd + td)
+
+ def testHashable(self):
+ try:
+ {relativedelta(minute=1): 'test'}
+ except:
+ self.fail("relativedelta() failed to hash!")
+
+
+class RelativeDeltaWeeksPropertyGetterTest(unittest.TestCase):
+ """Test the weeks property getter"""
+
+ def test_one_day(self):
+ rd = relativedelta(days=1)
+ self.assertEqual(rd.days, 1)
+ self.assertEqual(rd.weeks, 0)
+
+ def test_minus_one_day(self):
+ rd = relativedelta(days=-1)
+ self.assertEqual(rd.days, -1)
+ self.assertEqual(rd.weeks, 0)
+
+ def test_height_days(self):
+ rd = relativedelta(days=8)
+ self.assertEqual(rd.days, 8)
+ self.assertEqual(rd.weeks, 1)
+
+ def test_minus_height_days(self):
+ rd = relativedelta(days=-8)
+ self.assertEqual(rd.days, -8)
+ self.assertEqual(rd.weeks, -1)
+
+
+class RelativeDeltaWeeksPropertySetterTest(unittest.TestCase):
+ """Test the weeks setter which makes a "smart" update of the days attribute"""
+
+ def test_one_day_set_one_week(self):
+ rd = relativedelta(days=1)
+ rd.weeks = 1 # add 7 days
+ self.assertEqual(rd.days, 8)
+ self.assertEqual(rd.weeks, 1)
+
+ def test_minus_one_day_set_one_week(self):
+ rd = relativedelta(days=-1)
+ rd.weeks = 1 # add 7 days
+ self.assertEqual(rd.days, 6)
+ self.assertEqual(rd.weeks, 0)
+
+ def test_height_days_set_minus_one_week(self):
+ rd = relativedelta(days=8)
+ rd.weeks = -1 # change from 1 week, 1 day to -1 week, 1 day
+ self.assertEqual(rd.days, -6)
+ self.assertEqual(rd.weeks, 0)
+
+ def test_minus_height_days_set_minus_one_week(self):
+ rd = relativedelta(days=-8)
+ rd.weeks = -1 # does not change anything
+ self.assertEqual(rd.days, -8)
+ self.assertEqual(rd.weeks, -1)
+
+
+# vim:ts=4:sw=4:et
diff --git a/contrib/python/dateutil/dateutil/test/test_rrule.py b/contrib/python/dateutil/dateutil/test/test_rrule.py
index ccd33bb234..52673ecc26 100644
--- a/contrib/python/dateutil/dateutil/test/test_rrule.py
+++ b/contrib/python/dateutil/dateutil/test/test_rrule.py
@@ -1,2857 +1,2857 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from datetime import datetime, date
-import unittest
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from datetime import datetime, date
+import unittest
from six import PY2
-
-from dateutil import tz
-from dateutil.rrule import (
- rrule, rruleset, rrulestr,
- YEARLY, MONTHLY, WEEKLY, DAILY,
- HOURLY, MINUTELY, SECONDLY,
- MO, TU, WE, TH, FR, SA, SU
-)
-
-from freezegun import freeze_time
-
-import pytest
-
-
-@pytest.mark.rrule
+
+from dateutil import tz
+from dateutil.rrule import (
+ rrule, rruleset, rrulestr,
+ YEARLY, MONTHLY, WEEKLY, DAILY,
+ HOURLY, MINUTELY, SECONDLY,
+ MO, TU, WE, TH, FR, SA, SU
+)
+
+from freezegun import freeze_time
+
+import pytest
+
+
+@pytest.mark.rrule
class RRuleTest(unittest.TestCase):
- def _rrulestr_reverse_test(self, rule):
- """
- Call with an `rrule` and it will test that `str(rrule)` generates a
- string which generates the same `rrule` as the input when passed to
- `rrulestr()`
- """
- rr_str = str(rule)
- rrulestr_rrule = rrulestr(rr_str)
-
- self.assertEqual(list(rule), list(rrulestr_rrule))
-
- def testStrAppendRRULEToken(self):
- # `_rrulestr_reverse_test` does not check if the "RRULE:" prefix
- # property is appended properly, so give it a dedicated test
- self.assertEqual(str(rrule(YEARLY,
- count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=5")
-
- rr_str = (
- 'DTSTART:19970105T083000\nRRULE:FREQ=YEARLY;INTERVAL=2'
- )
- self.assertEqual(str(rrulestr(rr_str)), rr_str)
-
- def testYearly(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testYearlyInterval(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0),
- datetime(2001, 9, 2, 9, 0)])
-
- def testYearlyIntervalLarge(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- interval=100,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(2097, 9, 2, 9, 0),
- datetime(2197, 9, 2, 9, 0)])
-
- def testYearlyByMonth(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 2, 9, 0),
- datetime(1998, 3, 2, 9, 0),
- datetime(1999, 1, 2, 9, 0)])
-
- def testYearlyByMonthDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 9, 0),
- datetime(1997, 10, 1, 9, 0),
- datetime(1997, 10, 3, 9, 0)])
-
- def testYearlyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 9, 0),
- datetime(1998, 1, 7, 9, 0),
- datetime(1998, 3, 5, 9, 0)])
-
- def testYearlyByWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testYearlyByNWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 25, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 12, 31, 9, 0)])
-
- def testYearlyByNWeekDayLarge(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 11, 9, 0),
- datetime(1998, 1, 20, 9, 0),
- datetime(1998, 12, 17, 9, 0)])
-
- def testYearlyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testYearlyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 29, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testYearlyByMonthAndNWeekDayLarge(self):
- # This is interesting because the TH(-3) ends up before
- # the TU(3).
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 15, 9, 0),
- datetime(1998, 1, 20, 9, 0),
- datetime(1998, 3, 12, 9, 0)])
-
- def testYearlyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 2, 3, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testYearlyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 3, 3, 9, 0),
- datetime(2001, 3, 1, 9, 0)])
-
- def testYearlyByYearDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testYearlyByYearDayNeg(self):
- self.assertEqual(list(rrule(YEARLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testYearlyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(YEARLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 4, 10, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testYearlyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(YEARLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 4, 10, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testYearlyByWeekNo(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 9, 0),
- datetime(1998, 5, 12, 9, 0),
- datetime(1998, 5, 13, 9, 0)])
-
- def testYearlyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 9, 0),
- datetime(1999, 1, 4, 9, 0),
- datetime(2000, 1, 3, 9, 0)])
-
- def testYearlyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1998, 12, 27, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testYearlyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1999, 1, 3, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testYearlyByEaster(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 9, 0),
- datetime(1999, 4, 4, 9, 0),
- datetime(2000, 4, 23, 9, 0)])
-
- def testYearlyByEasterPos(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 9, 0),
- datetime(1999, 4, 5, 9, 0),
- datetime(2000, 4, 24, 9, 0)])
-
- def testYearlyByEasterNeg(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 9, 0),
- datetime(1999, 4, 3, 9, 0),
- datetime(2000, 4, 22, 9, 0)])
-
- def testYearlyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 9, 0),
- datetime(2004, 12, 27, 9, 0),
- datetime(2009, 12, 28, 9, 0)])
-
- def testYearlyByHour(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1998, 9, 2, 6, 0),
- datetime(1998, 9, 2, 18, 0)])
-
- def testYearlyByMinute(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1998, 9, 2, 9, 6)])
-
- def testYearlyBySecond(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1998, 9, 2, 9, 0, 6)])
-
- def testYearlyByHourAndMinute(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1998, 9, 2, 6, 6)])
-
- def testYearlyByHourAndSecond(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1998, 9, 2, 6, 0, 6)])
-
- def testYearlyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testYearlyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testYearlyBySetPos(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonthday=15,
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 11, 15, 18, 0),
- datetime(1998, 2, 15, 6, 0),
- datetime(1998, 11, 15, 18, 0)])
-
- def testMonthly(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 10, 2, 9, 0),
- datetime(1997, 11, 2, 9, 0)])
-
- def testMonthlyInterval(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 11, 2, 9, 0),
- datetime(1998, 1, 2, 9, 0)])
-
- def testMonthlyIntervalLarge(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- interval=18,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1999, 3, 2, 9, 0),
- datetime(2000, 9, 2, 9, 0)])
-
- def testMonthlyByMonth(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 2, 9, 0),
- datetime(1998, 3, 2, 9, 0),
- datetime(1999, 1, 2, 9, 0)])
-
- def testMonthlyByMonthDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 9, 0),
- datetime(1997, 10, 1, 9, 0),
- datetime(1997, 10, 3, 9, 0)])
-
- def testMonthlyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 9, 0),
- datetime(1998, 1, 7, 9, 0),
- datetime(1998, 3, 5, 9, 0)])
-
- def testMonthlyByWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- # Third Monday of the month
- self.assertEqual(rrule(MONTHLY,
- byweekday=(MO(+3)),
- dtstart=datetime(1997, 9, 1)).between(datetime(1997, 9, 1),
- datetime(1997, 12, 1)),
- [datetime(1997, 9, 15, 0, 0),
- datetime(1997, 10, 20, 0, 0),
- datetime(1997, 11, 17, 0, 0)])
-
- def testMonthlyByNWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 25, 9, 0),
- datetime(1997, 10, 7, 9, 0)])
-
- def testMonthlyByNWeekDayLarge(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 16, 9, 0),
- datetime(1997, 10, 16, 9, 0)])
-
- def testMonthlyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testMonthlyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 29, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testMonthlyByMonthAndNWeekDayLarge(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 15, 9, 0),
- datetime(1998, 1, 20, 9, 0),
- datetime(1998, 3, 12, 9, 0)])
-
- def testMonthlyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 2, 3, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testMonthlyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 3, 3, 9, 0),
- datetime(2001, 3, 1, 9, 0)])
-
- def testMonthlyByYearDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testMonthlyByYearDayNeg(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testMonthlyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 4, 10, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testMonthlyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 4, 10, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testMonthlyByWeekNo(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 9, 0),
- datetime(1998, 5, 12, 9, 0),
- datetime(1998, 5, 13, 9, 0)])
-
- def testMonthlyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 9, 0),
- datetime(1999, 1, 4, 9, 0),
- datetime(2000, 1, 3, 9, 0)])
-
- def testMonthlyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1998, 12, 27, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testMonthlyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1999, 1, 3, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testMonthlyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 9, 0),
- datetime(2004, 12, 27, 9, 0),
- datetime(2009, 12, 28, 9, 0)])
-
- def testMonthlyByEaster(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 9, 0),
- datetime(1999, 4, 4, 9, 0),
- datetime(2000, 4, 23, 9, 0)])
-
- def testMonthlyByEasterPos(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 9, 0),
- datetime(1999, 4, 5, 9, 0),
- datetime(2000, 4, 24, 9, 0)])
-
- def testMonthlyByEasterNeg(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 9, 0),
- datetime(1999, 4, 3, 9, 0),
- datetime(2000, 4, 22, 9, 0)])
-
- def testMonthlyByHour(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 10, 2, 6, 0),
- datetime(1997, 10, 2, 18, 0)])
-
- def testMonthlyByMinute(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1997, 10, 2, 9, 6)])
-
- def testMonthlyBySecond(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 10, 2, 9, 0, 6)])
-
- def testMonthlyByHourAndMinute(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1997, 10, 2, 6, 6)])
-
- def testMonthlyByHourAndSecond(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 10, 2, 6, 0, 6)])
-
- def testMonthlyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testMonthlyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testMonthlyBySetPos(self):
- self.assertEqual(list(rrule(MONTHLY,
- count=3,
- bymonthday=(13, 17),
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 13, 18, 0),
- datetime(1997, 9, 17, 6, 0),
- datetime(1997, 10, 13, 18, 0)])
-
- def testWeekly(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testWeeklyInterval(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 16, 9, 0),
- datetime(1997, 9, 30, 9, 0)])
-
- def testWeeklyIntervalLarge(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- interval=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 1, 20, 9, 0),
- datetime(1998, 6, 9, 9, 0)])
-
- def testWeeklyByMonth(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 13, 9, 0),
- datetime(1998, 1, 20, 9, 0)])
-
- def testWeeklyByMonthDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 9, 0),
- datetime(1997, 10, 1, 9, 0),
- datetime(1997, 10, 3, 9, 0)])
-
- def testWeeklyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 9, 0),
- datetime(1998, 1, 7, 9, 0),
- datetime(1998, 3, 5, 9, 0)])
-
- def testWeeklyByWeekDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testWeeklyByNWeekDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testWeeklyByMonthAndWeekDay(self):
- # This test is interesting, because it crosses the year
- # boundary in a weekly period to find day '1' as a
- # valid recurrence.
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testWeeklyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testWeeklyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 2, 3, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testWeeklyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 3, 3, 9, 0),
- datetime(2001, 3, 1, 9, 0)])
-
- def testWeeklyByYearDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testWeeklyByYearDayNeg(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testWeeklyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=4,
- bymonth=(1, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 1, 1, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testWeeklyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=4,
- bymonth=(1, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 1, 1, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testWeeklyByWeekNo(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 9, 0),
- datetime(1998, 5, 12, 9, 0),
- datetime(1998, 5, 13, 9, 0)])
-
- def testWeeklyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 9, 0),
- datetime(1999, 1, 4, 9, 0),
- datetime(2000, 1, 3, 9, 0)])
-
- def testWeeklyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1998, 12, 27, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testWeeklyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1999, 1, 3, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testWeeklyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 9, 0),
- datetime(2004, 12, 27, 9, 0),
- datetime(2009, 12, 28, 9, 0)])
-
- def testWeeklyByEaster(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 9, 0),
- datetime(1999, 4, 4, 9, 0),
- datetime(2000, 4, 23, 9, 0)])
-
- def testWeeklyByEasterPos(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 9, 0),
- datetime(1999, 4, 5, 9, 0),
- datetime(2000, 4, 24, 9, 0)])
-
- def testWeeklyByEasterNeg(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 9, 0),
- datetime(1999, 4, 3, 9, 0),
- datetime(2000, 4, 22, 9, 0)])
-
- def testWeeklyByHour(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 9, 9, 6, 0),
- datetime(1997, 9, 9, 18, 0)])
-
- def testWeeklyByMinute(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1997, 9, 9, 9, 6)])
-
- def testWeeklyBySecond(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 9, 9, 9, 0, 6)])
-
- def testWeeklyByHourAndMinute(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1997, 9, 9, 6, 6)])
-
- def testWeeklyByHourAndSecond(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 9, 9, 6, 0, 6)])
-
- def testWeeklyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testWeeklyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testWeeklyBySetPos(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- byweekday=(TU, TH),
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 9, 4, 6, 0),
- datetime(1997, 9, 9, 18, 0)])
-
- def testDaily(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testDailyInterval(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 6, 9, 0)])
-
- def testDailyIntervalLarge(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- interval=92,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 12, 3, 9, 0),
- datetime(1998, 3, 5, 9, 0)])
-
- def testDailyByMonth(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 2, 9, 0),
- datetime(1998, 1, 3, 9, 0)])
-
- def testDailyByMonthDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 9, 0),
- datetime(1997, 10, 1, 9, 0),
- datetime(1997, 10, 3, 9, 0)])
-
- def testDailyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 9, 0),
- datetime(1998, 1, 7, 9, 0),
- datetime(1998, 3, 5, 9, 0)])
-
- def testDailyByWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testDailyByNWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testDailyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testDailyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 1, 8, 9, 0)])
-
- def testDailyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 2, 3, 9, 0),
- datetime(1998, 3, 3, 9, 0)])
-
- def testDailyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 3, 3, 9, 0),
- datetime(2001, 3, 1, 9, 0)])
-
- def testDailyByYearDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testDailyByYearDayNeg(self):
- self.assertEqual(list(rrule(DAILY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 9, 0),
- datetime(1998, 1, 1, 9, 0),
- datetime(1998, 4, 10, 9, 0),
- datetime(1998, 7, 19, 9, 0)])
-
- def testDailyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(DAILY,
- count=4,
- bymonth=(1, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 1, 1, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testDailyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(DAILY,
- count=4,
- bymonth=(1, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 9, 0),
- datetime(1998, 7, 19, 9, 0),
- datetime(1999, 1, 1, 9, 0),
- datetime(1999, 7, 19, 9, 0)])
-
- def testDailyByWeekNo(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 9, 0),
- datetime(1998, 5, 12, 9, 0),
- datetime(1998, 5, 13, 9, 0)])
-
- def testDailyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 9, 0),
- datetime(1999, 1, 4, 9, 0),
- datetime(2000, 1, 3, 9, 0)])
-
- def testDailyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1998, 12, 27, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testDailyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 9, 0),
- datetime(1999, 1, 3, 9, 0),
- datetime(2000, 1, 2, 9, 0)])
-
- def testDailyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 9, 0),
- datetime(2004, 12, 27, 9, 0),
- datetime(2009, 12, 28, 9, 0)])
-
- def testDailyByEaster(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 9, 0),
- datetime(1999, 4, 4, 9, 0),
- datetime(2000, 4, 23, 9, 0)])
-
- def testDailyByEasterPos(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 9, 0),
- datetime(1999, 4, 5, 9, 0),
- datetime(2000, 4, 24, 9, 0)])
-
- def testDailyByEasterNeg(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 9, 0),
- datetime(1999, 4, 3, 9, 0),
- datetime(2000, 4, 22, 9, 0)])
-
- def testDailyByHour(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 9, 3, 6, 0),
- datetime(1997, 9, 3, 18, 0)])
-
- def testDailyByMinute(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1997, 9, 3, 9, 6)])
-
- def testDailyBySecond(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 9, 3, 9, 0, 6)])
-
- def testDailyByHourAndMinute(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1997, 9, 3, 6, 6)])
-
- def testDailyByHourAndSecond(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 9, 3, 6, 0, 6)])
-
- def testDailyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testDailyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testDailyBySetPos(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(15, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 15),
- datetime(1997, 9, 3, 6, 45),
- datetime(1997, 9, 3, 18, 15)])
-
- def testHourly(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 10, 0),
- datetime(1997, 9, 2, 11, 0)])
-
- def testHourlyInterval(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 11, 0),
- datetime(1997, 9, 2, 13, 0)])
-
- def testHourlyIntervalLarge(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- interval=769,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 10, 4, 10, 0),
- datetime(1997, 11, 5, 11, 0)])
-
- def testHourlyByMonth(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 1, 0),
- datetime(1998, 1, 1, 2, 0)])
-
- def testHourlyByMonthDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 0, 0),
- datetime(1997, 9, 3, 1, 0),
- datetime(1997, 9, 3, 2, 0)])
-
- def testHourlyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 0, 0),
- datetime(1998, 1, 5, 1, 0),
- datetime(1998, 1, 5, 2, 0)])
-
- def testHourlyByWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 10, 0),
- datetime(1997, 9, 2, 11, 0)])
-
- def testHourlyByNWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 10, 0),
- datetime(1997, 9, 2, 11, 0)])
-
- def testHourlyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 1, 0),
- datetime(1998, 1, 1, 2, 0)])
-
- def testHourlyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 1, 0),
- datetime(1998, 1, 1, 2, 0)])
-
- def testHourlyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 1, 0),
- datetime(1998, 1, 1, 2, 0)])
-
- def testHourlyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 1, 0),
- datetime(1998, 1, 1, 2, 0)])
-
- def testHourlyByYearDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0),
- datetime(1997, 12, 31, 1, 0),
- datetime(1997, 12, 31, 2, 0),
- datetime(1997, 12, 31, 3, 0)])
-
- def testHourlyByYearDayNeg(self):
- self.assertEqual(list(rrule(HOURLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0),
- datetime(1997, 12, 31, 1, 0),
- datetime(1997, 12, 31, 2, 0),
- datetime(1997, 12, 31, 3, 0)])
-
- def testHourlyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0),
- datetime(1998, 4, 10, 1, 0),
- datetime(1998, 4, 10, 2, 0),
- datetime(1998, 4, 10, 3, 0)])
-
- def testHourlyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(HOURLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0),
- datetime(1998, 4, 10, 1, 0),
- datetime(1998, 4, 10, 2, 0),
- datetime(1998, 4, 10, 3, 0)])
-
- def testHourlyByWeekNo(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 0, 0),
- datetime(1998, 5, 11, 1, 0),
- datetime(1998, 5, 11, 2, 0)])
-
- def testHourlyByWeekNoAndWeekDay(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 0, 0),
- datetime(1997, 12, 29, 1, 0),
- datetime(1997, 12, 29, 2, 0)])
-
- def testHourlyByWeekNoAndWeekDayLarge(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0),
- datetime(1997, 12, 28, 1, 0),
- datetime(1997, 12, 28, 2, 0)])
-
- def testHourlyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0),
- datetime(1997, 12, 28, 1, 0),
- datetime(1997, 12, 28, 2, 0)])
-
- def testHourlyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 0, 0),
- datetime(1998, 12, 28, 1, 0),
- datetime(1998, 12, 28, 2, 0)])
-
- def testHourlyByEaster(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 0, 0),
- datetime(1998, 4, 12, 1, 0),
- datetime(1998, 4, 12, 2, 0)])
-
- def testHourlyByEasterPos(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 0, 0),
- datetime(1998, 4, 13, 1, 0),
- datetime(1998, 4, 13, 2, 0)])
-
- def testHourlyByEasterNeg(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 0, 0),
- datetime(1998, 4, 11, 1, 0),
- datetime(1998, 4, 11, 2, 0)])
-
- def testHourlyByHour(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 9, 3, 6, 0),
- datetime(1997, 9, 3, 18, 0)])
-
- def testHourlyByMinute(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1997, 9, 2, 10, 6)])
-
- def testHourlyBySecond(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 9, 2, 10, 0, 6)])
-
- def testHourlyByHourAndMinute(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1997, 9, 3, 6, 6)])
-
- def testHourlyByHourAndSecond(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 9, 3, 6, 0, 6)])
-
- def testHourlyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testHourlyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testHourlyBySetPos(self):
- self.assertEqual(list(rrule(HOURLY,
- count=3,
- byminute=(15, 45),
- bysecond=(15, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 15, 45),
- datetime(1997, 9, 2, 9, 45, 15),
- datetime(1997, 9, 2, 10, 15, 45)])
-
- def testMinutely(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 9, 1),
- datetime(1997, 9, 2, 9, 2)])
-
- def testMinutelyInterval(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 9, 2),
- datetime(1997, 9, 2, 9, 4)])
-
- def testMinutelyIntervalLarge(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- interval=1501,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 10, 1),
- datetime(1997, 9, 4, 11, 2)])
-
- def testMinutelyByMonth(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 0, 1),
- datetime(1998, 1, 1, 0, 2)])
-
- def testMinutelyByMonthDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 0, 0),
- datetime(1997, 9, 3, 0, 1),
- datetime(1997, 9, 3, 0, 2)])
-
- def testMinutelyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 0, 0),
- datetime(1998, 1, 5, 0, 1),
- datetime(1998, 1, 5, 0, 2)])
-
- def testMinutelyByWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 9, 1),
- datetime(1997, 9, 2, 9, 2)])
-
- def testMinutelyByNWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 2, 9, 1),
- datetime(1997, 9, 2, 9, 2)])
-
- def testMinutelyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 0, 1),
- datetime(1998, 1, 1, 0, 2)])
-
- def testMinutelyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 0, 1),
- datetime(1998, 1, 1, 0, 2)])
-
- def testMinutelyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 0, 1),
- datetime(1998, 1, 1, 0, 2)])
-
- def testMinutelyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0),
- datetime(1998, 1, 1, 0, 1),
- datetime(1998, 1, 1, 0, 2)])
-
- def testMinutelyByYearDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0),
- datetime(1997, 12, 31, 0, 1),
- datetime(1997, 12, 31, 0, 2),
- datetime(1997, 12, 31, 0, 3)])
-
- def testMinutelyByYearDayNeg(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0),
- datetime(1997, 12, 31, 0, 1),
- datetime(1997, 12, 31, 0, 2),
- datetime(1997, 12, 31, 0, 3)])
-
- def testMinutelyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0),
- datetime(1998, 4, 10, 0, 1),
- datetime(1998, 4, 10, 0, 2),
- datetime(1998, 4, 10, 0, 3)])
-
- def testMinutelyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0),
- datetime(1998, 4, 10, 0, 1),
- datetime(1998, 4, 10, 0, 2),
- datetime(1998, 4, 10, 0, 3)])
-
- def testMinutelyByWeekNo(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 0, 0),
- datetime(1998, 5, 11, 0, 1),
- datetime(1998, 5, 11, 0, 2)])
-
- def testMinutelyByWeekNoAndWeekDay(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 0, 0),
- datetime(1997, 12, 29, 0, 1),
- datetime(1997, 12, 29, 0, 2)])
-
- def testMinutelyByWeekNoAndWeekDayLarge(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0),
- datetime(1997, 12, 28, 0, 1),
- datetime(1997, 12, 28, 0, 2)])
-
- def testMinutelyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0),
- datetime(1997, 12, 28, 0, 1),
- datetime(1997, 12, 28, 0, 2)])
-
- def testMinutelyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 0, 0),
- datetime(1998, 12, 28, 0, 1),
- datetime(1998, 12, 28, 0, 2)])
-
- def testMinutelyByEaster(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 0, 0),
- datetime(1998, 4, 12, 0, 1),
- datetime(1998, 4, 12, 0, 2)])
-
- def testMinutelyByEasterPos(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 0, 0),
- datetime(1998, 4, 13, 0, 1),
- datetime(1998, 4, 13, 0, 2)])
-
- def testMinutelyByEasterNeg(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 0, 0),
- datetime(1998, 4, 11, 0, 1),
- datetime(1998, 4, 11, 0, 2)])
-
- def testMinutelyByHour(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0),
- datetime(1997, 9, 2, 18, 1),
- datetime(1997, 9, 2, 18, 2)])
-
- def testMinutelyByMinute(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6),
- datetime(1997, 9, 2, 9, 18),
- datetime(1997, 9, 2, 10, 6)])
-
- def testMinutelyBySecond(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 9, 2, 9, 1, 6)])
-
- def testMinutelyByHourAndMinute(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6),
- datetime(1997, 9, 2, 18, 18),
- datetime(1997, 9, 3, 6, 6)])
-
- def testMinutelyByHourAndSecond(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 9, 2, 18, 1, 6)])
-
- def testMinutelyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testMinutelyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testMinutelyBySetPos(self):
- self.assertEqual(list(rrule(MINUTELY,
- count=3,
- bysecond=(15, 30, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 15),
- datetime(1997, 9, 2, 9, 0, 45),
- datetime(1997, 9, 2, 9, 1, 15)])
-
- def testSecondly(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1997, 9, 2, 9, 0, 1),
- datetime(1997, 9, 2, 9, 0, 2)])
-
- def testSecondlyInterval(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1997, 9, 2, 9, 0, 2),
- datetime(1997, 9, 2, 9, 0, 4)])
-
- def testSecondlyIntervalLarge(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- interval=90061,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1997, 9, 3, 10, 1, 1),
- datetime(1997, 9, 4, 11, 2, 2)])
-
- def testSecondlyByMonth(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0, 0),
- datetime(1998, 1, 1, 0, 0, 1),
- datetime(1998, 1, 1, 0, 0, 2)])
-
- def testSecondlyByMonthDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 3, 0, 0, 0),
- datetime(1997, 9, 3, 0, 0, 1),
- datetime(1997, 9, 3, 0, 0, 2)])
-
- def testSecondlyByMonthAndMonthDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 0, 0, 0),
- datetime(1998, 1, 5, 0, 0, 1),
- datetime(1998, 1, 5, 0, 0, 2)])
-
- def testSecondlyByWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1997, 9, 2, 9, 0, 1),
- datetime(1997, 9, 2, 9, 0, 2)])
-
- def testSecondlyByNWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1997, 9, 2, 9, 0, 1),
- datetime(1997, 9, 2, 9, 0, 2)])
-
- def testSecondlyByMonthAndWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0, 0),
- datetime(1998, 1, 1, 0, 0, 1),
- datetime(1998, 1, 1, 0, 0, 2)])
-
- def testSecondlyByMonthAndNWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0, 0),
- datetime(1998, 1, 1, 0, 0, 1),
- datetime(1998, 1, 1, 0, 0, 2)])
-
- def testSecondlyByMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0, 0),
- datetime(1998, 1, 1, 0, 0, 1),
- datetime(1998, 1, 1, 0, 0, 2)])
-
- def testSecondlyByMonthAndMonthDayAndWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 1, 0, 0, 0),
- datetime(1998, 1, 1, 0, 0, 1),
- datetime(1998, 1, 1, 0, 0, 2)])
-
- def testSecondlyByYearDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0, 0),
- datetime(1997, 12, 31, 0, 0, 1),
- datetime(1997, 12, 31, 0, 0, 2),
- datetime(1997, 12, 31, 0, 0, 3)])
-
- def testSecondlyByYearDayNeg(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 31, 0, 0, 0),
- datetime(1997, 12, 31, 0, 0, 1),
- datetime(1997, 12, 31, 0, 0, 2),
- datetime(1997, 12, 31, 0, 0, 3)])
-
- def testSecondlyByMonthAndYearDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0, 0),
- datetime(1998, 4, 10, 0, 0, 1),
- datetime(1998, 4, 10, 0, 0, 2),
- datetime(1998, 4, 10, 0, 0, 3)])
-
- def testSecondlyByMonthAndYearDayNeg(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 10, 0, 0, 0),
- datetime(1998, 4, 10, 0, 0, 1),
- datetime(1998, 4, 10, 0, 0, 2),
- datetime(1998, 4, 10, 0, 0, 3)])
-
- def testSecondlyByWeekNo(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 5, 11, 0, 0, 0),
- datetime(1998, 5, 11, 0, 0, 1),
- datetime(1998, 5, 11, 0, 0, 2)])
-
- def testSecondlyByWeekNoAndWeekDay(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 29, 0, 0, 0),
- datetime(1997, 12, 29, 0, 0, 1),
- datetime(1997, 12, 29, 0, 0, 2)])
-
- def testSecondlyByWeekNoAndWeekDayLarge(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0, 0),
- datetime(1997, 12, 28, 0, 0, 1),
- datetime(1997, 12, 28, 0, 0, 2)])
-
- def testSecondlyByWeekNoAndWeekDayLast(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 12, 28, 0, 0, 0),
- datetime(1997, 12, 28, 0, 0, 1),
- datetime(1997, 12, 28, 0, 0, 2)])
-
- def testSecondlyByWeekNoAndWeekDay53(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 12, 28, 0, 0, 0),
- datetime(1998, 12, 28, 0, 0, 1),
- datetime(1998, 12, 28, 0, 0, 2)])
-
- def testSecondlyByEaster(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 12, 0, 0, 0),
- datetime(1998, 4, 12, 0, 0, 1),
- datetime(1998, 4, 12, 0, 0, 2)])
-
- def testSecondlyByEasterPos(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 13, 0, 0, 0),
- datetime(1998, 4, 13, 0, 0, 1),
- datetime(1998, 4, 13, 0, 0, 2)])
-
- def testSecondlyByEasterNeg(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 4, 11, 0, 0, 0),
- datetime(1998, 4, 11, 0, 0, 1),
- datetime(1998, 4, 11, 0, 0, 2)])
-
- def testSecondlyByHour(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 0),
- datetime(1997, 9, 2, 18, 0, 1),
- datetime(1997, 9, 2, 18, 0, 2)])
-
- def testSecondlyByMinute(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 0),
- datetime(1997, 9, 2, 9, 6, 1),
- datetime(1997, 9, 2, 9, 6, 2)])
-
- def testSecondlyBySecond(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0, 6),
- datetime(1997, 9, 2, 9, 0, 18),
- datetime(1997, 9, 2, 9, 1, 6)])
-
- def testSecondlyByHourAndMinute(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 0),
- datetime(1997, 9, 2, 18, 6, 1),
- datetime(1997, 9, 2, 18, 6, 2)])
-
- def testSecondlyByHourAndSecond(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 0, 6),
- datetime(1997, 9, 2, 18, 0, 18),
- datetime(1997, 9, 2, 18, 1, 6)])
-
- def testSecondlyByMinuteAndSecond(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 6, 6),
- datetime(1997, 9, 2, 9, 6, 18),
- datetime(1997, 9, 2, 9, 18, 6)])
-
- def testSecondlyByHourAndMinuteAndSecond(self):
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 18, 6, 6),
- datetime(1997, 9, 2, 18, 6, 18),
- datetime(1997, 9, 2, 18, 18, 6)])
-
- def testSecondlyByHourAndMinuteAndSecondBug(self):
- # This explores a bug found by Mathieu Bridon.
- self.assertEqual(list(rrule(SECONDLY,
- count=3,
- bysecond=(0,),
- byminute=(1,),
- dtstart=datetime(2010, 3, 22, 12, 1))),
- [datetime(2010, 3, 22, 12, 1),
- datetime(2010, 3, 22, 13, 1),
- datetime(2010, 3, 22, 14, 1)])
-
- def testLongIntegers(self):
+ def _rrulestr_reverse_test(self, rule):
+ """
+ Call with an `rrule` and it will test that `str(rrule)` generates a
+ string which generates the same `rrule` as the input when passed to
+ `rrulestr()`
+ """
+ rr_str = str(rule)
+ rrulestr_rrule = rrulestr(rr_str)
+
+ self.assertEqual(list(rule), list(rrulestr_rrule))
+
+ def testStrAppendRRULEToken(self):
+ # `_rrulestr_reverse_test` does not check if the "RRULE:" prefix
+ # property is appended properly, so give it a dedicated test
+ self.assertEqual(str(rrule(YEARLY,
+ count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=5")
+
+ rr_str = (
+ 'DTSTART:19970105T083000\nRRULE:FREQ=YEARLY;INTERVAL=2'
+ )
+ self.assertEqual(str(rrulestr(rr_str)), rr_str)
+
+ def testYearly(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testYearlyInterval(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0),
+ datetime(2001, 9, 2, 9, 0)])
+
+ def testYearlyIntervalLarge(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ interval=100,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(2097, 9, 2, 9, 0),
+ datetime(2197, 9, 2, 9, 0)])
+
+ def testYearlyByMonth(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 2, 9, 0),
+ datetime(1998, 3, 2, 9, 0),
+ datetime(1999, 1, 2, 9, 0)])
+
+ def testYearlyByMonthDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 10, 1, 9, 0),
+ datetime(1997, 10, 3, 9, 0)])
+
+ def testYearlyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 9, 0),
+ datetime(1998, 1, 7, 9, 0),
+ datetime(1998, 3, 5, 9, 0)])
+
+ def testYearlyByWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testYearlyByNWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 25, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 12, 31, 9, 0)])
+
+ def testYearlyByNWeekDayLarge(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 11, 9, 0),
+ datetime(1998, 1, 20, 9, 0),
+ datetime(1998, 12, 17, 9, 0)])
+
+ def testYearlyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testYearlyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 29, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testYearlyByMonthAndNWeekDayLarge(self):
+ # This is interesting because the TH(-3) ends up before
+ # the TU(3).
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 15, 9, 0),
+ datetime(1998, 1, 20, 9, 0),
+ datetime(1998, 3, 12, 9, 0)])
+
+ def testYearlyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 2, 3, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testYearlyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 3, 3, 9, 0),
+ datetime(2001, 3, 1, 9, 0)])
+
+ def testYearlyByYearDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testYearlyByYearDayNeg(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testYearlyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 4, 10, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testYearlyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 4, 10, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testYearlyByWeekNo(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 9, 0),
+ datetime(1998, 5, 12, 9, 0),
+ datetime(1998, 5, 13, 9, 0)])
+
+ def testYearlyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 9, 0),
+ datetime(1999, 1, 4, 9, 0),
+ datetime(2000, 1, 3, 9, 0)])
+
+ def testYearlyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1998, 12, 27, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testYearlyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1999, 1, 3, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testYearlyByEaster(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 9, 0),
+ datetime(1999, 4, 4, 9, 0),
+ datetime(2000, 4, 23, 9, 0)])
+
+ def testYearlyByEasterPos(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 9, 0),
+ datetime(1999, 4, 5, 9, 0),
+ datetime(2000, 4, 24, 9, 0)])
+
+ def testYearlyByEasterNeg(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 9, 0),
+ datetime(1999, 4, 3, 9, 0),
+ datetime(2000, 4, 22, 9, 0)])
+
+ def testYearlyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 9, 0),
+ datetime(2004, 12, 27, 9, 0),
+ datetime(2009, 12, 28, 9, 0)])
+
+ def testYearlyByHour(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1998, 9, 2, 6, 0),
+ datetime(1998, 9, 2, 18, 0)])
+
+ def testYearlyByMinute(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1998, 9, 2, 9, 6)])
+
+ def testYearlyBySecond(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1998, 9, 2, 9, 0, 6)])
+
+ def testYearlyByHourAndMinute(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1998, 9, 2, 6, 6)])
+
+ def testYearlyByHourAndSecond(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1998, 9, 2, 6, 0, 6)])
+
+ def testYearlyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testYearlyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testYearlyBySetPos(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonthday=15,
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 11, 15, 18, 0),
+ datetime(1998, 2, 15, 6, 0),
+ datetime(1998, 11, 15, 18, 0)])
+
+ def testMonthly(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 10, 2, 9, 0),
+ datetime(1997, 11, 2, 9, 0)])
+
+ def testMonthlyInterval(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 11, 2, 9, 0),
+ datetime(1998, 1, 2, 9, 0)])
+
+ def testMonthlyIntervalLarge(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ interval=18,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1999, 3, 2, 9, 0),
+ datetime(2000, 9, 2, 9, 0)])
+
+ def testMonthlyByMonth(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 2, 9, 0),
+ datetime(1998, 3, 2, 9, 0),
+ datetime(1999, 1, 2, 9, 0)])
+
+ def testMonthlyByMonthDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 10, 1, 9, 0),
+ datetime(1997, 10, 3, 9, 0)])
+
+ def testMonthlyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 9, 0),
+ datetime(1998, 1, 7, 9, 0),
+ datetime(1998, 3, 5, 9, 0)])
+
+ def testMonthlyByWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ # Third Monday of the month
+ self.assertEqual(rrule(MONTHLY,
+ byweekday=(MO(+3)),
+ dtstart=datetime(1997, 9, 1)).between(datetime(1997, 9, 1),
+ datetime(1997, 12, 1)),
+ [datetime(1997, 9, 15, 0, 0),
+ datetime(1997, 10, 20, 0, 0),
+ datetime(1997, 11, 17, 0, 0)])
+
+ def testMonthlyByNWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 25, 9, 0),
+ datetime(1997, 10, 7, 9, 0)])
+
+ def testMonthlyByNWeekDayLarge(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 16, 9, 0),
+ datetime(1997, 10, 16, 9, 0)])
+
+ def testMonthlyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testMonthlyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 29, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testMonthlyByMonthAndNWeekDayLarge(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 15, 9, 0),
+ datetime(1998, 1, 20, 9, 0),
+ datetime(1998, 3, 12, 9, 0)])
+
+ def testMonthlyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 2, 3, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testMonthlyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 3, 3, 9, 0),
+ datetime(2001, 3, 1, 9, 0)])
+
+ def testMonthlyByYearDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testMonthlyByYearDayNeg(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testMonthlyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 4, 10, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testMonthlyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 4, 10, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testMonthlyByWeekNo(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 9, 0),
+ datetime(1998, 5, 12, 9, 0),
+ datetime(1998, 5, 13, 9, 0)])
+
+ def testMonthlyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 9, 0),
+ datetime(1999, 1, 4, 9, 0),
+ datetime(2000, 1, 3, 9, 0)])
+
+ def testMonthlyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1998, 12, 27, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testMonthlyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1999, 1, 3, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testMonthlyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 9, 0),
+ datetime(2004, 12, 27, 9, 0),
+ datetime(2009, 12, 28, 9, 0)])
+
+ def testMonthlyByEaster(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 9, 0),
+ datetime(1999, 4, 4, 9, 0),
+ datetime(2000, 4, 23, 9, 0)])
+
+ def testMonthlyByEasterPos(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 9, 0),
+ datetime(1999, 4, 5, 9, 0),
+ datetime(2000, 4, 24, 9, 0)])
+
+ def testMonthlyByEasterNeg(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 9, 0),
+ datetime(1999, 4, 3, 9, 0),
+ datetime(2000, 4, 22, 9, 0)])
+
+ def testMonthlyByHour(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 10, 2, 6, 0),
+ datetime(1997, 10, 2, 18, 0)])
+
+ def testMonthlyByMinute(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1997, 10, 2, 9, 6)])
+
+ def testMonthlyBySecond(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 10, 2, 9, 0, 6)])
+
+ def testMonthlyByHourAndMinute(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1997, 10, 2, 6, 6)])
+
+ def testMonthlyByHourAndSecond(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 10, 2, 6, 0, 6)])
+
+ def testMonthlyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testMonthlyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testMonthlyBySetPos(self):
+ self.assertEqual(list(rrule(MONTHLY,
+ count=3,
+ bymonthday=(13, 17),
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 13, 18, 0),
+ datetime(1997, 9, 17, 6, 0),
+ datetime(1997, 10, 13, 18, 0)])
+
+ def testWeekly(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testWeeklyInterval(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 16, 9, 0),
+ datetime(1997, 9, 30, 9, 0)])
+
+ def testWeeklyIntervalLarge(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ interval=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 1, 20, 9, 0),
+ datetime(1998, 6, 9, 9, 0)])
+
+ def testWeeklyByMonth(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 13, 9, 0),
+ datetime(1998, 1, 20, 9, 0)])
+
+ def testWeeklyByMonthDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 10, 1, 9, 0),
+ datetime(1997, 10, 3, 9, 0)])
+
+ def testWeeklyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 9, 0),
+ datetime(1998, 1, 7, 9, 0),
+ datetime(1998, 3, 5, 9, 0)])
+
+ def testWeeklyByWeekDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testWeeklyByNWeekDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testWeeklyByMonthAndWeekDay(self):
+ # This test is interesting, because it crosses the year
+ # boundary in a weekly period to find day '1' as a
+ # valid recurrence.
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testWeeklyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testWeeklyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 2, 3, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testWeeklyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 3, 3, 9, 0),
+ datetime(2001, 3, 1, 9, 0)])
+
+ def testWeeklyByYearDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testWeeklyByYearDayNeg(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testWeeklyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 1, 1, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testWeeklyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 1, 1, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testWeeklyByWeekNo(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 9, 0),
+ datetime(1998, 5, 12, 9, 0),
+ datetime(1998, 5, 13, 9, 0)])
+
+ def testWeeklyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 9, 0),
+ datetime(1999, 1, 4, 9, 0),
+ datetime(2000, 1, 3, 9, 0)])
+
+ def testWeeklyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1998, 12, 27, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testWeeklyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1999, 1, 3, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testWeeklyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 9, 0),
+ datetime(2004, 12, 27, 9, 0),
+ datetime(2009, 12, 28, 9, 0)])
+
+ def testWeeklyByEaster(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 9, 0),
+ datetime(1999, 4, 4, 9, 0),
+ datetime(2000, 4, 23, 9, 0)])
+
+ def testWeeklyByEasterPos(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 9, 0),
+ datetime(1999, 4, 5, 9, 0),
+ datetime(2000, 4, 24, 9, 0)])
+
+ def testWeeklyByEasterNeg(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 9, 0),
+ datetime(1999, 4, 3, 9, 0),
+ datetime(2000, 4, 22, 9, 0)])
+
+ def testWeeklyByHour(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 9, 9, 6, 0),
+ datetime(1997, 9, 9, 18, 0)])
+
+ def testWeeklyByMinute(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1997, 9, 9, 9, 6)])
+
+ def testWeeklyBySecond(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 9, 9, 9, 0, 6)])
+
+ def testWeeklyByHourAndMinute(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1997, 9, 9, 6, 6)])
+
+ def testWeeklyByHourAndSecond(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 9, 9, 6, 0, 6)])
+
+ def testWeeklyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testWeeklyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testWeeklyBySetPos(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU, TH),
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 9, 4, 6, 0),
+ datetime(1997, 9, 9, 18, 0)])
+
+ def testDaily(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testDailyInterval(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 6, 9, 0)])
+
+ def testDailyIntervalLarge(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ interval=92,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 12, 3, 9, 0),
+ datetime(1998, 3, 5, 9, 0)])
+
+ def testDailyByMonth(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 2, 9, 0),
+ datetime(1998, 1, 3, 9, 0)])
+
+ def testDailyByMonthDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 10, 1, 9, 0),
+ datetime(1997, 10, 3, 9, 0)])
+
+ def testDailyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 9, 0),
+ datetime(1998, 1, 7, 9, 0),
+ datetime(1998, 3, 5, 9, 0)])
+
+ def testDailyByWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testDailyByNWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testDailyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testDailyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 1, 8, 9, 0)])
+
+ def testDailyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 2, 3, 9, 0),
+ datetime(1998, 3, 3, 9, 0)])
+
+ def testDailyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 3, 3, 9, 0),
+ datetime(2001, 3, 1, 9, 0)])
+
+ def testDailyByYearDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testDailyByYearDayNeg(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 9, 0),
+ datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 4, 10, 9, 0),
+ datetime(1998, 7, 19, 9, 0)])
+
+ def testDailyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 1, 1, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testDailyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 9, 0),
+ datetime(1998, 7, 19, 9, 0),
+ datetime(1999, 1, 1, 9, 0),
+ datetime(1999, 7, 19, 9, 0)])
+
+ def testDailyByWeekNo(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 9, 0),
+ datetime(1998, 5, 12, 9, 0),
+ datetime(1998, 5, 13, 9, 0)])
+
+ def testDailyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 9, 0),
+ datetime(1999, 1, 4, 9, 0),
+ datetime(2000, 1, 3, 9, 0)])
+
+ def testDailyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1998, 12, 27, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testDailyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 9, 0),
+ datetime(1999, 1, 3, 9, 0),
+ datetime(2000, 1, 2, 9, 0)])
+
+ def testDailyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 9, 0),
+ datetime(2004, 12, 27, 9, 0),
+ datetime(2009, 12, 28, 9, 0)])
+
+ def testDailyByEaster(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 9, 0),
+ datetime(1999, 4, 4, 9, 0),
+ datetime(2000, 4, 23, 9, 0)])
+
+ def testDailyByEasterPos(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 9, 0),
+ datetime(1999, 4, 5, 9, 0),
+ datetime(2000, 4, 24, 9, 0)])
+
+ def testDailyByEasterNeg(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 9, 0),
+ datetime(1999, 4, 3, 9, 0),
+ datetime(2000, 4, 22, 9, 0)])
+
+ def testDailyByHour(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 9, 3, 6, 0),
+ datetime(1997, 9, 3, 18, 0)])
+
+ def testDailyByMinute(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1997, 9, 3, 9, 6)])
+
+ def testDailyBySecond(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 9, 3, 9, 0, 6)])
+
+ def testDailyByHourAndMinute(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1997, 9, 3, 6, 6)])
+
+ def testDailyByHourAndSecond(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 9, 3, 6, 0, 6)])
+
+ def testDailyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testDailyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testDailyBySetPos(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(15, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 15),
+ datetime(1997, 9, 3, 6, 45),
+ datetime(1997, 9, 3, 18, 15)])
+
+ def testHourly(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 10, 0),
+ datetime(1997, 9, 2, 11, 0)])
+
+ def testHourlyInterval(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 11, 0),
+ datetime(1997, 9, 2, 13, 0)])
+
+ def testHourlyIntervalLarge(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ interval=769,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 10, 4, 10, 0),
+ datetime(1997, 11, 5, 11, 0)])
+
+ def testHourlyByMonth(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 1, 0),
+ datetime(1998, 1, 1, 2, 0)])
+
+ def testHourlyByMonthDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 0, 0),
+ datetime(1997, 9, 3, 1, 0),
+ datetime(1997, 9, 3, 2, 0)])
+
+ def testHourlyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 0, 0),
+ datetime(1998, 1, 5, 1, 0),
+ datetime(1998, 1, 5, 2, 0)])
+
+ def testHourlyByWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 10, 0),
+ datetime(1997, 9, 2, 11, 0)])
+
+ def testHourlyByNWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 10, 0),
+ datetime(1997, 9, 2, 11, 0)])
+
+ def testHourlyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 1, 0),
+ datetime(1998, 1, 1, 2, 0)])
+
+ def testHourlyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 1, 0),
+ datetime(1998, 1, 1, 2, 0)])
+
+ def testHourlyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 1, 0),
+ datetime(1998, 1, 1, 2, 0)])
+
+ def testHourlyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 1, 0),
+ datetime(1998, 1, 1, 2, 0)])
+
+ def testHourlyByYearDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0),
+ datetime(1997, 12, 31, 1, 0),
+ datetime(1997, 12, 31, 2, 0),
+ datetime(1997, 12, 31, 3, 0)])
+
+ def testHourlyByYearDayNeg(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0),
+ datetime(1997, 12, 31, 1, 0),
+ datetime(1997, 12, 31, 2, 0),
+ datetime(1997, 12, 31, 3, 0)])
+
+ def testHourlyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0),
+ datetime(1998, 4, 10, 1, 0),
+ datetime(1998, 4, 10, 2, 0),
+ datetime(1998, 4, 10, 3, 0)])
+
+ def testHourlyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0),
+ datetime(1998, 4, 10, 1, 0),
+ datetime(1998, 4, 10, 2, 0),
+ datetime(1998, 4, 10, 3, 0)])
+
+ def testHourlyByWeekNo(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 0, 0),
+ datetime(1998, 5, 11, 1, 0),
+ datetime(1998, 5, 11, 2, 0)])
+
+ def testHourlyByWeekNoAndWeekDay(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 0, 0),
+ datetime(1997, 12, 29, 1, 0),
+ datetime(1997, 12, 29, 2, 0)])
+
+ def testHourlyByWeekNoAndWeekDayLarge(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0),
+ datetime(1997, 12, 28, 1, 0),
+ datetime(1997, 12, 28, 2, 0)])
+
+ def testHourlyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0),
+ datetime(1997, 12, 28, 1, 0),
+ datetime(1997, 12, 28, 2, 0)])
+
+ def testHourlyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 0, 0),
+ datetime(1998, 12, 28, 1, 0),
+ datetime(1998, 12, 28, 2, 0)])
+
+ def testHourlyByEaster(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 0, 0),
+ datetime(1998, 4, 12, 1, 0),
+ datetime(1998, 4, 12, 2, 0)])
+
+ def testHourlyByEasterPos(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 0, 0),
+ datetime(1998, 4, 13, 1, 0),
+ datetime(1998, 4, 13, 2, 0)])
+
+ def testHourlyByEasterNeg(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 0, 0),
+ datetime(1998, 4, 11, 1, 0),
+ datetime(1998, 4, 11, 2, 0)])
+
+ def testHourlyByHour(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 9, 3, 6, 0),
+ datetime(1997, 9, 3, 18, 0)])
+
+ def testHourlyByMinute(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1997, 9, 2, 10, 6)])
+
+ def testHourlyBySecond(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 9, 2, 10, 0, 6)])
+
+ def testHourlyByHourAndMinute(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1997, 9, 3, 6, 6)])
+
+ def testHourlyByHourAndSecond(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 9, 3, 6, 0, 6)])
+
+ def testHourlyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testHourlyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testHourlyBySetPos(self):
+ self.assertEqual(list(rrule(HOURLY,
+ count=3,
+ byminute=(15, 45),
+ bysecond=(15, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 15, 45),
+ datetime(1997, 9, 2, 9, 45, 15),
+ datetime(1997, 9, 2, 10, 15, 45)])
+
+ def testMinutely(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 9, 1),
+ datetime(1997, 9, 2, 9, 2)])
+
+ def testMinutelyInterval(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 9, 2),
+ datetime(1997, 9, 2, 9, 4)])
+
+ def testMinutelyIntervalLarge(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ interval=1501,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 10, 1),
+ datetime(1997, 9, 4, 11, 2)])
+
+ def testMinutelyByMonth(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 0, 1),
+ datetime(1998, 1, 1, 0, 2)])
+
+ def testMinutelyByMonthDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 0, 0),
+ datetime(1997, 9, 3, 0, 1),
+ datetime(1997, 9, 3, 0, 2)])
+
+ def testMinutelyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 0, 0),
+ datetime(1998, 1, 5, 0, 1),
+ datetime(1998, 1, 5, 0, 2)])
+
+ def testMinutelyByWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 9, 1),
+ datetime(1997, 9, 2, 9, 2)])
+
+ def testMinutelyByNWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 2, 9, 1),
+ datetime(1997, 9, 2, 9, 2)])
+
+ def testMinutelyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 0, 1),
+ datetime(1998, 1, 1, 0, 2)])
+
+ def testMinutelyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 0, 1),
+ datetime(1998, 1, 1, 0, 2)])
+
+ def testMinutelyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 0, 1),
+ datetime(1998, 1, 1, 0, 2)])
+
+ def testMinutelyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0),
+ datetime(1998, 1, 1, 0, 1),
+ datetime(1998, 1, 1, 0, 2)])
+
+ def testMinutelyByYearDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0),
+ datetime(1997, 12, 31, 0, 1),
+ datetime(1997, 12, 31, 0, 2),
+ datetime(1997, 12, 31, 0, 3)])
+
+ def testMinutelyByYearDayNeg(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0),
+ datetime(1997, 12, 31, 0, 1),
+ datetime(1997, 12, 31, 0, 2),
+ datetime(1997, 12, 31, 0, 3)])
+
+ def testMinutelyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0),
+ datetime(1998, 4, 10, 0, 1),
+ datetime(1998, 4, 10, 0, 2),
+ datetime(1998, 4, 10, 0, 3)])
+
+ def testMinutelyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0),
+ datetime(1998, 4, 10, 0, 1),
+ datetime(1998, 4, 10, 0, 2),
+ datetime(1998, 4, 10, 0, 3)])
+
+ def testMinutelyByWeekNo(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 0, 0),
+ datetime(1998, 5, 11, 0, 1),
+ datetime(1998, 5, 11, 0, 2)])
+
+ def testMinutelyByWeekNoAndWeekDay(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 0, 0),
+ datetime(1997, 12, 29, 0, 1),
+ datetime(1997, 12, 29, 0, 2)])
+
+ def testMinutelyByWeekNoAndWeekDayLarge(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0),
+ datetime(1997, 12, 28, 0, 1),
+ datetime(1997, 12, 28, 0, 2)])
+
+ def testMinutelyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0),
+ datetime(1997, 12, 28, 0, 1),
+ datetime(1997, 12, 28, 0, 2)])
+
+ def testMinutelyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 0, 0),
+ datetime(1998, 12, 28, 0, 1),
+ datetime(1998, 12, 28, 0, 2)])
+
+ def testMinutelyByEaster(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 0, 0),
+ datetime(1998, 4, 12, 0, 1),
+ datetime(1998, 4, 12, 0, 2)])
+
+ def testMinutelyByEasterPos(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 0, 0),
+ datetime(1998, 4, 13, 0, 1),
+ datetime(1998, 4, 13, 0, 2)])
+
+ def testMinutelyByEasterNeg(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 0, 0),
+ datetime(1998, 4, 11, 0, 1),
+ datetime(1998, 4, 11, 0, 2)])
+
+ def testMinutelyByHour(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0),
+ datetime(1997, 9, 2, 18, 1),
+ datetime(1997, 9, 2, 18, 2)])
+
+ def testMinutelyByMinute(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6),
+ datetime(1997, 9, 2, 9, 18),
+ datetime(1997, 9, 2, 10, 6)])
+
+ def testMinutelyBySecond(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 9, 2, 9, 1, 6)])
+
+ def testMinutelyByHourAndMinute(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6),
+ datetime(1997, 9, 2, 18, 18),
+ datetime(1997, 9, 3, 6, 6)])
+
+ def testMinutelyByHourAndSecond(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 9, 2, 18, 1, 6)])
+
+ def testMinutelyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testMinutelyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testMinutelyBySetPos(self):
+ self.assertEqual(list(rrule(MINUTELY,
+ count=3,
+ bysecond=(15, 30, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 15),
+ datetime(1997, 9, 2, 9, 0, 45),
+ datetime(1997, 9, 2, 9, 1, 15)])
+
+ def testSecondly(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1997, 9, 2, 9, 0, 1),
+ datetime(1997, 9, 2, 9, 0, 2)])
+
+ def testSecondlyInterval(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1997, 9, 2, 9, 0, 2),
+ datetime(1997, 9, 2, 9, 0, 4)])
+
+ def testSecondlyIntervalLarge(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ interval=90061,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1997, 9, 3, 10, 1, 1),
+ datetime(1997, 9, 4, 11, 2, 2)])
+
+ def testSecondlyByMonth(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0, 0),
+ datetime(1998, 1, 1, 0, 0, 1),
+ datetime(1998, 1, 1, 0, 0, 2)])
+
+ def testSecondlyByMonthDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 3, 0, 0, 0),
+ datetime(1997, 9, 3, 0, 0, 1),
+ datetime(1997, 9, 3, 0, 0, 2)])
+
+ def testSecondlyByMonthAndMonthDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 0, 0, 0),
+ datetime(1998, 1, 5, 0, 0, 1),
+ datetime(1998, 1, 5, 0, 0, 2)])
+
+ def testSecondlyByWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1997, 9, 2, 9, 0, 1),
+ datetime(1997, 9, 2, 9, 0, 2)])
+
+ def testSecondlyByNWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1997, 9, 2, 9, 0, 1),
+ datetime(1997, 9, 2, 9, 0, 2)])
+
+ def testSecondlyByMonthAndWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0, 0),
+ datetime(1998, 1, 1, 0, 0, 1),
+ datetime(1998, 1, 1, 0, 0, 2)])
+
+ def testSecondlyByMonthAndNWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0, 0),
+ datetime(1998, 1, 1, 0, 0, 1),
+ datetime(1998, 1, 1, 0, 0, 2)])
+
+ def testSecondlyByMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0, 0),
+ datetime(1998, 1, 1, 0, 0, 1),
+ datetime(1998, 1, 1, 0, 0, 2)])
+
+ def testSecondlyByMonthAndMonthDayAndWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 1, 0, 0, 0),
+ datetime(1998, 1, 1, 0, 0, 1),
+ datetime(1998, 1, 1, 0, 0, 2)])
+
+ def testSecondlyByYearDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0, 0),
+ datetime(1997, 12, 31, 0, 0, 1),
+ datetime(1997, 12, 31, 0, 0, 2),
+ datetime(1997, 12, 31, 0, 0, 3)])
+
+ def testSecondlyByYearDayNeg(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 31, 0, 0, 0),
+ datetime(1997, 12, 31, 0, 0, 1),
+ datetime(1997, 12, 31, 0, 0, 2),
+ datetime(1997, 12, 31, 0, 0, 3)])
+
+ def testSecondlyByMonthAndYearDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0, 0),
+ datetime(1998, 4, 10, 0, 0, 1),
+ datetime(1998, 4, 10, 0, 0, 2),
+ datetime(1998, 4, 10, 0, 0, 3)])
+
+ def testSecondlyByMonthAndYearDayNeg(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 10, 0, 0, 0),
+ datetime(1998, 4, 10, 0, 0, 1),
+ datetime(1998, 4, 10, 0, 0, 2),
+ datetime(1998, 4, 10, 0, 0, 3)])
+
+ def testSecondlyByWeekNo(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 5, 11, 0, 0, 0),
+ datetime(1998, 5, 11, 0, 0, 1),
+ datetime(1998, 5, 11, 0, 0, 2)])
+
+ def testSecondlyByWeekNoAndWeekDay(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 29, 0, 0, 0),
+ datetime(1997, 12, 29, 0, 0, 1),
+ datetime(1997, 12, 29, 0, 0, 2)])
+
+ def testSecondlyByWeekNoAndWeekDayLarge(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0, 0),
+ datetime(1997, 12, 28, 0, 0, 1),
+ datetime(1997, 12, 28, 0, 0, 2)])
+
+ def testSecondlyByWeekNoAndWeekDayLast(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 12, 28, 0, 0, 0),
+ datetime(1997, 12, 28, 0, 0, 1),
+ datetime(1997, 12, 28, 0, 0, 2)])
+
+ def testSecondlyByWeekNoAndWeekDay53(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 12, 28, 0, 0, 0),
+ datetime(1998, 12, 28, 0, 0, 1),
+ datetime(1998, 12, 28, 0, 0, 2)])
+
+ def testSecondlyByEaster(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 12, 0, 0, 0),
+ datetime(1998, 4, 12, 0, 0, 1),
+ datetime(1998, 4, 12, 0, 0, 2)])
+
+ def testSecondlyByEasterPos(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 13, 0, 0, 0),
+ datetime(1998, 4, 13, 0, 0, 1),
+ datetime(1998, 4, 13, 0, 0, 2)])
+
+ def testSecondlyByEasterNeg(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 4, 11, 0, 0, 0),
+ datetime(1998, 4, 11, 0, 0, 1),
+ datetime(1998, 4, 11, 0, 0, 2)])
+
+ def testSecondlyByHour(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 0),
+ datetime(1997, 9, 2, 18, 0, 1),
+ datetime(1997, 9, 2, 18, 0, 2)])
+
+ def testSecondlyByMinute(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 0),
+ datetime(1997, 9, 2, 9, 6, 1),
+ datetime(1997, 9, 2, 9, 6, 2)])
+
+ def testSecondlyBySecond(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0, 6),
+ datetime(1997, 9, 2, 9, 0, 18),
+ datetime(1997, 9, 2, 9, 1, 6)])
+
+ def testSecondlyByHourAndMinute(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 0),
+ datetime(1997, 9, 2, 18, 6, 1),
+ datetime(1997, 9, 2, 18, 6, 2)])
+
+ def testSecondlyByHourAndSecond(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 0, 6),
+ datetime(1997, 9, 2, 18, 0, 18),
+ datetime(1997, 9, 2, 18, 1, 6)])
+
+ def testSecondlyByMinuteAndSecond(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 6, 6),
+ datetime(1997, 9, 2, 9, 6, 18),
+ datetime(1997, 9, 2, 9, 18, 6)])
+
+ def testSecondlyByHourAndMinuteAndSecond(self):
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 18, 6, 6),
+ datetime(1997, 9, 2, 18, 6, 18),
+ datetime(1997, 9, 2, 18, 18, 6)])
+
+ def testSecondlyByHourAndMinuteAndSecondBug(self):
+ # This explores a bug found by Mathieu Bridon.
+ self.assertEqual(list(rrule(SECONDLY,
+ count=3,
+ bysecond=(0,),
+ byminute=(1,),
+ dtstart=datetime(2010, 3, 22, 12, 1))),
+ [datetime(2010, 3, 22, 12, 1),
+ datetime(2010, 3, 22, 13, 1),
+ datetime(2010, 3, 22, 14, 1)])
+
+ def testLongIntegers(self):
if PY2: # There are no longs in python3
- self.assertEqual(list(rrule(MINUTELY,
- count=long(2),
- interval=long(2),
- bymonth=long(2),
- byweekday=long(3),
- byhour=long(6),
- byminute=long(6),
- bysecond=long(6),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 2, 5, 6, 6, 6),
- datetime(1998, 2, 12, 6, 6, 6)])
- self.assertEqual(list(rrule(YEARLY,
- count=long(2),
- bymonthday=long(5),
- byweekno=long(2),
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1998, 1, 5, 9, 0),
- datetime(2004, 1, 5, 9, 0)])
-
- def testHourlyBadRRule(self):
- """
- When `byhour` is specified with `freq=HOURLY`, there are certain
- combinations of `dtstart` and `byhour` which result in an rrule with no
- valid values.
-
- See https://github.com/dateutil/dateutil/issues/4
- """
-
- self.assertRaises(ValueError, rrule, HOURLY,
- **dict(interval=4, byhour=(7, 11, 15, 19),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testMinutelyBadRRule(self):
- """
- See :func:`testHourlyBadRRule` for details.
- """
-
- self.assertRaises(ValueError, rrule, MINUTELY,
- **dict(interval=12, byminute=(10, 11, 25, 39, 50),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testSecondlyBadRRule(self):
- """
- See :func:`testHourlyBadRRule` for details.
- """
-
- self.assertRaises(ValueError, rrule, SECONDLY,
- **dict(interval=10, bysecond=(2, 15, 37, 42, 59),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testMinutelyBadComboRRule(self):
- """
- Certain values of :param:`interval` in :class:`rrule`, when combined
- with certain values of :param:`byhour` create rules which apply to no
- valid dates. The library should detect this case in the iterator and
- raise a :exception:`ValueError`.
- """
-
- # In Python 2.7 you can use a context manager for this.
- def make_bad_rrule():
- list(rrule(MINUTELY, interval=120, byhour=(10, 12, 14, 16),
- count=2, dtstart=datetime(1997, 9, 2, 9, 0)))
-
- self.assertRaises(ValueError, make_bad_rrule)
-
- def testSecondlyBadComboRRule(self):
- """
- See :func:`testMinutelyBadComboRRule' for details.
- """
-
- # In Python 2.7 you can use a context manager for this.
- def make_bad_minute_rrule():
- list(rrule(SECONDLY, interval=360, byminute=(10, 28, 49),
- count=4, dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def make_bad_hour_rrule():
- list(rrule(SECONDLY, interval=43200, byhour=(2, 10, 18, 23),
- count=4, dtstart=datetime(1997, 9, 2, 9, 0)))
-
- self.assertRaises(ValueError, make_bad_minute_rrule)
- self.assertRaises(ValueError, make_bad_hour_rrule)
-
- def testBadUntilCountRRule(self):
- """
- See rfc-5545 3.3.10 - This checks for the deprecation warning, and will
- eventually check for an error.
- """
+ self.assertEqual(list(rrule(MINUTELY,
+ count=long(2),
+ interval=long(2),
+ bymonth=long(2),
+ byweekday=long(3),
+ byhour=long(6),
+ byminute=long(6),
+ bysecond=long(6),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 2, 5, 6, 6, 6),
+ datetime(1998, 2, 12, 6, 6, 6)])
+ self.assertEqual(list(rrule(YEARLY,
+ count=long(2),
+ bymonthday=long(5),
+ byweekno=long(2),
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1998, 1, 5, 9, 0),
+ datetime(2004, 1, 5, 9, 0)])
+
+ def testHourlyBadRRule(self):
+ """
+ When `byhour` is specified with `freq=HOURLY`, there are certain
+ combinations of `dtstart` and `byhour` which result in an rrule with no
+ valid values.
+
+ See https://github.com/dateutil/dateutil/issues/4
+ """
+
+ self.assertRaises(ValueError, rrule, HOURLY,
+ **dict(interval=4, byhour=(7, 11, 15, 19),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testMinutelyBadRRule(self):
+ """
+ See :func:`testHourlyBadRRule` for details.
+ """
+
+ self.assertRaises(ValueError, rrule, MINUTELY,
+ **dict(interval=12, byminute=(10, 11, 25, 39, 50),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testSecondlyBadRRule(self):
+ """
+ See :func:`testHourlyBadRRule` for details.
+ """
+
+ self.assertRaises(ValueError, rrule, SECONDLY,
+ **dict(interval=10, bysecond=(2, 15, 37, 42, 59),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testMinutelyBadComboRRule(self):
+ """
+ Certain values of :param:`interval` in :class:`rrule`, when combined
+ with certain values of :param:`byhour` create rules which apply to no
+ valid dates. The library should detect this case in the iterator and
+ raise a :exception:`ValueError`.
+ """
+
+ # In Python 2.7 you can use a context manager for this.
+ def make_bad_rrule():
+ list(rrule(MINUTELY, interval=120, byhour=(10, 12, 14, 16),
+ count=2, dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ self.assertRaises(ValueError, make_bad_rrule)
+
+ def testSecondlyBadComboRRule(self):
+ """
+ See :func:`testMinutelyBadComboRRule' for details.
+ """
+
+ # In Python 2.7 you can use a context manager for this.
+ def make_bad_minute_rrule():
+ list(rrule(SECONDLY, interval=360, byminute=(10, 28, 49),
+ count=4, dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def make_bad_hour_rrule():
+ list(rrule(SECONDLY, interval=43200, byhour=(2, 10, 18, 23),
+ count=4, dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ self.assertRaises(ValueError, make_bad_minute_rrule)
+ self.assertRaises(ValueError, make_bad_hour_rrule)
+
+ def testBadUntilCountRRule(self):
+ """
+ See rfc-5545 3.3.10 - This checks for the deprecation warning, and will
+ eventually check for an error.
+ """
with pytest.warns(DeprecationWarning):
- rrule(DAILY, dtstart=datetime(1997, 9, 2, 9, 0),
- count=3, until=datetime(1997, 9, 4, 9, 0))
-
- def testUntilNotMatching(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0),
- until=datetime(1997, 9, 5, 8, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testUntilMatching(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0),
- until=datetime(1997, 9, 4, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testUntilSingle(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0),
- until=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0)])
-
- def testUntilEmpty(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0),
- until=datetime(1997, 9, 1, 9, 0))),
- [])
-
- def testUntilWithDate(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0),
- until=date(1997, 9, 5))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testWkStIntervalMO(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- interval=2,
- byweekday=(TU, SU),
- wkst=MO,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 7, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testWkStIntervalSU(self):
- self.assertEqual(list(rrule(WEEKLY,
- count=3,
- interval=2,
- byweekday=(TU, SU),
- wkst=SU,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testDTStartIsDate(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- dtstart=date(1997, 9, 2))),
- [datetime(1997, 9, 2, 0, 0),
- datetime(1997, 9, 3, 0, 0),
- datetime(1997, 9, 4, 0, 0)])
-
- def testDTStartWithMicroseconds(self):
- self.assertEqual(list(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0, 0, 500000))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testMaxYear(self):
- self.assertEqual(list(rrule(YEARLY,
- count=3,
- bymonth=2,
- bymonthday=31,
- dtstart=datetime(9997, 9, 2, 9, 0, 0))),
- [])
-
- def testGetItem(self):
- self.assertEqual(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))[0],
- datetime(1997, 9, 2, 9, 0))
-
- def testGetItemNeg(self):
- self.assertEqual(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))[-1],
- datetime(1997, 9, 4, 9, 0))
-
- def testGetItemSlice(self):
- self.assertEqual(rrule(DAILY,
- # count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))[1:2],
- [datetime(1997, 9, 3, 9, 0)])
-
- def testGetItemSliceEmpty(self):
- self.assertEqual(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))[:],
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0)])
-
- def testGetItemSliceStep(self):
- self.assertEqual(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0))[::-2],
- [datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 2, 9, 0)])
-
- def testCount(self):
- self.assertEqual(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)).count(),
- 3)
-
- def testCountZero(self):
- self.assertEqual(rrule(YEARLY,
- count=0,
- dtstart=datetime(1997, 9, 2, 9, 0)).count(),
- 0)
-
- def testContains(self):
- rr = rrule(DAILY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
- self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
-
- def testContainsNot(self):
- rr = rrule(DAILY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
- self.assertEqual(datetime(1997, 9, 3, 9, 0) not in rr, False)
-
- def testBefore(self):
- self.assertEqual(rrule(DAILY, # count=5
- dtstart=datetime(1997, 9, 2, 9, 0)).before(datetime(1997, 9, 5, 9, 0)),
- datetime(1997, 9, 4, 9, 0))
-
- def testBeforeInc(self):
- self.assertEqual(rrule(DAILY,
- #count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .before(datetime(1997, 9, 5, 9, 0), inc=True),
- datetime(1997, 9, 5, 9, 0))
-
- def testAfter(self):
- self.assertEqual(rrule(DAILY,
- #count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .after(datetime(1997, 9, 4, 9, 0)),
- datetime(1997, 9, 5, 9, 0))
-
- def testAfterInc(self):
- self.assertEqual(rrule(DAILY,
- #count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .after(datetime(1997, 9, 4, 9, 0), inc=True),
- datetime(1997, 9, 4, 9, 0))
-
- def testXAfter(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .xafter(datetime(1997, 9, 8, 9, 0), count=12)),
- [datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 10, 9, 0),
- datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 12, 9, 0),
- datetime(1997, 9, 13, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 15, 9, 0),
- datetime(1997, 9, 16, 9, 0),
- datetime(1997, 9, 17, 9, 0),
- datetime(1997, 9, 18, 9, 0),
- datetime(1997, 9, 19, 9, 0),
- datetime(1997, 9, 20, 9, 0)])
-
- def testXAfterInc(self):
- self.assertEqual(list(rrule(DAILY,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .xafter(datetime(1997, 9, 8, 9, 0), count=12, inc=True)),
- [datetime(1997, 9, 8, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 10, 9, 0),
- datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 12, 9, 0),
- datetime(1997, 9, 13, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 15, 9, 0),
- datetime(1997, 9, 16, 9, 0),
- datetime(1997, 9, 17, 9, 0),
- datetime(1997, 9, 18, 9, 0),
- datetime(1997, 9, 19, 9, 0)])
-
- def testBetween(self):
- self.assertEqual(rrule(DAILY,
- #count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .between(datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 6, 9, 0)),
- [datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 5, 9, 0)])
-
- def testBetweenInc(self):
- self.assertEqual(rrule(DAILY,
- #count=5,
- dtstart=datetime(1997, 9, 2, 9, 0))
- .between(datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 6, 9, 0), inc=True),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 5, 9, 0),
- datetime(1997, 9, 6, 9, 0)])
-
- def testCachePre(self):
- rr = rrule(DAILY, count=15, cache=True,
- dtstart=datetime(1997, 9, 2, 9, 0))
- self.assertEqual(list(rr),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 5, 9, 0),
- datetime(1997, 9, 6, 9, 0),
- datetime(1997, 9, 7, 9, 0),
- datetime(1997, 9, 8, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 10, 9, 0),
- datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 12, 9, 0),
- datetime(1997, 9, 13, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 15, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testCachePost(self):
- rr = rrule(DAILY, count=15, cache=True,
- dtstart=datetime(1997, 9, 2, 9, 0))
- for x in rr: pass
- self.assertEqual(list(rr),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 5, 9, 0),
- datetime(1997, 9, 6, 9, 0),
- datetime(1997, 9, 7, 9, 0),
- datetime(1997, 9, 8, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 10, 9, 0),
- datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 12, 9, 0),
- datetime(1997, 9, 13, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 15, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testCachePostInternal(self):
- rr = rrule(DAILY, count=15, cache=True,
- dtstart=datetime(1997, 9, 2, 9, 0))
- for x in rr: pass
- self.assertEqual(rr._cache,
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 3, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 5, 9, 0),
- datetime(1997, 9, 6, 9, 0),
- datetime(1997, 9, 7, 9, 0),
- datetime(1997, 9, 8, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 10, 9, 0),
- datetime(1997, 9, 11, 9, 0),
- datetime(1997, 9, 12, 9, 0),
- datetime(1997, 9, 13, 9, 0),
- datetime(1997, 9, 14, 9, 0),
- datetime(1997, 9, 15, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testCachePreContains(self):
- rr = rrule(DAILY, count=3, cache=True,
- dtstart=datetime(1997, 9, 2, 9, 0))
- self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
-
- def testCachePostContains(self):
- rr = rrule(DAILY, count=3, cache=True,
- dtstart=datetime(1997, 9, 2, 9, 0))
- for x in rr: pass
- self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
-
- def testStr(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrWithTZID(self):
- NYC = tz.gettz('America/New_York')
- self.assertEqual(list(rrulestr(
- "DTSTART;TZID=America/New_York:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3\n"
- )),
- [datetime(1997, 9, 2, 9, 0, tzinfo=NYC),
- datetime(1998, 9, 2, 9, 0, tzinfo=NYC),
- datetime(1999, 9, 2, 9, 0, tzinfo=NYC)])
-
- def testStrWithTZIDMapping(self):
- rrstr = ("DTSTART;TZID=Eastern:19970902T090000\n" +
- "RRULE:FREQ=YEARLY;COUNT=3")
-
- NYC = tz.gettz('America/New_York')
- rr = rrulestr(rrstr, tzids={'Eastern': NYC})
- exp = [datetime(1997, 9, 2, 9, 0, tzinfo=NYC),
- datetime(1998, 9, 2, 9, 0, tzinfo=NYC),
- datetime(1999, 9, 2, 9, 0, tzinfo=NYC)]
-
- self.assertEqual(list(rr), exp)
-
- def testStrWithTZIDCallable(self):
- rrstr = ('DTSTART;TZID=UTC+04:19970902T090000\n' +
- 'RRULE:FREQ=YEARLY;COUNT=3')
-
- TZ = tz.tzstr('UTC+04')
- def parse_tzstr(tzstr):
- if tzstr is None:
- raise ValueError('Invalid tzstr')
-
- return tz.tzstr(tzstr)
-
- rr = rrulestr(rrstr, tzids=parse_tzstr)
-
- exp = [datetime(1997, 9, 2, 9, 0, tzinfo=TZ),
- datetime(1998, 9, 2, 9, 0, tzinfo=TZ),
- datetime(1999, 9, 2, 9, 0, tzinfo=TZ),]
-
- self.assertEqual(list(rr), exp)
-
- def testStrWithTZIDCallableFailure(self):
- rrstr = ('DTSTART;TZID=America/New_York:19970902T090000\n' +
- 'RRULE:FREQ=YEARLY;COUNT=3')
-
- class TzInfoError(Exception):
- pass
-
- def tzinfos(tzstr):
- if tzstr == 'America/New_York':
- raise TzInfoError('Invalid!')
- return None
-
- with self.assertRaises(TzInfoError):
- rrulestr(rrstr, tzids=tzinfos)
-
- def testStrWithConflictingTZID(self):
- # RFC 5545 Section 3.3.5, FORM #2: DATE WITH UTC TIME
- # https://tools.ietf.org/html/rfc5545#section-3.3.5
- # The "TZID" property parameter MUST NOT be applied to DATE-TIME
- with self.assertRaises(ValueError):
- rrulestr("DTSTART;TZID=America/New_York:19970902T090000Z\n"+
- "RRULE:FREQ=YEARLY;COUNT=3\n")
-
- def testStrType(self):
- self.assertEqual(isinstance(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3\n"
- ), rrule), True)
-
- def testStrForceSetType(self):
- self.assertEqual(isinstance(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3\n"
- , forceset=True), rruleset), True)
-
- def testStrSetType(self):
- self.assertEqual(isinstance(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU\n"
- "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH\n"
- ), rruleset), True)
-
- def testStrCase(self):
- self.assertEqual(list(rrulestr(
- "dtstart:19970902T090000\n"
- "rrule:freq=yearly;count=3\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrSpaces(self):
- self.assertEqual(list(rrulestr(
- " DTSTART:19970902T090000 "
- " RRULE:FREQ=YEARLY;COUNT=3 "
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrSpacesAndLines(self):
- self.assertEqual(list(rrulestr(
- " DTSTART:19970902T090000 \n"
- " \n"
- " RRULE:FREQ=YEARLY;COUNT=3 \n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrNoDTStart(self):
- self.assertEqual(list(rrulestr(
- "RRULE:FREQ=YEARLY;COUNT=3\n"
- , dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrValueOnly(self):
- self.assertEqual(list(rrulestr(
- "FREQ=YEARLY;COUNT=3\n"
- , dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrUnfold(self):
- self.assertEqual(list(rrulestr(
- "FREQ=YEA\n RLY;COUNT=3\n", unfold=True,
- dtstart=datetime(1997, 9, 2, 9, 0))),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1998, 9, 2, 9, 0),
- datetime(1999, 9, 2, 9, 0)])
-
- def testStrSet(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU\n"
- "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testStrSetDate(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TU\n"
- "RDATE:19970904T090000\n"
- "RDATE:19970909T090000\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testStrSetExRule(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=6;BYDAY=TU,TH\n"
- "EXRULE:FREQ=YEARLY;COUNT=3;BYDAY=TH\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testStrSetExDate(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=6;BYDAY=TU,TH\n"
- "EXDATE:19970904T090000\n"
- "EXDATE:19970911T090000\n"
- "EXDATE:19970918T090000\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
+ rrule(DAILY, dtstart=datetime(1997, 9, 2, 9, 0),
+ count=3, until=datetime(1997, 9, 4, 9, 0))
+
+ def testUntilNotMatching(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0),
+ until=datetime(1997, 9, 5, 8, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testUntilMatching(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0),
+ until=datetime(1997, 9, 4, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testUntilSingle(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0),
+ until=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0)])
+
+ def testUntilEmpty(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0),
+ until=datetime(1997, 9, 1, 9, 0))),
+ [])
+
+ def testUntilWithDate(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0),
+ until=date(1997, 9, 5))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testWkStIntervalMO(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ interval=2,
+ byweekday=(TU, SU),
+ wkst=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 7, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testWkStIntervalSU(self):
+ self.assertEqual(list(rrule(WEEKLY,
+ count=3,
+ interval=2,
+ byweekday=(TU, SU),
+ wkst=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testDTStartIsDate(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ dtstart=date(1997, 9, 2))),
+ [datetime(1997, 9, 2, 0, 0),
+ datetime(1997, 9, 3, 0, 0),
+ datetime(1997, 9, 4, 0, 0)])
+
+ def testDTStartWithMicroseconds(self):
+ self.assertEqual(list(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0, 0, 500000))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testMaxYear(self):
+ self.assertEqual(list(rrule(YEARLY,
+ count=3,
+ bymonth=2,
+ bymonthday=31,
+ dtstart=datetime(9997, 9, 2, 9, 0, 0))),
+ [])
+
+ def testGetItem(self):
+ self.assertEqual(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))[0],
+ datetime(1997, 9, 2, 9, 0))
+
+ def testGetItemNeg(self):
+ self.assertEqual(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))[-1],
+ datetime(1997, 9, 4, 9, 0))
+
+ def testGetItemSlice(self):
+ self.assertEqual(rrule(DAILY,
+ # count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))[1:2],
+ [datetime(1997, 9, 3, 9, 0)])
+
+ def testGetItemSliceEmpty(self):
+ self.assertEqual(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))[:],
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0)])
+
+ def testGetItemSliceStep(self):
+ self.assertEqual(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0))[::-2],
+ [datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 2, 9, 0)])
+
+ def testCount(self):
+ self.assertEqual(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)).count(),
+ 3)
+
+ def testCountZero(self):
+ self.assertEqual(rrule(YEARLY,
+ count=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)).count(),
+ 0)
+
+ def testContains(self):
+ rr = rrule(DAILY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
+ self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
+
+ def testContainsNot(self):
+ rr = rrule(DAILY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
+ self.assertEqual(datetime(1997, 9, 3, 9, 0) not in rr, False)
+
+ def testBefore(self):
+ self.assertEqual(rrule(DAILY, # count=5
+ dtstart=datetime(1997, 9, 2, 9, 0)).before(datetime(1997, 9, 5, 9, 0)),
+ datetime(1997, 9, 4, 9, 0))
+
+ def testBeforeInc(self):
+ self.assertEqual(rrule(DAILY,
+ #count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .before(datetime(1997, 9, 5, 9, 0), inc=True),
+ datetime(1997, 9, 5, 9, 0))
+
+ def testAfter(self):
+ self.assertEqual(rrule(DAILY,
+ #count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .after(datetime(1997, 9, 4, 9, 0)),
+ datetime(1997, 9, 5, 9, 0))
+
+ def testAfterInc(self):
+ self.assertEqual(rrule(DAILY,
+ #count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .after(datetime(1997, 9, 4, 9, 0), inc=True),
+ datetime(1997, 9, 4, 9, 0))
+
+ def testXAfter(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .xafter(datetime(1997, 9, 8, 9, 0), count=12)),
+ [datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 10, 9, 0),
+ datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 12, 9, 0),
+ datetime(1997, 9, 13, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 15, 9, 0),
+ datetime(1997, 9, 16, 9, 0),
+ datetime(1997, 9, 17, 9, 0),
+ datetime(1997, 9, 18, 9, 0),
+ datetime(1997, 9, 19, 9, 0),
+ datetime(1997, 9, 20, 9, 0)])
+
+ def testXAfterInc(self):
+ self.assertEqual(list(rrule(DAILY,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .xafter(datetime(1997, 9, 8, 9, 0), count=12, inc=True)),
+ [datetime(1997, 9, 8, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 10, 9, 0),
+ datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 12, 9, 0),
+ datetime(1997, 9, 13, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 15, 9, 0),
+ datetime(1997, 9, 16, 9, 0),
+ datetime(1997, 9, 17, 9, 0),
+ datetime(1997, 9, 18, 9, 0),
+ datetime(1997, 9, 19, 9, 0)])
+
+ def testBetween(self):
+ self.assertEqual(rrule(DAILY,
+ #count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .between(datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 6, 9, 0)),
+ [datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 5, 9, 0)])
+
+ def testBetweenInc(self):
+ self.assertEqual(rrule(DAILY,
+ #count=5,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ .between(datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 6, 9, 0), inc=True),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 5, 9, 0),
+ datetime(1997, 9, 6, 9, 0)])
+
+ def testCachePre(self):
+ rr = rrule(DAILY, count=15, cache=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ self.assertEqual(list(rr),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 5, 9, 0),
+ datetime(1997, 9, 6, 9, 0),
+ datetime(1997, 9, 7, 9, 0),
+ datetime(1997, 9, 8, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 10, 9, 0),
+ datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 12, 9, 0),
+ datetime(1997, 9, 13, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 15, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testCachePost(self):
+ rr = rrule(DAILY, count=15, cache=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ for x in rr: pass
+ self.assertEqual(list(rr),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 5, 9, 0),
+ datetime(1997, 9, 6, 9, 0),
+ datetime(1997, 9, 7, 9, 0),
+ datetime(1997, 9, 8, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 10, 9, 0),
+ datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 12, 9, 0),
+ datetime(1997, 9, 13, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 15, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testCachePostInternal(self):
+ rr = rrule(DAILY, count=15, cache=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ for x in rr: pass
+ self.assertEqual(rr._cache,
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 3, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 5, 9, 0),
+ datetime(1997, 9, 6, 9, 0),
+ datetime(1997, 9, 7, 9, 0),
+ datetime(1997, 9, 8, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 10, 9, 0),
+ datetime(1997, 9, 11, 9, 0),
+ datetime(1997, 9, 12, 9, 0),
+ datetime(1997, 9, 13, 9, 0),
+ datetime(1997, 9, 14, 9, 0),
+ datetime(1997, 9, 15, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testCachePreContains(self):
+ rr = rrule(DAILY, count=3, cache=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
+
+ def testCachePostContains(self):
+ rr = rrule(DAILY, count=3, cache=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ for x in rr: pass
+ self.assertEqual(datetime(1997, 9, 3, 9, 0) in rr, True)
+
+ def testStr(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrWithTZID(self):
+ NYC = tz.gettz('America/New_York')
+ self.assertEqual(list(rrulestr(
+ "DTSTART;TZID=America/New_York:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0, tzinfo=NYC),
+ datetime(1998, 9, 2, 9, 0, tzinfo=NYC),
+ datetime(1999, 9, 2, 9, 0, tzinfo=NYC)])
+
+ def testStrWithTZIDMapping(self):
+ rrstr = ("DTSTART;TZID=Eastern:19970902T090000\n" +
+ "RRULE:FREQ=YEARLY;COUNT=3")
+
+ NYC = tz.gettz('America/New_York')
+ rr = rrulestr(rrstr, tzids={'Eastern': NYC})
+ exp = [datetime(1997, 9, 2, 9, 0, tzinfo=NYC),
+ datetime(1998, 9, 2, 9, 0, tzinfo=NYC),
+ datetime(1999, 9, 2, 9, 0, tzinfo=NYC)]
+
+ self.assertEqual(list(rr), exp)
+
+ def testStrWithTZIDCallable(self):
+ rrstr = ('DTSTART;TZID=UTC+04:19970902T090000\n' +
+ 'RRULE:FREQ=YEARLY;COUNT=3')
+
+ TZ = tz.tzstr('UTC+04')
+ def parse_tzstr(tzstr):
+ if tzstr is None:
+ raise ValueError('Invalid tzstr')
+
+ return tz.tzstr(tzstr)
+
+ rr = rrulestr(rrstr, tzids=parse_tzstr)
+
+ exp = [datetime(1997, 9, 2, 9, 0, tzinfo=TZ),
+ datetime(1998, 9, 2, 9, 0, tzinfo=TZ),
+ datetime(1999, 9, 2, 9, 0, tzinfo=TZ),]
+
+ self.assertEqual(list(rr), exp)
+
+ def testStrWithTZIDCallableFailure(self):
+ rrstr = ('DTSTART;TZID=America/New_York:19970902T090000\n' +
+ 'RRULE:FREQ=YEARLY;COUNT=3')
+
+ class TzInfoError(Exception):
+ pass
+
+ def tzinfos(tzstr):
+ if tzstr == 'America/New_York':
+ raise TzInfoError('Invalid!')
+ return None
+
+ with self.assertRaises(TzInfoError):
+ rrulestr(rrstr, tzids=tzinfos)
+
+ def testStrWithConflictingTZID(self):
+ # RFC 5545 Section 3.3.5, FORM #2: DATE WITH UTC TIME
+ # https://tools.ietf.org/html/rfc5545#section-3.3.5
+ # The "TZID" property parameter MUST NOT be applied to DATE-TIME
+ with self.assertRaises(ValueError):
+ rrulestr("DTSTART;TZID=America/New_York:19970902T090000Z\n"+
+ "RRULE:FREQ=YEARLY;COUNT=3\n")
+
+ def testStrType(self):
+ self.assertEqual(isinstance(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3\n"
+ ), rrule), True)
+
+ def testStrForceSetType(self):
+ self.assertEqual(isinstance(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3\n"
+ , forceset=True), rruleset), True)
+
+ def testStrSetType(self):
+ self.assertEqual(isinstance(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU\n"
+ "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH\n"
+ ), rruleset), True)
+
+ def testStrCase(self):
+ self.assertEqual(list(rrulestr(
+ "dtstart:19970902T090000\n"
+ "rrule:freq=yearly;count=3\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrSpaces(self):
+ self.assertEqual(list(rrulestr(
+ " DTSTART:19970902T090000 "
+ " RRULE:FREQ=YEARLY;COUNT=3 "
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrSpacesAndLines(self):
+ self.assertEqual(list(rrulestr(
+ " DTSTART:19970902T090000 \n"
+ " \n"
+ " RRULE:FREQ=YEARLY;COUNT=3 \n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrNoDTStart(self):
+ self.assertEqual(list(rrulestr(
+ "RRULE:FREQ=YEARLY;COUNT=3\n"
+ , dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrValueOnly(self):
+ self.assertEqual(list(rrulestr(
+ "FREQ=YEARLY;COUNT=3\n"
+ , dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrUnfold(self):
+ self.assertEqual(list(rrulestr(
+ "FREQ=YEA\n RLY;COUNT=3\n", unfold=True,
+ dtstart=datetime(1997, 9, 2, 9, 0))),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1998, 9, 2, 9, 0),
+ datetime(1999, 9, 2, 9, 0)])
+
+ def testStrSet(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU\n"
+ "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testStrSetDate(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TU\n"
+ "RDATE:19970904T090000\n"
+ "RDATE:19970909T090000\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testStrSetExRule(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=6;BYDAY=TU,TH\n"
+ "EXRULE:FREQ=YEARLY;COUNT=3;BYDAY=TH\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testStrSetExDate(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=6;BYDAY=TU,TH\n"
+ "EXDATE:19970904T090000\n"
+ "EXDATE:19970911T090000\n"
+ "EXDATE:19970918T090000\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
def testStrSetExDateMultiple(self):
rrstr = ("DTSTART:19970902T090000\n"
"RRULE:FREQ=YEARLY;COUNT=6;BYDAY=TU,TH\n"
@@ -2920,1995 +2920,1995 @@ class RRuleTest(unittest.TestCase):
rr = rrulestr(rrstr)
assert list(rr) == [datetime(1997, 9, 4), datetime(1997, 9, 11)]
- def testStrSetDateAndExDate(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RDATE:19970902T090000\n"
- "RDATE:19970904T090000\n"
- "RDATE:19970909T090000\n"
- "RDATE:19970911T090000\n"
- "RDATE:19970916T090000\n"
- "RDATE:19970918T090000\n"
- "EXDATE:19970904T090000\n"
- "EXDATE:19970911T090000\n"
- "EXDATE:19970918T090000\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testStrSetDateAndExRule(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RDATE:19970902T090000\n"
- "RDATE:19970904T090000\n"
- "RDATE:19970909T090000\n"
- "RDATE:19970911T090000\n"
- "RDATE:19970916T090000\n"
- "RDATE:19970918T090000\n"
- "EXRULE:FREQ=YEARLY;COUNT=3;BYDAY=TH\n"
- )),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testStrKeywords(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3;INTERVAL=3;"
- "BYMONTH=3;BYWEEKDAY=TH;BYMONTHDAY=3;"
- "BYHOUR=3;BYMINUTE=3;BYSECOND=3\n"
- )),
- [datetime(2033, 3, 3, 3, 3, 3),
- datetime(2039, 3, 3, 3, 3, 3),
- datetime(2072, 3, 3, 3, 3, 3)])
-
- def testStrNWeekDay(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=3;BYDAY=1TU,-1TH\n"
- )),
- [datetime(1997, 12, 25, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 12, 31, 9, 0)])
-
- def testStrUntil(self):
- self.assertEqual(list(rrulestr(
- "DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;"
- "UNTIL=19990101T000000;BYDAY=1TU,-1TH\n"
- )),
- [datetime(1997, 12, 25, 9, 0),
- datetime(1998, 1, 6, 9, 0),
- datetime(1998, 12, 31, 9, 0)])
-
- def testStrValueDatetime(self):
- rr = rrulestr("DTSTART;VALUE=DATE-TIME:19970902T090000\n"
- "RRULE:FREQ=YEARLY;COUNT=2")
-
- self.assertEqual(list(rr), [datetime(1997, 9, 2, 9, 0, 0),
- datetime(1998, 9, 2, 9, 0, 0)])
-
- def testStrValueDate(self):
- rr = rrulestr("DTSTART;VALUE=DATE:19970902\n"
- "RRULE:FREQ=YEARLY;COUNT=2")
-
- self.assertEqual(list(rr), [datetime(1997, 9, 2, 0, 0, 0),
- datetime(1998, 9, 2, 0, 0, 0)])
-
+ def testStrSetDateAndExDate(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RDATE:19970902T090000\n"
+ "RDATE:19970904T090000\n"
+ "RDATE:19970909T090000\n"
+ "RDATE:19970911T090000\n"
+ "RDATE:19970916T090000\n"
+ "RDATE:19970918T090000\n"
+ "EXDATE:19970904T090000\n"
+ "EXDATE:19970911T090000\n"
+ "EXDATE:19970918T090000\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testStrSetDateAndExRule(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RDATE:19970902T090000\n"
+ "RDATE:19970904T090000\n"
+ "RDATE:19970909T090000\n"
+ "RDATE:19970911T090000\n"
+ "RDATE:19970916T090000\n"
+ "RDATE:19970918T090000\n"
+ "EXRULE:FREQ=YEARLY;COUNT=3;BYDAY=TH\n"
+ )),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testStrKeywords(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3;INTERVAL=3;"
+ "BYMONTH=3;BYWEEKDAY=TH;BYMONTHDAY=3;"
+ "BYHOUR=3;BYMINUTE=3;BYSECOND=3\n"
+ )),
+ [datetime(2033, 3, 3, 3, 3, 3),
+ datetime(2039, 3, 3, 3, 3, 3),
+ datetime(2072, 3, 3, 3, 3, 3)])
+
+ def testStrNWeekDay(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=3;BYDAY=1TU,-1TH\n"
+ )),
+ [datetime(1997, 12, 25, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 12, 31, 9, 0)])
+
+ def testStrUntil(self):
+ self.assertEqual(list(rrulestr(
+ "DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;"
+ "UNTIL=19990101T000000;BYDAY=1TU,-1TH\n"
+ )),
+ [datetime(1997, 12, 25, 9, 0),
+ datetime(1998, 1, 6, 9, 0),
+ datetime(1998, 12, 31, 9, 0)])
+
+ def testStrValueDatetime(self):
+ rr = rrulestr("DTSTART;VALUE=DATE-TIME:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;COUNT=2")
+
+ self.assertEqual(list(rr), [datetime(1997, 9, 2, 9, 0, 0),
+ datetime(1998, 9, 2, 9, 0, 0)])
+
+ def testStrValueDate(self):
+ rr = rrulestr("DTSTART;VALUE=DATE:19970902\n"
+ "RRULE:FREQ=YEARLY;COUNT=2")
+
+ self.assertEqual(list(rr), [datetime(1997, 9, 2, 0, 0, 0),
+ datetime(1998, 9, 2, 0, 0, 0)])
+
def testStrMultipleDTStartComma(self):
with pytest.raises(ValueError):
rr = rrulestr("DTSTART:19970101T000000,19970202T000000\n"
"RRULE:FREQ=YEARLY;COUNT=1")
- def testStrInvalidUntil(self):
- with self.assertRaises(ValueError):
- list(rrulestr("DTSTART:19970902T090000\n"
- "RRULE:FREQ=YEARLY;"
- "UNTIL=TheCowsComeHome;BYDAY=1TU,-1TH\n"))
-
- def testStrUntilMustBeUTC(self):
- with self.assertRaises(ValueError):
- list(rrulestr("DTSTART;TZID=America/New_York:19970902T090000\n"
- "RRULE:FREQ=YEARLY;"
- "UNTIL=19990101T000000;BYDAY=1TU,-1TH\n"))
-
- def testStrUntilWithTZ(self):
- NYC = tz.gettz('America/New_York')
- rr = list(rrulestr("DTSTART;TZID=America/New_York:19970101T000000\n"
- "RRULE:FREQ=YEARLY;"
- "UNTIL=19990101T000000Z\n"))
- self.assertEqual(list(rr), [datetime(1997, 1, 1, 0, 0, 0, tzinfo=NYC),
- datetime(1998, 1, 1, 0, 0, 0, tzinfo=NYC)])
-
- def testStrEmptyByDay(self):
- with self.assertRaises(ValueError):
- list(rrulestr("DTSTART:19970902T090000\n"
- "FREQ=WEEKLY;"
- "BYDAY=;" # This part is invalid
- "WKST=SU"))
-
- def testStrInvalidByDay(self):
- with self.assertRaises(ValueError):
- list(rrulestr("DTSTART:19970902T090000\n"
- "FREQ=WEEKLY;"
- "BYDAY=-1OK;" # This part is invalid
- "WKST=SU"))
-
- def testBadBySetPos(self):
- self.assertRaises(ValueError,
- rrule, MONTHLY,
- count=1,
- bysetpos=0,
- dtstart=datetime(1997, 9, 2, 9, 0))
-
- def testBadBySetPosMany(self):
- self.assertRaises(ValueError,
- rrule, MONTHLY,
- count=1,
- bysetpos=(-1, 0, 1),
- dtstart=datetime(1997, 9, 2, 9, 0))
-
- # Tests to ensure that str(rrule) works
- def testToStrYearly(self):
- rule = rrule(YEARLY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
- self._rrulestr_reverse_test(rule)
-
- def testToStrYearlyInterval(self):
- rule = rrule(YEARLY, count=3, interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0))
- self._rrulestr_reverse_test(rule)
-
- def testToStrYearlyByMonth(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByNWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndNWeekDayLarge(self):
- # This is interesting because the TH(-3) ends up before
- # the TU(3).
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByYearDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByEaster(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByHour(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMinute(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyBySecond(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrYearlyBySetPos(self):
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=3,
- bymonthday=15,
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthly(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyInterval(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- interval=18,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonth(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- # Third Monday of the month
- self.assertEqual(rrule(MONTHLY,
- byweekday=(MO(+3)),
- dtstart=datetime(1997, 9, 1)).between(datetime(1997,
- 9,
- 1),
- datetime(1997,
- 12,
- 1)),
- [datetime(1997, 9, 15, 0, 0),
- datetime(1997, 10, 20, 0, 0),
- datetime(1997, 11, 17, 0, 0)])
-
- def testToStrMonthlyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByNWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndNWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(3), TH(-3)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByYearDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByEaster(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByHour(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMinute(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyBySecond(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMonthlyBySetPos(self):
- self._rrulestr_reverse_test(rrule(MONTHLY,
- count=3,
- bymonthday=(13, 17),
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeekly(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyInterval(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- interval=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonth(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndWeekDay(self):
- # This test is interesting, because it crosses the year
- # boundary in a weekly period to find day '1' as a
- # valid recurrence.
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByYearDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=4,
- bymonth=(1, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=4,
- bymonth=(1, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByEaster(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByHour(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMinute(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyBySecond(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrWeeklyBySetPos(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- byweekday=(TU, TH),
- byhour=(6, 18),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDaily(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyInterval(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- interval=92,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonth(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByYearDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=4,
- bymonth=(1, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=4,
- bymonth=(1, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekNoAndWeekDay(self):
- # That's a nice one. The first days of week number one
- # may be in the last year.
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekNoAndWeekDayLarge(self):
- # Another nice test. The last days of week number 52/53
- # may be in the next year.
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByEaster(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByHour(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMinute(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyBySecond(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrDailyBySetPos(self):
- self._rrulestr_reverse_test(rrule(DAILY,
- count=3,
- byhour=(6, 18),
- byminute=(15, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourly(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyInterval(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- interval=769,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonth(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByYearDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekNoAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekNoAndWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByEaster(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByHour(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMinute(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyBySecond(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrHourlyBySetPos(self):
- self._rrulestr_reverse_test(rrule(HOURLY,
- count=3,
- byminute=(15, 45),
- bysecond=(15, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutely(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyInterval(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- interval=1501,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonth(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByYearDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekNoAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekNoAndWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByEaster(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByHour(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMinute(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyBySecond(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrMinutelyBySetPos(self):
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=3,
- bysecond=(15, 30, 45),
- bysetpos=(3, -3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondly(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyInterval(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- interval=2,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyIntervalLarge(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- interval=90061,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonth(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonthday=(1, 3),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndMonthDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(5, 7),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByNWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndNWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- byweekday=(TU(1), TH(-1)),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndMonthDayAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bymonth=(1, 3),
- bymonthday=(1, 3),
- byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByYearDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=4,
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=4,
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndYearDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(1, 100, 200, 365),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMonthAndYearDayNeg(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=4,
- bymonth=(4, 7),
- byyearday=(-365, -266, -166, -1),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekNo(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekno=20,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekNoAndWeekDay(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekno=1,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekNoAndWeekDayLarge(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekno=52,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekNoAndWeekDayLast(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekno=-1,
- byweekday=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByWeekNoAndWeekDay53(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byweekno=53,
- byweekday=MO,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByEaster(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byeaster=0,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByEasterPos(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byeaster=1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByEasterNeg(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byeaster=-1,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByHour(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMinute(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyBySecond(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByHourAndMinute(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByHourAndSecond(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByHourAndMinuteAndSecond(self):
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- byhour=(6, 18),
- byminute=(6, 18),
- bysecond=(6, 18),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrSecondlyByHourAndMinuteAndSecondBug(self):
- # This explores a bug found by Mathieu Bridon.
- self._rrulestr_reverse_test(rrule(SECONDLY,
- count=3,
- bysecond=(0,),
- byminute=(1,),
- dtstart=datetime(2010, 3, 22, 12, 1)))
-
- def testToStrWithWkSt(self):
- self._rrulestr_reverse_test(rrule(WEEKLY,
- count=3,
- wkst=SU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testToStrLongIntegers(self):
+ def testStrInvalidUntil(self):
+ with self.assertRaises(ValueError):
+ list(rrulestr("DTSTART:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;"
+ "UNTIL=TheCowsComeHome;BYDAY=1TU,-1TH\n"))
+
+ def testStrUntilMustBeUTC(self):
+ with self.assertRaises(ValueError):
+ list(rrulestr("DTSTART;TZID=America/New_York:19970902T090000\n"
+ "RRULE:FREQ=YEARLY;"
+ "UNTIL=19990101T000000;BYDAY=1TU,-1TH\n"))
+
+ def testStrUntilWithTZ(self):
+ NYC = tz.gettz('America/New_York')
+ rr = list(rrulestr("DTSTART;TZID=America/New_York:19970101T000000\n"
+ "RRULE:FREQ=YEARLY;"
+ "UNTIL=19990101T000000Z\n"))
+ self.assertEqual(list(rr), [datetime(1997, 1, 1, 0, 0, 0, tzinfo=NYC),
+ datetime(1998, 1, 1, 0, 0, 0, tzinfo=NYC)])
+
+ def testStrEmptyByDay(self):
+ with self.assertRaises(ValueError):
+ list(rrulestr("DTSTART:19970902T090000\n"
+ "FREQ=WEEKLY;"
+ "BYDAY=;" # This part is invalid
+ "WKST=SU"))
+
+ def testStrInvalidByDay(self):
+ with self.assertRaises(ValueError):
+ list(rrulestr("DTSTART:19970902T090000\n"
+ "FREQ=WEEKLY;"
+ "BYDAY=-1OK;" # This part is invalid
+ "WKST=SU"))
+
+ def testBadBySetPos(self):
+ self.assertRaises(ValueError,
+ rrule, MONTHLY,
+ count=1,
+ bysetpos=0,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+
+ def testBadBySetPosMany(self):
+ self.assertRaises(ValueError,
+ rrule, MONTHLY,
+ count=1,
+ bysetpos=(-1, 0, 1),
+ dtstart=datetime(1997, 9, 2, 9, 0))
+
+ # Tests to ensure that str(rrule) works
+ def testToStrYearly(self):
+ rule = rrule(YEARLY, count=3, dtstart=datetime(1997, 9, 2, 9, 0))
+ self._rrulestr_reverse_test(rule)
+
+ def testToStrYearlyInterval(self):
+ rule = rrule(YEARLY, count=3, interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0))
+ self._rrulestr_reverse_test(rule)
+
+ def testToStrYearlyByMonth(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByNWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndNWeekDayLarge(self):
+ # This is interesting because the TH(-3) ends up before
+ # the TU(3).
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByEaster(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByHour(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMinute(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyBySecond(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrYearlyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=3,
+ bymonthday=15,
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthly(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyInterval(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ interval=18,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonth(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ # Third Monday of the month
+ self.assertEqual(rrule(MONTHLY,
+ byweekday=(MO(+3)),
+ dtstart=datetime(1997, 9, 1)).between(datetime(1997,
+ 9,
+ 1),
+ datetime(1997,
+ 12,
+ 1)),
+ [datetime(1997, 9, 15, 0, 0),
+ datetime(1997, 10, 20, 0, 0),
+ datetime(1997, 11, 17, 0, 0)])
+
+ def testToStrMonthlyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByNWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndNWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(3), TH(-3)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByEaster(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByHour(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMinute(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyBySecond(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMonthlyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(MONTHLY,
+ count=3,
+ bymonthday=(13, 17),
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeekly(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyInterval(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ interval=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonth(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndWeekDay(self):
+ # This test is interesting, because it crosses the year
+ # boundary in a weekly period to find day '1' as a
+ # valid recurrence.
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByEaster(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByHour(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMinute(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyBySecond(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrWeeklyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ byweekday=(TU, TH),
+ byhour=(6, 18),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDaily(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyInterval(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ interval=92,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonth(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=4,
+ bymonth=(1, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekNoAndWeekDay(self):
+ # That's a nice one. The first days of week number one
+ # may be in the last year.
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekNoAndWeekDayLarge(self):
+ # Another nice test. The last days of week number 52/53
+ # may be in the next year.
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByEaster(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByHour(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMinute(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyBySecond(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrDailyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(DAILY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(15, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourly(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyInterval(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ interval=769,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonth(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekNoAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekNoAndWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByEaster(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByHour(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMinute(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyBySecond(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrHourlyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(HOURLY,
+ count=3,
+ byminute=(15, 45),
+ bysecond=(15, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutely(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyInterval(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ interval=1501,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonth(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekNoAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekNoAndWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByEaster(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByHour(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMinute(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyBySecond(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrMinutelyBySetPos(self):
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=3,
+ bysecond=(15, 30, 45),
+ bysetpos=(3, -3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondly(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyInterval(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ interval=2,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyIntervalLarge(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ interval=90061,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonth(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonthday=(1, 3),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndMonthDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(5, 7),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndNWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ byweekday=(TU(1), TH(-1)),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndMonthDayAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bymonth=(1, 3),
+ bymonthday=(1, 3),
+ byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByYearDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=4,
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=4,
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndYearDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(1, 100, 200, 365),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMonthAndYearDayNeg(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=4,
+ bymonth=(4, 7),
+ byyearday=(-365, -266, -166, -1),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekNo(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekno=20,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekNoAndWeekDay(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekno=1,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekNoAndWeekDayLarge(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekno=52,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekNoAndWeekDayLast(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekno=-1,
+ byweekday=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByWeekNoAndWeekDay53(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byweekno=53,
+ byweekday=MO,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByEaster(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byeaster=0,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByEasterPos(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byeaster=1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByEasterNeg(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byeaster=-1,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByHour(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMinute(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyBySecond(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByHourAndMinute(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByHourAndSecond(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByHourAndMinuteAndSecond(self):
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ byhour=(6, 18),
+ byminute=(6, 18),
+ bysecond=(6, 18),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrSecondlyByHourAndMinuteAndSecondBug(self):
+ # This explores a bug found by Mathieu Bridon.
+ self._rrulestr_reverse_test(rrule(SECONDLY,
+ count=3,
+ bysecond=(0,),
+ byminute=(1,),
+ dtstart=datetime(2010, 3, 22, 12, 1)))
+
+ def testToStrWithWkSt(self):
+ self._rrulestr_reverse_test(rrule(WEEKLY,
+ count=3,
+ wkst=SU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testToStrLongIntegers(self):
if PY2: # There are no longs in python3
- self._rrulestr_reverse_test(rrule(MINUTELY,
- count=long(2),
- interval=long(2),
- bymonth=long(2),
- byweekday=long(3),
- byhour=long(6),
- byminute=long(6),
- bysecond=long(6),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- self._rrulestr_reverse_test(rrule(YEARLY,
- count=long(2),
- bymonthday=long(5),
- byweekno=long(2),
- dtstart=datetime(1997, 9, 2, 9, 0)))
-
- def testReplaceIfSet(self):
- rr = rrule(YEARLY,
- count=1,
- bymonthday=5,
- dtstart=datetime(1997, 1, 1))
- newrr = rr.replace(bymonthday=6)
- self.assertEqual(list(rr), [datetime(1997, 1, 5)])
- self.assertEqual(list(newrr),
- [datetime(1997, 1, 6)])
-
- def testReplaceIfNotSet(self):
- rr = rrule(YEARLY,
- count=1,
- dtstart=datetime(1997, 1, 1))
- newrr = rr.replace(bymonthday=6)
- self.assertEqual(list(rr), [datetime(1997, 1, 1)])
- self.assertEqual(list(newrr),
- [datetime(1997, 1, 6)])
-
-
-@pytest.mark.rrule
-@freeze_time(datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC))
-def test_generated_aware_dtstart():
- dtstart_exp = datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC)
- UNTIL = datetime(2018, 3, 6, 8, 0, tzinfo=tz.UTC)
-
- rule_without_dtstart = rrule(freq=HOURLY, until=UNTIL)
- rule_with_dtstart = rrule(freq=HOURLY, dtstart=dtstart_exp, until=UNTIL)
- assert list(rule_without_dtstart) == list(rule_with_dtstart)
-
-
-@pytest.mark.rrule
-@pytest.mark.rrulestr
-@pytest.mark.xfail(reason="rrulestr loses time zone, gh issue #637")
-@freeze_time(datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC))
-def test_generated_aware_dtstart_rrulestr():
- rrule_without_dtstart = rrule(freq=HOURLY,
- until=datetime(2018, 3, 6, 8, 0,
- tzinfo=tz.UTC))
- rrule_r = rrulestr(str(rrule_without_dtstart))
-
- assert list(rrule_r) == list(rrule_without_dtstart)
-
-
-@pytest.mark.rruleset
-class RRuleSetTest(unittest.TestCase):
- def testSet(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testSetDate(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=1, byweekday=TU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.rdate(datetime(1997, 9, 4, 9))
- rrset.rdate(datetime(1997, 9, 9, 9))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testSetExRule(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testSetExDate(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.exdate(datetime(1997, 9, 4, 9))
- rrset.exdate(datetime(1997, 9, 11, 9))
- rrset.exdate(datetime(1997, 9, 18, 9))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testSetExDateRevOrder(self):
- rrset = rruleset()
- rrset.rrule(rrule(MONTHLY, count=5, bymonthday=10,
- dtstart=datetime(2004, 1, 1, 9, 0)))
- rrset.exdate(datetime(2004, 4, 10, 9, 0))
- rrset.exdate(datetime(2004, 2, 10, 9, 0))
- self.assertEqual(list(rrset),
- [datetime(2004, 1, 10, 9, 0),
- datetime(2004, 3, 10, 9, 0),
- datetime(2004, 5, 10, 9, 0)])
-
- def testSetDateAndExDate(self):
- rrset = rruleset()
- rrset.rdate(datetime(1997, 9, 2, 9))
- rrset.rdate(datetime(1997, 9, 4, 9))
- rrset.rdate(datetime(1997, 9, 9, 9))
- rrset.rdate(datetime(1997, 9, 11, 9))
- rrset.rdate(datetime(1997, 9, 16, 9))
- rrset.rdate(datetime(1997, 9, 18, 9))
- rrset.exdate(datetime(1997, 9, 4, 9))
- rrset.exdate(datetime(1997, 9, 11, 9))
- rrset.exdate(datetime(1997, 9, 18, 9))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testSetDateAndExRule(self):
- rrset = rruleset()
- rrset.rdate(datetime(1997, 9, 2, 9))
- rrset.rdate(datetime(1997, 9, 4, 9))
- rrset.rdate(datetime(1997, 9, 9, 9))
- rrset.rdate(datetime(1997, 9, 11, 9))
- rrset.rdate(datetime(1997, 9, 16, 9))
- rrset.rdate(datetime(1997, 9, 18, 9))
- rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 9, 9, 0),
- datetime(1997, 9, 16, 9, 0)])
-
- def testSetCount(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- self.assertEqual(rrset.count(), 3)
-
- def testSetCachePre(self):
- rrset = rruleset()
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testSetCachePost(self):
- rrset = rruleset(cache=True)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- for x in rrset: pass
- self.assertEqual(list(rrset),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testSetCachePostInternal(self):
- rrset = rruleset(cache=True)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
- dtstart=datetime(1997, 9, 2, 9, 0)))
- for x in rrset: pass
- self.assertEqual(list(rrset._cache),
- [datetime(1997, 9, 2, 9, 0),
- datetime(1997, 9, 4, 9, 0),
- datetime(1997, 9, 9, 9, 0)])
-
- def testSetRRuleCount(self):
- # Test that the count is updated when an rrule is added
- rrset = rruleset(cache=False)
- for cache in (True, False):
- rrset = rruleset(cache=cache)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
- dtstart=datetime(1983, 4, 1)))
- rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
- dtstart=datetime(1991, 6, 3)))
-
- # Check the length twice - first one sets a cache, second reads it
- self.assertEqual(rrset.count(), 6)
- self.assertEqual(rrset.count(), 6)
-
- # This should invalidate the cache and force an update
- rrset.rrule(rrule(MONTHLY, count=3, dtstart=datetime(1994, 1, 3)))
-
- self.assertEqual(rrset.count(), 9)
- self.assertEqual(rrset.count(), 9)
-
- def testSetRDateCount(self):
- # Test that the count is updated when an rdate is added
- rrset = rruleset(cache=False)
- for cache in (True, False):
- rrset = rruleset(cache=cache)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
- dtstart=datetime(1983, 4, 1)))
- rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
- dtstart=datetime(1991, 6, 3)))
-
- # Check the length twice - first one sets a cache, second reads it
- self.assertEqual(rrset.count(), 6)
- self.assertEqual(rrset.count(), 6)
-
- # This should invalidate the cache and force an update
- rrset.rdate(datetime(1993, 2, 14))
-
- self.assertEqual(rrset.count(), 7)
- self.assertEqual(rrset.count(), 7)
-
- def testSetExRuleCount(self):
- # Test that the count is updated when an exrule is added
- rrset = rruleset(cache=False)
- for cache in (True, False):
- rrset = rruleset(cache=cache)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
- dtstart=datetime(1983, 4, 1)))
- rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
- dtstart=datetime(1991, 6, 3)))
-
- # Check the length twice - first one sets a cache, second reads it
- self.assertEqual(rrset.count(), 6)
- self.assertEqual(rrset.count(), 6)
-
- # This should invalidate the cache and force an update
- rrset.exrule(rrule(WEEKLY, count=2, interval=2,
- dtstart=datetime(1991, 6, 14)))
-
- self.assertEqual(rrset.count(), 4)
- self.assertEqual(rrset.count(), 4)
-
- def testSetExDateCount(self):
- # Test that the count is updated when an rdate is added
- for cache in (True, False):
- rrset = rruleset(cache=cache)
- rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
- dtstart=datetime(1983, 4, 1)))
- rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
- dtstart=datetime(1991, 6, 3)))
-
- # Check the length twice - first one sets a cache, second reads it
- self.assertEqual(rrset.count(), 6)
- self.assertEqual(rrset.count(), 6)
-
- # This should invalidate the cache and force an update
- rrset.exdate(datetime(1991, 6, 28))
-
- self.assertEqual(rrset.count(), 5)
- self.assertEqual(rrset.count(), 5)
-
-
-class WeekdayTest(unittest.TestCase):
- def testInvalidNthWeekday(self):
- with self.assertRaises(ValueError):
- FR(0)
-
- def testWeekdayCallable(self):
- # Calling a weekday instance generates a new weekday instance with the
- # value of n changed.
- from dateutil.rrule import weekday
- self.assertEqual(MO(1), weekday(0, 1))
-
- # Calling a weekday instance with the identical n returns the original
- # object
- FR_3 = weekday(4, 3)
- self.assertIs(FR_3(3), FR_3)
-
- def testWeekdayEquality(self):
- # Two weekday objects are not equal if they have different values for n
- self.assertNotEqual(TH, TH(-1))
- self.assertNotEqual(SA(3), SA(2))
-
- def testWeekdayEqualitySubclass(self):
- # Two weekday objects equal if their "weekday" and "n" attributes are
- # available and the same
- class BasicWeekday(object):
- def __init__(self, weekday):
- self.weekday = weekday
-
- class BasicNWeekday(BasicWeekday):
- def __init__(self, weekday, n=None):
- super(BasicNWeekday, self).__init__(weekday)
- self.n = n
-
- MO_Basic = BasicWeekday(0)
-
- self.assertNotEqual(MO, MO_Basic)
- self.assertNotEqual(MO(1), MO_Basic)
-
- TU_BasicN = BasicNWeekday(1)
-
- self.assertEqual(TU, TU_BasicN)
- self.assertNotEqual(TU(3), TU_BasicN)
-
- WE_Basic3 = BasicNWeekday(2, 3)
- self.assertEqual(WE(3), WE_Basic3)
- self.assertNotEqual(WE(2), WE_Basic3)
-
- def testWeekdayReprNoN(self):
- no_n_reprs = ('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU')
- no_n_wdays = (MO, TU, WE, TH, FR, SA, SU)
-
- for repstr, wday in zip(no_n_reprs, no_n_wdays):
- self.assertEqual(repr(wday), repstr)
-
- def testWeekdayReprWithN(self):
- with_n_reprs = ('WE(+1)', 'TH(-2)', 'SU(+3)')
- with_n_wdays = (WE(1), TH(-2), SU(+3))
-
- for repstr, wday in zip(with_n_reprs, with_n_wdays):
- self.assertEqual(repr(wday), repstr)
+ self._rrulestr_reverse_test(rrule(MINUTELY,
+ count=long(2),
+ interval=long(2),
+ bymonth=long(2),
+ byweekday=long(3),
+ byhour=long(6),
+ byminute=long(6),
+ bysecond=long(6),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ self._rrulestr_reverse_test(rrule(YEARLY,
+ count=long(2),
+ bymonthday=long(5),
+ byweekno=long(2),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+
+ def testReplaceIfSet(self):
+ rr = rrule(YEARLY,
+ count=1,
+ bymonthday=5,
+ dtstart=datetime(1997, 1, 1))
+ newrr = rr.replace(bymonthday=6)
+ self.assertEqual(list(rr), [datetime(1997, 1, 5)])
+ self.assertEqual(list(newrr),
+ [datetime(1997, 1, 6)])
+
+ def testReplaceIfNotSet(self):
+ rr = rrule(YEARLY,
+ count=1,
+ dtstart=datetime(1997, 1, 1))
+ newrr = rr.replace(bymonthday=6)
+ self.assertEqual(list(rr), [datetime(1997, 1, 1)])
+ self.assertEqual(list(newrr),
+ [datetime(1997, 1, 6)])
+
+
+@pytest.mark.rrule
+@freeze_time(datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC))
+def test_generated_aware_dtstart():
+ dtstart_exp = datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC)
+ UNTIL = datetime(2018, 3, 6, 8, 0, tzinfo=tz.UTC)
+
+ rule_without_dtstart = rrule(freq=HOURLY, until=UNTIL)
+ rule_with_dtstart = rrule(freq=HOURLY, dtstart=dtstart_exp, until=UNTIL)
+ assert list(rule_without_dtstart) == list(rule_with_dtstart)
+
+
+@pytest.mark.rrule
+@pytest.mark.rrulestr
+@pytest.mark.xfail(reason="rrulestr loses time zone, gh issue #637")
+@freeze_time(datetime(2018, 3, 6, 5, 36, tzinfo=tz.UTC))
+def test_generated_aware_dtstart_rrulestr():
+ rrule_without_dtstart = rrule(freq=HOURLY,
+ until=datetime(2018, 3, 6, 8, 0,
+ tzinfo=tz.UTC))
+ rrule_r = rrulestr(str(rrule_without_dtstart))
+
+ assert list(rrule_r) == list(rrule_without_dtstart)
+
+
+@pytest.mark.rruleset
+class RRuleSetTest(unittest.TestCase):
+ def testSet(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testSetDate(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=1, byweekday=TU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.rdate(datetime(1997, 9, 4, 9))
+ rrset.rdate(datetime(1997, 9, 9, 9))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testSetExRule(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testSetExDate(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.exdate(datetime(1997, 9, 4, 9))
+ rrset.exdate(datetime(1997, 9, 11, 9))
+ rrset.exdate(datetime(1997, 9, 18, 9))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testSetExDateRevOrder(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(MONTHLY, count=5, bymonthday=10,
+ dtstart=datetime(2004, 1, 1, 9, 0)))
+ rrset.exdate(datetime(2004, 4, 10, 9, 0))
+ rrset.exdate(datetime(2004, 2, 10, 9, 0))
+ self.assertEqual(list(rrset),
+ [datetime(2004, 1, 10, 9, 0),
+ datetime(2004, 3, 10, 9, 0),
+ datetime(2004, 5, 10, 9, 0)])
+
+ def testSetDateAndExDate(self):
+ rrset = rruleset()
+ rrset.rdate(datetime(1997, 9, 2, 9))
+ rrset.rdate(datetime(1997, 9, 4, 9))
+ rrset.rdate(datetime(1997, 9, 9, 9))
+ rrset.rdate(datetime(1997, 9, 11, 9))
+ rrset.rdate(datetime(1997, 9, 16, 9))
+ rrset.rdate(datetime(1997, 9, 18, 9))
+ rrset.exdate(datetime(1997, 9, 4, 9))
+ rrset.exdate(datetime(1997, 9, 11, 9))
+ rrset.exdate(datetime(1997, 9, 18, 9))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testSetDateAndExRule(self):
+ rrset = rruleset()
+ rrset.rdate(datetime(1997, 9, 2, 9))
+ rrset.rdate(datetime(1997, 9, 4, 9))
+ rrset.rdate(datetime(1997, 9, 9, 9))
+ rrset.rdate(datetime(1997, 9, 11, 9))
+ rrset.rdate(datetime(1997, 9, 16, 9))
+ rrset.rdate(datetime(1997, 9, 18, 9))
+ rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 9, 9, 0),
+ datetime(1997, 9, 16, 9, 0)])
+
+ def testSetCount(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=6, byweekday=(TU, TH),
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.exrule(rrule(YEARLY, count=3, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ self.assertEqual(rrset.count(), 3)
+
+ def testSetCachePre(self):
+ rrset = rruleset()
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testSetCachePost(self):
+ rrset = rruleset(cache=True)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ for x in rrset: pass
+ self.assertEqual(list(rrset),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testSetCachePostInternal(self):
+ rrset = rruleset(cache=True)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TU,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ rrset.rrule(rrule(YEARLY, count=1, byweekday=TH,
+ dtstart=datetime(1997, 9, 2, 9, 0)))
+ for x in rrset: pass
+ self.assertEqual(list(rrset._cache),
+ [datetime(1997, 9, 2, 9, 0),
+ datetime(1997, 9, 4, 9, 0),
+ datetime(1997, 9, 9, 9, 0)])
+
+ def testSetRRuleCount(self):
+ # Test that the count is updated when an rrule is added
+ rrset = rruleset(cache=False)
+ for cache in (True, False):
+ rrset = rruleset(cache=cache)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
+ dtstart=datetime(1983, 4, 1)))
+ rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
+ dtstart=datetime(1991, 6, 3)))
+
+ # Check the length twice - first one sets a cache, second reads it
+ self.assertEqual(rrset.count(), 6)
+ self.assertEqual(rrset.count(), 6)
+
+ # This should invalidate the cache and force an update
+ rrset.rrule(rrule(MONTHLY, count=3, dtstart=datetime(1994, 1, 3)))
+
+ self.assertEqual(rrset.count(), 9)
+ self.assertEqual(rrset.count(), 9)
+
+ def testSetRDateCount(self):
+ # Test that the count is updated when an rdate is added
+ rrset = rruleset(cache=False)
+ for cache in (True, False):
+ rrset = rruleset(cache=cache)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
+ dtstart=datetime(1983, 4, 1)))
+ rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
+ dtstart=datetime(1991, 6, 3)))
+
+ # Check the length twice - first one sets a cache, second reads it
+ self.assertEqual(rrset.count(), 6)
+ self.assertEqual(rrset.count(), 6)
+
+ # This should invalidate the cache and force an update
+ rrset.rdate(datetime(1993, 2, 14))
+
+ self.assertEqual(rrset.count(), 7)
+ self.assertEqual(rrset.count(), 7)
+
+ def testSetExRuleCount(self):
+ # Test that the count is updated when an exrule is added
+ rrset = rruleset(cache=False)
+ for cache in (True, False):
+ rrset = rruleset(cache=cache)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
+ dtstart=datetime(1983, 4, 1)))
+ rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
+ dtstart=datetime(1991, 6, 3)))
+
+ # Check the length twice - first one sets a cache, second reads it
+ self.assertEqual(rrset.count(), 6)
+ self.assertEqual(rrset.count(), 6)
+
+ # This should invalidate the cache and force an update
+ rrset.exrule(rrule(WEEKLY, count=2, interval=2,
+ dtstart=datetime(1991, 6, 14)))
+
+ self.assertEqual(rrset.count(), 4)
+ self.assertEqual(rrset.count(), 4)
+
+ def testSetExDateCount(self):
+ # Test that the count is updated when an rdate is added
+ for cache in (True, False):
+ rrset = rruleset(cache=cache)
+ rrset.rrule(rrule(YEARLY, count=2, byweekday=TH,
+ dtstart=datetime(1983, 4, 1)))
+ rrset.rrule(rrule(WEEKLY, count=4, byweekday=FR,
+ dtstart=datetime(1991, 6, 3)))
+
+ # Check the length twice - first one sets a cache, second reads it
+ self.assertEqual(rrset.count(), 6)
+ self.assertEqual(rrset.count(), 6)
+
+ # This should invalidate the cache and force an update
+ rrset.exdate(datetime(1991, 6, 28))
+
+ self.assertEqual(rrset.count(), 5)
+ self.assertEqual(rrset.count(), 5)
+
+
+class WeekdayTest(unittest.TestCase):
+ def testInvalidNthWeekday(self):
+ with self.assertRaises(ValueError):
+ FR(0)
+
+ def testWeekdayCallable(self):
+ # Calling a weekday instance generates a new weekday instance with the
+ # value of n changed.
+ from dateutil.rrule import weekday
+ self.assertEqual(MO(1), weekday(0, 1))
+
+ # Calling a weekday instance with the identical n returns the original
+ # object
+ FR_3 = weekday(4, 3)
+ self.assertIs(FR_3(3), FR_3)
+
+ def testWeekdayEquality(self):
+ # Two weekday objects are not equal if they have different values for n
+ self.assertNotEqual(TH, TH(-1))
+ self.assertNotEqual(SA(3), SA(2))
+
+ def testWeekdayEqualitySubclass(self):
+ # Two weekday objects equal if their "weekday" and "n" attributes are
+ # available and the same
+ class BasicWeekday(object):
+ def __init__(self, weekday):
+ self.weekday = weekday
+
+ class BasicNWeekday(BasicWeekday):
+ def __init__(self, weekday, n=None):
+ super(BasicNWeekday, self).__init__(weekday)
+ self.n = n
+
+ MO_Basic = BasicWeekday(0)
+
+ self.assertNotEqual(MO, MO_Basic)
+ self.assertNotEqual(MO(1), MO_Basic)
+
+ TU_BasicN = BasicNWeekday(1)
+
+ self.assertEqual(TU, TU_BasicN)
+ self.assertNotEqual(TU(3), TU_BasicN)
+
+ WE_Basic3 = BasicNWeekday(2, 3)
+ self.assertEqual(WE(3), WE_Basic3)
+ self.assertNotEqual(WE(2), WE_Basic3)
+
+ def testWeekdayReprNoN(self):
+ no_n_reprs = ('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU')
+ no_n_wdays = (MO, TU, WE, TH, FR, SA, SU)
+
+ for repstr, wday in zip(no_n_reprs, no_n_wdays):
+ self.assertEqual(repr(wday), repstr)
+
+ def testWeekdayReprWithN(self):
+ with_n_reprs = ('WE(+1)', 'TH(-2)', 'SU(+3)')
+ with_n_wdays = (WE(1), TH(-2), SU(+3))
+
+ for repstr, wday in zip(with_n_reprs, with_n_wdays):
+ self.assertEqual(repr(wday), repstr)
diff --git a/contrib/python/dateutil/dateutil/test/test_tz.py b/contrib/python/dateutil/dateutil/test/test_tz.py
index 926e730b30..e5e4772d9a 100644
--- a/contrib/python/dateutil/dateutil/test/test_tz.py
+++ b/contrib/python/dateutil/dateutil/test/test_tz.py
@@ -1,743 +1,743 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-from ._common import PicklableMixin
-from ._common import TZEnvContext, TZWinContext
-from ._common import ComparesEqual
-
-from datetime import datetime, timedelta
-from datetime import time as dt_time
-from datetime import tzinfo
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from ._common import PicklableMixin
+from ._common import TZEnvContext, TZWinContext
+from ._common import ComparesEqual
+
+from datetime import datetime, timedelta
+from datetime import time as dt_time
+from datetime import tzinfo
from six import PY2
from io import BytesIO, StringIO
-import unittest
-
-import sys
-import base64
-import copy
+import unittest
+
+import sys
+import base64
+import copy
import gc
import weakref
-
-from functools import partial
-
-IS_WIN = sys.platform.startswith('win')
-
-import pytest
-
-# dateutil imports
-from dateutil.relativedelta import relativedelta, SU, TH
-from dateutil.parser import parse
-from dateutil import tz as tz
-from dateutil import zoneinfo
-
-try:
- from dateutil import tzwin
-except ImportError as e:
- if IS_WIN:
- raise e
- else:
- pass
-
-MISSING_TARBALL = ("This test fails if you don't have the dateutil "
- "timezone file installed. Please read the README")
-
-TZFILE_EST5EDT = b"""
-VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAADrAAAABAAAABCeph5wn7rrYKCGAHCh
-ms1gomXicKOD6eCkaq5wpTWnYKZTyvCnFYlgqDOs8Kj+peCqE47wqt6H4KvzcPCsvmngrdNS8K6e
-S+CvszTwsH4t4LGcUXCyZ0pgs3wzcLRHLGC1XBVwticOYLc793C4BvBguRvZcLnm0mC7BPXwu8a0
-YLzk1/C9r9DgvsS58L+PsuDApJvwwW+U4MKEffDDT3bgxGRf8MUvWODGTXxwxw864MgtXnDI+Fdg
-yg1AcMrYOWDLiPBw0iP0cNJg++DTdeTw1EDd4NVVxvDWIL/g1zWo8NgAoeDZFYrw2eCD4Nr+p3Db
-wGXg3N6JcN2pgmDevmtw34lkYOCeTXDhaUZg4n4vcONJKGDkXhFw5Vcu4OZHLfDnNxDg6CcP8OkW
-8uDqBvHw6vbU4Ovm0/Ds1rbg7ca18O6/02Dvr9Jw8J+1YPGPtHDyf5dg82+WcPRfeWD1T3hw9j9b
-YPcvWnD4KHfg+Q88cPoIWeD6+Fjw++g74PzYOvD9yB3g/rgc8P+n/+AAl/7wAYfh4AJ34PADcP5g
-BGD9cAVQ4GAGQN9wBzDCYAeNGXAJEKRgCa2U8ArwhmAL4IVwDNmi4A3AZ3AOuYTgD6mD8BCZZuAR
-iWXwEnlI4BNpR/AUWSrgFUkp8BY5DOAXKQvwGCIpYBkI7fAaAgtgGvIKcBvh7WAc0exwHcHPYB6x
-znAfobFgIHYA8CGBk2AiVeLwI2qv4CQ1xPAlSpHgJhWm8Ccqc+An/sNwKQpV4CnepXAq6jfgK76H
-cCzTVGAtnmlwLrM2YC9+S3AwkxhgMWdn8DJy+mAzR0nwNFLcYDUnK/A2Mr5gNwcN8Dgb2uA45u/w
-Ofu84DrG0fA7257gPK/ucD27gOA+j9BwP5ti4EBvsnBBhH9gQk+UcENkYWBEL3ZwRURDYEYPWHBH
-JCVgR/h08EkEB2BJ2FbwSuPpYEu4OPBMzQXgTZga8E6s5+BPd/zwUIzJ4FFhGXBSbKvgU0D7cFRM
-jeBVIN1wVixv4FcAv3BYFYxgWOChcFn1bmBawINwW9VQYFypn/BdtTJgXomB8F+VFGBgaWPwYX4w
-4GJJRfBjXhLgZCkn8GU99OBmEkRwZx3W4GfyJnBo/bjgadIIcGrdmuBrsepwbMa3YG2RzHBupplg
-b3GucHCGe2BxWsrwcmZdYHM6rPB0Rj9gdRqO8HYvW+B2+nDweA894HjaUvB57x/gero08HvPAeB8
-o1Fwfa7j4H6DM3B/jsXgAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAgMBAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA
-AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAAEAAQABAAEAAQABAAEAAf//x8ABAP//ubAABP//x8ABCP//x8ABDEVEVABFU1QARVdU
-AEVQVAAAAAABAAAAAQ==
-"""
-
-EUROPE_HELSINKI = b"""
-VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAFAAAABQAAAAAAAAB1AAAABQAAAA2kc28Yy85RYMy/hdAV
-I+uQFhPckBcDzZAX876QGOOvkBnToJAaw5GQG7y9EBysrhAdnJ8QHoyQEB98gRAgbHIQIVxjECJM
-VBAjPEUQJCw2ECUcJxAmDBgQJwVDkCf1NJAo5SWQKdUWkCrFB5ArtPiQLKTpkC2U2pAuhMuQL3S8
-kDBkrZAxXdkQMnK0EDM9uxA0UpYQNR2dEDYyeBA2/X8QOBuUkDjdYRA5+3aQOr1DEDvbWJA8pl+Q
-Pbs6kD6GQZA/mxyQQGYjkEGEORBCRgWQQ2QbEEQl55BFQ/0QRgXJkEcj3xBH7uYQSQPBEEnOyBBK
-46MQS66qEEzMv5BNjowQTqyhkE9ubhBQjIOQUVeKkFJsZZBTN2yQVExHkFUXTpBWLCmQVvcwkFgV
-RhBY1xKQWfUoEFq29JBb1QoQXKAREF207BBef/MQX5TOEGBf1RBhfeqQYj+3EGNdzJBkH5kQZT2u
-kGYItZBnHZCQZ+iXkGj9cpBpyHmQat1UkGuoW5BsxnEQbYg9kG6mUxBvaB+QcIY1EHFRPBByZhcQ
-czEeEHRF+RB1EQAQdi8VkHbw4hB4DveQeNDEEHnu2ZB6sKYQe867kHyZwpB9rp2QfnmkkH+Of5AC
-AQIDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQD
-BAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAME
-AwQAABdoAAAAACowAQQAABwgAAkAACowAQQAABwgAAlITVQARUVTVABFRVQAAAAAAQEAAAABAQ==
-"""
-
-NEW_YORK = b"""
-VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAABcAAADrAAAABAAAABCeph5wn7rrYKCGAHCh
-ms1gomXicKOD6eCkaq5wpTWnYKZTyvCnFYlgqDOs8Kj+peCqE47wqt6H4KvzcPCsvmngrdNS8K6e
-S+CvszTwsH4t4LGcUXCyZ0pgs3wzcLRHLGC1XBVwticOYLc793C4BvBguRvZcLnm0mC7BPXwu8a0
-YLzk1/C9r9DgvsS58L+PsuDApJvwwW+U4MKEffDDT3bgxGRf8MUvWODGTXxwxw864MgtXnDI+Fdg
-yg1AcMrYOWDLiPBw0iP0cNJg++DTdeTw1EDd4NVVxvDWIL/g1zWo8NgAoeDZFYrw2eCD4Nr+p3Db
-wGXg3N6JcN2pgmDevmtw34lkYOCeTXDhaUZg4n4vcONJKGDkXhFw5Vcu4OZHLfDnNxDg6CcP8OkW
-8uDqBvHw6vbU4Ovm0/Ds1rbg7ca18O6/02Dvr9Jw8J+1YPGPtHDyf5dg82+WcPRfeWD1T3hw9j9b
-YPcvWnD4KHfg+Q88cPoIWeD6+Fjw++g74PzYOvD9yB3g/rgc8P+n/+AAl/7wAYfh4AJ34PADcP5g
-BGD9cAVQ4GEGQN9yBzDCYgeNGXMJEKRjCa2U9ArwhmQL4IV1DNmi5Q3AZ3YOuYTmD6mD9xCZZucR
-iWX4EnlI6BNpR/kUWSrpFUkp+RY5DOoXKQv6GCIpaxkI7fsaAgtsGvIKfBvh7Wwc0ex8HcHPbR6x
-zn0fobFtIHYA/SGBk20iVeL+I2qv7iQ1xP4lSpHuJhWm/ycqc+8n/sOAKQpV8CnepYAq6jfxK76H
-gSzTVHItnmmCLrM2cy9+S4MwkxhzMWdoBDJy+nQzR0oENFLcdTUnLAU2Mr51NwcOBjgb2vY45vAG
-Ofu89jrG0gY72572PK/uhj27gPY+j9CGP5ti9kBvsoZBhH92Qk+UhkNkYXZEL3aHRURDd0XzqQdH
-LV/3R9OLB0kNQfdJs20HSu0j90uciYdM1kB3TXxrh062IndPXE2HUJYEd1E8L4dSdeZ3UxwRh1RV
-yHdU+/OHVjWqd1blEAdYHsb3WMTyB1n+qPdapNQHW96K91yEtgddvmz3XmSYB1+eTvdgTbSHYYdr
-d2ItlodjZ013ZA14h2VHL3dl7VqHZycRd2fNPIdpBvN3aa0eh2rm1XdrljsHbM/x9212HQdur9P3
-b1X/B3CPtfdxNeEHcm+X93MVwwd0T3n3dP7fh3Y4lnd23sGHeBh4d3i+o4d5+Fp3ep6Fh3vYPHd8
-fmeHfbged35eSYd/mAB3AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAgMBAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA
-AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
-AAEAAQABAAEAAQABAAEAAQABAAEAAf//x8ABAP//ubAABP//x8ABCP//x8ABDEVEVABFU1QARVdU
-AEVQVAAEslgAAAAAAQWk7AEAAAACB4YfggAAAAMJZ1MDAAAABAtIhoQAAAAFDSsLhQAAAAYPDD8G
-AAAABxDtcocAAAAIEs6mCAAAAAkVn8qJAAAACheA/goAAAALGWIxiwAAAAwdJeoMAAAADSHa5Q0A
-AAAOJZ6djgAAAA8nf9EPAAAAECpQ9ZAAAAARLDIpEQAAABIuE1ySAAAAEzDnJBMAAAAUM7hIlAAA
-ABU2jBAVAAAAFkO3G5YAAAAXAAAAAQAAAAE=
-"""
-
-TZICAL_EST5EDT = """
-BEGIN:VTIMEZONE
-TZID:US-Eastern
-LAST-MODIFIED:19870101T000000Z
-TZURL:http://zones.stds_r_us.net/tz/US-Eastern
-BEGIN:STANDARD
-DTSTART:19671029T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-TZNAME:EST
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19870405T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-TZNAME:EDT
-END:DAYLIGHT
-END:VTIMEZONE
-"""
-
-TZICAL_PST8PDT = """
-BEGIN:VTIMEZONE
-TZID:US-Pacific
-LAST-MODIFIED:19870101T000000Z
-BEGIN:STANDARD
-DTSTART:19671029T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZOFFSETFROM:-0700
-TZOFFSETTO:-0800
-TZNAME:PST
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19870405T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-TZNAME:PDT
-END:DAYLIGHT
-END:VTIMEZONE
-"""
-
-EST_TUPLE = ('EST', timedelta(hours=-5), timedelta(hours=0))
-EDT_TUPLE = ('EDT', timedelta(hours=-4), timedelta(hours=1))
-
+
+from functools import partial
+
+IS_WIN = sys.platform.startswith('win')
+
+import pytest
+
+# dateutil imports
+from dateutil.relativedelta import relativedelta, SU, TH
+from dateutil.parser import parse
+from dateutil import tz as tz
+from dateutil import zoneinfo
+
+try:
+ from dateutil import tzwin
+except ImportError as e:
+ if IS_WIN:
+ raise e
+ else:
+ pass
+
+MISSING_TARBALL = ("This test fails if you don't have the dateutil "
+ "timezone file installed. Please read the README")
+
+TZFILE_EST5EDT = b"""
+VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAADrAAAABAAAABCeph5wn7rrYKCGAHCh
+ms1gomXicKOD6eCkaq5wpTWnYKZTyvCnFYlgqDOs8Kj+peCqE47wqt6H4KvzcPCsvmngrdNS8K6e
+S+CvszTwsH4t4LGcUXCyZ0pgs3wzcLRHLGC1XBVwticOYLc793C4BvBguRvZcLnm0mC7BPXwu8a0
+YLzk1/C9r9DgvsS58L+PsuDApJvwwW+U4MKEffDDT3bgxGRf8MUvWODGTXxwxw864MgtXnDI+Fdg
+yg1AcMrYOWDLiPBw0iP0cNJg++DTdeTw1EDd4NVVxvDWIL/g1zWo8NgAoeDZFYrw2eCD4Nr+p3Db
+wGXg3N6JcN2pgmDevmtw34lkYOCeTXDhaUZg4n4vcONJKGDkXhFw5Vcu4OZHLfDnNxDg6CcP8OkW
+8uDqBvHw6vbU4Ovm0/Ds1rbg7ca18O6/02Dvr9Jw8J+1YPGPtHDyf5dg82+WcPRfeWD1T3hw9j9b
+YPcvWnD4KHfg+Q88cPoIWeD6+Fjw++g74PzYOvD9yB3g/rgc8P+n/+AAl/7wAYfh4AJ34PADcP5g
+BGD9cAVQ4GAGQN9wBzDCYAeNGXAJEKRgCa2U8ArwhmAL4IVwDNmi4A3AZ3AOuYTgD6mD8BCZZuAR
+iWXwEnlI4BNpR/AUWSrgFUkp8BY5DOAXKQvwGCIpYBkI7fAaAgtgGvIKcBvh7WAc0exwHcHPYB6x
+znAfobFgIHYA8CGBk2AiVeLwI2qv4CQ1xPAlSpHgJhWm8Ccqc+An/sNwKQpV4CnepXAq6jfgK76H
+cCzTVGAtnmlwLrM2YC9+S3AwkxhgMWdn8DJy+mAzR0nwNFLcYDUnK/A2Mr5gNwcN8Dgb2uA45u/w
+Ofu84DrG0fA7257gPK/ucD27gOA+j9BwP5ti4EBvsnBBhH9gQk+UcENkYWBEL3ZwRURDYEYPWHBH
+JCVgR/h08EkEB2BJ2FbwSuPpYEu4OPBMzQXgTZga8E6s5+BPd/zwUIzJ4FFhGXBSbKvgU0D7cFRM
+jeBVIN1wVixv4FcAv3BYFYxgWOChcFn1bmBawINwW9VQYFypn/BdtTJgXomB8F+VFGBgaWPwYX4w
+4GJJRfBjXhLgZCkn8GU99OBmEkRwZx3W4GfyJnBo/bjgadIIcGrdmuBrsepwbMa3YG2RzHBupplg
+b3GucHCGe2BxWsrwcmZdYHM6rPB0Rj9gdRqO8HYvW+B2+nDweA894HjaUvB57x/gero08HvPAeB8
+o1Fwfa7j4H6DM3B/jsXgAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAgMBAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA
+AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAAEAAQABAAEAAQABAAEAAf//x8ABAP//ubAABP//x8ABCP//x8ABDEVEVABFU1QARVdU
+AEVQVAAAAAABAAAAAQ==
+"""
+
+EUROPE_HELSINKI = b"""
+VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAFAAAABQAAAAAAAAB1AAAABQAAAA2kc28Yy85RYMy/hdAV
+I+uQFhPckBcDzZAX876QGOOvkBnToJAaw5GQG7y9EBysrhAdnJ8QHoyQEB98gRAgbHIQIVxjECJM
+VBAjPEUQJCw2ECUcJxAmDBgQJwVDkCf1NJAo5SWQKdUWkCrFB5ArtPiQLKTpkC2U2pAuhMuQL3S8
+kDBkrZAxXdkQMnK0EDM9uxA0UpYQNR2dEDYyeBA2/X8QOBuUkDjdYRA5+3aQOr1DEDvbWJA8pl+Q
+Pbs6kD6GQZA/mxyQQGYjkEGEORBCRgWQQ2QbEEQl55BFQ/0QRgXJkEcj3xBH7uYQSQPBEEnOyBBK
+46MQS66qEEzMv5BNjowQTqyhkE9ubhBQjIOQUVeKkFJsZZBTN2yQVExHkFUXTpBWLCmQVvcwkFgV
+RhBY1xKQWfUoEFq29JBb1QoQXKAREF207BBef/MQX5TOEGBf1RBhfeqQYj+3EGNdzJBkH5kQZT2u
+kGYItZBnHZCQZ+iXkGj9cpBpyHmQat1UkGuoW5BsxnEQbYg9kG6mUxBvaB+QcIY1EHFRPBByZhcQ
+czEeEHRF+RB1EQAQdi8VkHbw4hB4DveQeNDEEHnu2ZB6sKYQe867kHyZwpB9rp2QfnmkkH+Of5AC
+AQIDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQD
+BAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAME
+AwQAABdoAAAAACowAQQAABwgAAkAACowAQQAABwgAAlITVQARUVTVABFRVQAAAAAAQEAAAABAQ==
+"""
+
+NEW_YORK = b"""
+VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAABcAAADrAAAABAAAABCeph5wn7rrYKCGAHCh
+ms1gomXicKOD6eCkaq5wpTWnYKZTyvCnFYlgqDOs8Kj+peCqE47wqt6H4KvzcPCsvmngrdNS8K6e
+S+CvszTwsH4t4LGcUXCyZ0pgs3wzcLRHLGC1XBVwticOYLc793C4BvBguRvZcLnm0mC7BPXwu8a0
+YLzk1/C9r9DgvsS58L+PsuDApJvwwW+U4MKEffDDT3bgxGRf8MUvWODGTXxwxw864MgtXnDI+Fdg
+yg1AcMrYOWDLiPBw0iP0cNJg++DTdeTw1EDd4NVVxvDWIL/g1zWo8NgAoeDZFYrw2eCD4Nr+p3Db
+wGXg3N6JcN2pgmDevmtw34lkYOCeTXDhaUZg4n4vcONJKGDkXhFw5Vcu4OZHLfDnNxDg6CcP8OkW
+8uDqBvHw6vbU4Ovm0/Ds1rbg7ca18O6/02Dvr9Jw8J+1YPGPtHDyf5dg82+WcPRfeWD1T3hw9j9b
+YPcvWnD4KHfg+Q88cPoIWeD6+Fjw++g74PzYOvD9yB3g/rgc8P+n/+AAl/7wAYfh4AJ34PADcP5g
+BGD9cAVQ4GEGQN9yBzDCYgeNGXMJEKRjCa2U9ArwhmQL4IV1DNmi5Q3AZ3YOuYTmD6mD9xCZZucR
+iWX4EnlI6BNpR/kUWSrpFUkp+RY5DOoXKQv6GCIpaxkI7fsaAgtsGvIKfBvh7Wwc0ex8HcHPbR6x
+zn0fobFtIHYA/SGBk20iVeL+I2qv7iQ1xP4lSpHuJhWm/ycqc+8n/sOAKQpV8CnepYAq6jfxK76H
+gSzTVHItnmmCLrM2cy9+S4MwkxhzMWdoBDJy+nQzR0oENFLcdTUnLAU2Mr51NwcOBjgb2vY45vAG
+Ofu89jrG0gY72572PK/uhj27gPY+j9CGP5ti9kBvsoZBhH92Qk+UhkNkYXZEL3aHRURDd0XzqQdH
+LV/3R9OLB0kNQfdJs20HSu0j90uciYdM1kB3TXxrh062IndPXE2HUJYEd1E8L4dSdeZ3UxwRh1RV
+yHdU+/OHVjWqd1blEAdYHsb3WMTyB1n+qPdapNQHW96K91yEtgddvmz3XmSYB1+eTvdgTbSHYYdr
+d2ItlodjZ013ZA14h2VHL3dl7VqHZycRd2fNPIdpBvN3aa0eh2rm1XdrljsHbM/x9212HQdur9P3
+b1X/B3CPtfdxNeEHcm+X93MVwwd0T3n3dP7fh3Y4lnd23sGHeBh4d3i+o4d5+Fp3ep6Fh3vYPHd8
+fmeHfbged35eSYd/mAB3AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAgMBAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA
+AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAB
+AAEAAQABAAEAAQABAAEAAQABAAEAAf//x8ABAP//ubAABP//x8ABCP//x8ABDEVEVABFU1QARVdU
+AEVQVAAEslgAAAAAAQWk7AEAAAACB4YfggAAAAMJZ1MDAAAABAtIhoQAAAAFDSsLhQAAAAYPDD8G
+AAAABxDtcocAAAAIEs6mCAAAAAkVn8qJAAAACheA/goAAAALGWIxiwAAAAwdJeoMAAAADSHa5Q0A
+AAAOJZ6djgAAAA8nf9EPAAAAECpQ9ZAAAAARLDIpEQAAABIuE1ySAAAAEzDnJBMAAAAUM7hIlAAA
+ABU2jBAVAAAAFkO3G5YAAAAXAAAAAQAAAAE=
+"""
+
+TZICAL_EST5EDT = """
+BEGIN:VTIMEZONE
+TZID:US-Eastern
+LAST-MODIFIED:19870101T000000Z
+TZURL:http://zones.stds_r_us.net/tz/US-Eastern
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+"""
+
+TZICAL_PST8PDT = """
+BEGIN:VTIMEZONE
+TZID:US-Pacific
+LAST-MODIFIED:19870101T000000Z
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+END:DAYLIGHT
+END:VTIMEZONE
+"""
+
+EST_TUPLE = ('EST', timedelta(hours=-5), timedelta(hours=0))
+EDT_TUPLE = ('EDT', timedelta(hours=-4), timedelta(hours=1))
+
SUPPORTS_SUB_MINUTE_OFFSETS = sys.version_info >= (3, 6)
-
-
-###
-# Helper functions
-def get_timezone_tuple(dt):
- """Retrieve a (tzname, utcoffset, dst) tuple for a given DST"""
- return dt.tzname(), dt.utcoffset(), dt.dst()
-
-
-###
-# Mix-ins
-class context_passthrough(object):
- def __init__(*args, **kwargs):
- pass
-
- def __enter__(*args, **kwargs):
- pass
-
- def __exit__(*args, **kwargs):
- pass
-
-
-class TzFoldMixin(object):
- """ Mix-in class for testing ambiguous times """
- def gettz(self, tzname):
- raise NotImplementedError
-
- def _get_tzname(self, tzname):
- return tzname
-
- def _gettz_context(self, tzname):
- return context_passthrough()
-
- def testFoldPositiveUTCOffset(self):
- # Test that we can resolve ambiguous times
- tzname = self._get_tzname('Australia/Sydney')
-
- with self._gettz_context(tzname):
- SYD = self.gettz(tzname)
-
+
+
+###
+# Helper functions
+def get_timezone_tuple(dt):
+ """Retrieve a (tzname, utcoffset, dst) tuple for a given DST"""
+ return dt.tzname(), dt.utcoffset(), dt.dst()
+
+
+###
+# Mix-ins
+class context_passthrough(object):
+ def __init__(*args, **kwargs):
+ pass
+
+ def __enter__(*args, **kwargs):
+ pass
+
+ def __exit__(*args, **kwargs):
+ pass
+
+
+class TzFoldMixin(object):
+ """ Mix-in class for testing ambiguous times """
+ def gettz(self, tzname):
+ raise NotImplementedError
+
+ def _get_tzname(self, tzname):
+ return tzname
+
+ def _gettz_context(self, tzname):
+ return context_passthrough()
+
+ def testFoldPositiveUTCOffset(self):
+ # Test that we can resolve ambiguous times
+ tzname = self._get_tzname('Australia/Sydney')
+
+ with self._gettz_context(tzname):
+ SYD = self.gettz(tzname)
+
t0_u = datetime(2012, 3, 31, 15, 30, tzinfo=tz.UTC) # AEST
t1_u = datetime(2012, 3, 31, 16, 30, tzinfo=tz.UTC) # AEDT
-
- t0_syd0 = t0_u.astimezone(SYD)
- t1_syd1 = t1_u.astimezone(SYD)
-
- self.assertEqual(t0_syd0.replace(tzinfo=None),
- datetime(2012, 4, 1, 2, 30))
-
- self.assertEqual(t1_syd1.replace(tzinfo=None),
- datetime(2012, 4, 1, 2, 30))
-
- self.assertEqual(t0_syd0.utcoffset(), timedelta(hours=11))
- self.assertEqual(t1_syd1.utcoffset(), timedelta(hours=10))
-
- def testGapPositiveUTCOffset(self):
- # Test that we don't have a problem around gaps.
- tzname = self._get_tzname('Australia/Sydney')
-
- with self._gettz_context(tzname):
- SYD = self.gettz(tzname)
-
+
+ t0_syd0 = t0_u.astimezone(SYD)
+ t1_syd1 = t1_u.astimezone(SYD)
+
+ self.assertEqual(t0_syd0.replace(tzinfo=None),
+ datetime(2012, 4, 1, 2, 30))
+
+ self.assertEqual(t1_syd1.replace(tzinfo=None),
+ datetime(2012, 4, 1, 2, 30))
+
+ self.assertEqual(t0_syd0.utcoffset(), timedelta(hours=11))
+ self.assertEqual(t1_syd1.utcoffset(), timedelta(hours=10))
+
+ def testGapPositiveUTCOffset(self):
+ # Test that we don't have a problem around gaps.
+ tzname = self._get_tzname('Australia/Sydney')
+
+ with self._gettz_context(tzname):
+ SYD = self.gettz(tzname)
+
t0_u = datetime(2012, 10, 6, 15, 30, tzinfo=tz.UTC) # AEST
t1_u = datetime(2012, 10, 6, 16, 30, tzinfo=tz.UTC) # AEDT
-
- t0 = t0_u.astimezone(SYD)
- t1 = t1_u.astimezone(SYD)
-
- self.assertEqual(t0.replace(tzinfo=None),
- datetime(2012, 10, 7, 1, 30))
-
- self.assertEqual(t1.replace(tzinfo=None),
- datetime(2012, 10, 7, 3, 30))
-
- self.assertEqual(t0.utcoffset(), timedelta(hours=10))
- self.assertEqual(t1.utcoffset(), timedelta(hours=11))
-
- def testFoldNegativeUTCOffset(self):
- # Test that we can resolve ambiguous times
- tzname = self._get_tzname('America/Toronto')
-
- with self._gettz_context(tzname):
- TOR = self.gettz(tzname)
-
+
+ t0 = t0_u.astimezone(SYD)
+ t1 = t1_u.astimezone(SYD)
+
+ self.assertEqual(t0.replace(tzinfo=None),
+ datetime(2012, 10, 7, 1, 30))
+
+ self.assertEqual(t1.replace(tzinfo=None),
+ datetime(2012, 10, 7, 3, 30))
+
+ self.assertEqual(t0.utcoffset(), timedelta(hours=10))
+ self.assertEqual(t1.utcoffset(), timedelta(hours=11))
+
+ def testFoldNegativeUTCOffset(self):
+ # Test that we can resolve ambiguous times
+ tzname = self._get_tzname('America/Toronto')
+
+ with self._gettz_context(tzname):
+ TOR = self.gettz(tzname)
+
t0_u = datetime(2011, 11, 6, 5, 30, tzinfo=tz.UTC)
t1_u = datetime(2011, 11, 6, 6, 30, tzinfo=tz.UTC)
-
- t0_tor = t0_u.astimezone(TOR)
- t1_tor = t1_u.astimezone(TOR)
-
- self.assertEqual(t0_tor.replace(tzinfo=None),
- datetime(2011, 11, 6, 1, 30))
-
- self.assertEqual(t1_tor.replace(tzinfo=None),
- datetime(2011, 11, 6, 1, 30))
-
- self.assertNotEqual(t0_tor.tzname(), t1_tor.tzname())
- self.assertEqual(t0_tor.utcoffset(), timedelta(hours=-4.0))
- self.assertEqual(t1_tor.utcoffset(), timedelta(hours=-5.0))
-
- def testGapNegativeUTCOffset(self):
- # Test that we don't have a problem around gaps.
- tzname = self._get_tzname('America/Toronto')
-
- with self._gettz_context(tzname):
- TOR = self.gettz(tzname)
-
+
+ t0_tor = t0_u.astimezone(TOR)
+ t1_tor = t1_u.astimezone(TOR)
+
+ self.assertEqual(t0_tor.replace(tzinfo=None),
+ datetime(2011, 11, 6, 1, 30))
+
+ self.assertEqual(t1_tor.replace(tzinfo=None),
+ datetime(2011, 11, 6, 1, 30))
+
+ self.assertNotEqual(t0_tor.tzname(), t1_tor.tzname())
+ self.assertEqual(t0_tor.utcoffset(), timedelta(hours=-4.0))
+ self.assertEqual(t1_tor.utcoffset(), timedelta(hours=-5.0))
+
+ def testGapNegativeUTCOffset(self):
+ # Test that we don't have a problem around gaps.
+ tzname = self._get_tzname('America/Toronto')
+
+ with self._gettz_context(tzname):
+ TOR = self.gettz(tzname)
+
t0_u = datetime(2011, 3, 13, 6, 30, tzinfo=tz.UTC)
t1_u = datetime(2011, 3, 13, 7, 30, tzinfo=tz.UTC)
-
- t0 = t0_u.astimezone(TOR)
- t1 = t1_u.astimezone(TOR)
-
- self.assertEqual(t0.replace(tzinfo=None),
- datetime(2011, 3, 13, 1, 30))
-
- self.assertEqual(t1.replace(tzinfo=None),
- datetime(2011, 3, 13, 3, 30))
-
- self.assertNotEqual(t0, t1)
- self.assertEqual(t0.utcoffset(), timedelta(hours=-5.0))
- self.assertEqual(t1.utcoffset(), timedelta(hours=-4.0))
-
- def testFoldLondon(self):
- tzname = self._get_tzname('Europe/London')
-
- with self._gettz_context(tzname):
- LON = self.gettz(tzname)
+
+ t0 = t0_u.astimezone(TOR)
+ t1 = t1_u.astimezone(TOR)
+
+ self.assertEqual(t0.replace(tzinfo=None),
+ datetime(2011, 3, 13, 1, 30))
+
+ self.assertEqual(t1.replace(tzinfo=None),
+ datetime(2011, 3, 13, 3, 30))
+
+ self.assertNotEqual(t0, t1)
+ self.assertEqual(t0.utcoffset(), timedelta(hours=-5.0))
+ self.assertEqual(t1.utcoffset(), timedelta(hours=-4.0))
+
+ def testFoldLondon(self):
+ tzname = self._get_tzname('Europe/London')
+
+ with self._gettz_context(tzname):
+ LON = self.gettz(tzname)
UTC = tz.UTC
-
- t0_u = datetime(2013, 10, 27, 0, 30, tzinfo=UTC) # BST
- t1_u = datetime(2013, 10, 27, 1, 30, tzinfo=UTC) # GMT
-
- t0 = t0_u.astimezone(LON)
- t1 = t1_u.astimezone(LON)
-
- self.assertEqual(t0.replace(tzinfo=None),
- datetime(2013, 10, 27, 1, 30))
-
- self.assertEqual(t1.replace(tzinfo=None),
- datetime(2013, 10, 27, 1, 30))
-
- self.assertEqual(t0.utcoffset(), timedelta(hours=1))
- self.assertEqual(t1.utcoffset(), timedelta(hours=0))
-
- def testFoldIndependence(self):
- tzname = self._get_tzname('America/New_York')
-
- with self._gettz_context(tzname):
- NYC = self.gettz(tzname)
+
+ t0_u = datetime(2013, 10, 27, 0, 30, tzinfo=UTC) # BST
+ t1_u = datetime(2013, 10, 27, 1, 30, tzinfo=UTC) # GMT
+
+ t0 = t0_u.astimezone(LON)
+ t1 = t1_u.astimezone(LON)
+
+ self.assertEqual(t0.replace(tzinfo=None),
+ datetime(2013, 10, 27, 1, 30))
+
+ self.assertEqual(t1.replace(tzinfo=None),
+ datetime(2013, 10, 27, 1, 30))
+
+ self.assertEqual(t0.utcoffset(), timedelta(hours=1))
+ self.assertEqual(t1.utcoffset(), timedelta(hours=0))
+
+ def testFoldIndependence(self):
+ tzname = self._get_tzname('America/New_York')
+
+ with self._gettz_context(tzname):
+ NYC = self.gettz(tzname)
UTC = tz.UTC
- hour = timedelta(hours=1)
-
- # Firmly 2015-11-01 0:30 EDT-4
- pre_dst = datetime(2015, 11, 1, 0, 30, tzinfo=NYC)
-
- # Ambiguous between 2015-11-01 1:30 EDT-4 and 2015-11-01 1:30 EST-5
- in_dst = pre_dst + hour
- in_dst_tzname_0 = in_dst.tzname() # Stash the tzname - EDT
-
- # Doing the arithmetic in UTC creates a date that is unambiguously
- # 2015-11-01 1:30 EDT-5
- in_dst_via_utc = (pre_dst.astimezone(UTC) + 2*hour).astimezone(NYC)
-
- # Make sure the dates are actually ambiguous
- self.assertEqual(in_dst, in_dst_via_utc)
-
- # Make sure we got the right folding behavior
- self.assertNotEqual(in_dst_via_utc.tzname(), in_dst_tzname_0)
-
- # Now check to make sure in_dst's tzname hasn't changed
- self.assertEqual(in_dst_tzname_0, in_dst.tzname())
-
- def testInZoneFoldEquality(self):
- # Two datetimes in the same zone are considered to be equal if their
- # wall times are equal, even if they have different absolute times.
-
- tzname = self._get_tzname('America/New_York')
-
- with self._gettz_context(tzname):
- NYC = self.gettz(tzname)
+ hour = timedelta(hours=1)
+
+ # Firmly 2015-11-01 0:30 EDT-4
+ pre_dst = datetime(2015, 11, 1, 0, 30, tzinfo=NYC)
+
+ # Ambiguous between 2015-11-01 1:30 EDT-4 and 2015-11-01 1:30 EST-5
+ in_dst = pre_dst + hour
+ in_dst_tzname_0 = in_dst.tzname() # Stash the tzname - EDT
+
+ # Doing the arithmetic in UTC creates a date that is unambiguously
+ # 2015-11-01 1:30 EDT-5
+ in_dst_via_utc = (pre_dst.astimezone(UTC) + 2*hour).astimezone(NYC)
+
+ # Make sure the dates are actually ambiguous
+ self.assertEqual(in_dst, in_dst_via_utc)
+
+ # Make sure we got the right folding behavior
+ self.assertNotEqual(in_dst_via_utc.tzname(), in_dst_tzname_0)
+
+ # Now check to make sure in_dst's tzname hasn't changed
+ self.assertEqual(in_dst_tzname_0, in_dst.tzname())
+
+ def testInZoneFoldEquality(self):
+ # Two datetimes in the same zone are considered to be equal if their
+ # wall times are equal, even if they have different absolute times.
+
+ tzname = self._get_tzname('America/New_York')
+
+ with self._gettz_context(tzname):
+ NYC = self.gettz(tzname)
UTC = tz.UTC
-
- dt0 = datetime(2011, 11, 6, 1, 30, tzinfo=NYC)
- dt1 = tz.enfold(dt0, fold=1)
-
- # Make sure these actually represent different times
- self.assertNotEqual(dt0.astimezone(UTC), dt1.astimezone(UTC))
-
- # Test that they compare equal
- self.assertEqual(dt0, dt1)
-
- def _test_ambiguous_time(self, dt, tzid, ambiguous):
- # This is a test to check that the individual is_ambiguous values
- # on the _tzinfo subclasses work.
- tzname = self._get_tzname(tzid)
-
- with self._gettz_context(tzname):
- tzi = self.gettz(tzname)
-
- self.assertEqual(tz.datetime_ambiguous(dt, tz=tzi), ambiguous)
-
- def testAmbiguousNegativeUTCOffset(self):
- self._test_ambiguous_time(datetime(2015, 11, 1, 1, 30),
- 'America/New_York', True)
-
- def testAmbiguousPositiveUTCOffset(self):
- self._test_ambiguous_time(datetime(2012, 4, 1, 2, 30),
- 'Australia/Sydney', True)
-
- def testUnambiguousNegativeUTCOffset(self):
- self._test_ambiguous_time(datetime(2015, 11, 1, 2, 30),
- 'America/New_York', False)
-
- def testUnambiguousPositiveUTCOffset(self):
- self._test_ambiguous_time(datetime(2012, 4, 1, 3, 30),
- 'Australia/Sydney', False)
-
- def testUnambiguousGapNegativeUTCOffset(self):
- # Imaginary time
- self._test_ambiguous_time(datetime(2011, 3, 13, 2, 30),
- 'America/New_York', False)
-
- def testUnambiguousGapPositiveUTCOffset(self):
- # Imaginary time
- self._test_ambiguous_time(datetime(2012, 10, 7, 2, 30),
- 'Australia/Sydney', False)
-
- def _test_imaginary_time(self, dt, tzid, exists):
- tzname = self._get_tzname(tzid)
- with self._gettz_context(tzname):
- tzi = self.gettz(tzname)
-
- self.assertEqual(tz.datetime_exists(dt, tz=tzi), exists)
-
- def testImaginaryNegativeUTCOffset(self):
- self._test_imaginary_time(datetime(2011, 3, 13, 2, 30),
- 'America/New_York', False)
-
- def testNotImaginaryNegativeUTCOffset(self):
- self._test_imaginary_time(datetime(2011, 3, 13, 1, 30),
- 'America/New_York', True)
-
- def testImaginaryPositiveUTCOffset(self):
- self._test_imaginary_time(datetime(2012, 10, 7, 2, 30),
- 'Australia/Sydney', False)
-
- def testNotImaginaryPositiveUTCOffset(self):
- self._test_imaginary_time(datetime(2012, 10, 7, 1, 30),
- 'Australia/Sydney', True)
-
- def testNotImaginaryFoldNegativeUTCOffset(self):
- self._test_imaginary_time(datetime(2015, 11, 1, 1, 30),
- 'America/New_York', True)
-
- def testNotImaginaryFoldPositiveUTCOffset(self):
- self._test_imaginary_time(datetime(2012, 4, 1, 3, 30),
- 'Australia/Sydney', True)
-
- @unittest.skip("Known failure in Python 3.6.")
- def testEqualAmbiguousComparison(self):
- tzname = self._get_tzname('Australia/Sydney')
-
- with self._gettz_context(tzname):
- SYD0 = self.gettz(tzname)
- SYD1 = self.gettz(tzname)
-
+
+ dt0 = datetime(2011, 11, 6, 1, 30, tzinfo=NYC)
+ dt1 = tz.enfold(dt0, fold=1)
+
+ # Make sure these actually represent different times
+ self.assertNotEqual(dt0.astimezone(UTC), dt1.astimezone(UTC))
+
+ # Test that they compare equal
+ self.assertEqual(dt0, dt1)
+
+ def _test_ambiguous_time(self, dt, tzid, ambiguous):
+ # This is a test to check that the individual is_ambiguous values
+ # on the _tzinfo subclasses work.
+ tzname = self._get_tzname(tzid)
+
+ with self._gettz_context(tzname):
+ tzi = self.gettz(tzname)
+
+ self.assertEqual(tz.datetime_ambiguous(dt, tz=tzi), ambiguous)
+
+ def testAmbiguousNegativeUTCOffset(self):
+ self._test_ambiguous_time(datetime(2015, 11, 1, 1, 30),
+ 'America/New_York', True)
+
+ def testAmbiguousPositiveUTCOffset(self):
+ self._test_ambiguous_time(datetime(2012, 4, 1, 2, 30),
+ 'Australia/Sydney', True)
+
+ def testUnambiguousNegativeUTCOffset(self):
+ self._test_ambiguous_time(datetime(2015, 11, 1, 2, 30),
+ 'America/New_York', False)
+
+ def testUnambiguousPositiveUTCOffset(self):
+ self._test_ambiguous_time(datetime(2012, 4, 1, 3, 30),
+ 'Australia/Sydney', False)
+
+ def testUnambiguousGapNegativeUTCOffset(self):
+ # Imaginary time
+ self._test_ambiguous_time(datetime(2011, 3, 13, 2, 30),
+ 'America/New_York', False)
+
+ def testUnambiguousGapPositiveUTCOffset(self):
+ # Imaginary time
+ self._test_ambiguous_time(datetime(2012, 10, 7, 2, 30),
+ 'Australia/Sydney', False)
+
+ def _test_imaginary_time(self, dt, tzid, exists):
+ tzname = self._get_tzname(tzid)
+ with self._gettz_context(tzname):
+ tzi = self.gettz(tzname)
+
+ self.assertEqual(tz.datetime_exists(dt, tz=tzi), exists)
+
+ def testImaginaryNegativeUTCOffset(self):
+ self._test_imaginary_time(datetime(2011, 3, 13, 2, 30),
+ 'America/New_York', False)
+
+ def testNotImaginaryNegativeUTCOffset(self):
+ self._test_imaginary_time(datetime(2011, 3, 13, 1, 30),
+ 'America/New_York', True)
+
+ def testImaginaryPositiveUTCOffset(self):
+ self._test_imaginary_time(datetime(2012, 10, 7, 2, 30),
+ 'Australia/Sydney', False)
+
+ def testNotImaginaryPositiveUTCOffset(self):
+ self._test_imaginary_time(datetime(2012, 10, 7, 1, 30),
+ 'Australia/Sydney', True)
+
+ def testNotImaginaryFoldNegativeUTCOffset(self):
+ self._test_imaginary_time(datetime(2015, 11, 1, 1, 30),
+ 'America/New_York', True)
+
+ def testNotImaginaryFoldPositiveUTCOffset(self):
+ self._test_imaginary_time(datetime(2012, 4, 1, 3, 30),
+ 'Australia/Sydney', True)
+
+ @unittest.skip("Known failure in Python 3.6.")
+ def testEqualAmbiguousComparison(self):
+ tzname = self._get_tzname('Australia/Sydney')
+
+ with self._gettz_context(tzname):
+ SYD0 = self.gettz(tzname)
+ SYD1 = self.gettz(tzname)
+
t0_u = datetime(2012, 3, 31, 14, 30, tzinfo=tz.UTC) # AEST
-
- t0_syd0 = t0_u.astimezone(SYD0)
- t0_syd1 = t0_u.astimezone(SYD1)
-
- # This is considered an "inter-zone comparison" because it's an
- # ambiguous datetime.
- self.assertEqual(t0_syd0, t0_syd1)
-
-
-class TzWinFoldMixin(object):
- def get_args(self, tzname):
- return (tzname, )
-
- class context(object):
- def __init__(*args, **kwargs):
- pass
-
- def __enter__(*args, **kwargs):
- pass
-
- def __exit__(*args, **kwargs):
- pass
-
- def get_utc_transitions(self, tzi, year, gap):
- dston, dstoff = tzi.transitions(year)
- if gap:
- t_n = dston - timedelta(minutes=30)
-
+
+ t0_syd0 = t0_u.astimezone(SYD0)
+ t0_syd1 = t0_u.astimezone(SYD1)
+
+ # This is considered an "inter-zone comparison" because it's an
+ # ambiguous datetime.
+ self.assertEqual(t0_syd0, t0_syd1)
+
+
+class TzWinFoldMixin(object):
+ def get_args(self, tzname):
+ return (tzname, )
+
+ class context(object):
+ def __init__(*args, **kwargs):
+ pass
+
+ def __enter__(*args, **kwargs):
+ pass
+
+ def __exit__(*args, **kwargs):
+ pass
+
+ def get_utc_transitions(self, tzi, year, gap):
+ dston, dstoff = tzi.transitions(year)
+ if gap:
+ t_n = dston - timedelta(minutes=30)
+
t0_u = t_n.replace(tzinfo=tzi).astimezone(tz.UTC)
- t1_u = t0_u + timedelta(hours=1)
- else:
- # Get 1 hour before the first ambiguous date
- t_n = dstoff - timedelta(minutes=30)
-
+ t1_u = t0_u + timedelta(hours=1)
+ else:
+ # Get 1 hour before the first ambiguous date
+ t_n = dstoff - timedelta(minutes=30)
+
t0_u = t_n.replace(tzinfo=tzi).astimezone(tz.UTC)
- t_n += timedelta(hours=1) # Naive ambiguous date
- t0_u = t0_u + timedelta(hours=1) # First ambiguous date
- t1_u = t0_u + timedelta(hours=1) # Second ambiguous date
-
- return t_n, t0_u, t1_u
-
- def testFoldPositiveUTCOffset(self):
- # Test that we can resolve ambiguous times
- tzname = 'AUS Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- # Calling fromutc() alters the tzfile object
- SYD = self.tzclass(*args)
-
- # Get the transition time in UTC from the object, because
- # Windows doesn't store historical info
- t_n, t0_u, t1_u = self.get_utc_transitions(SYD, 2012, False)
-
- # Using fresh tzfiles
- t0_syd = t0_u.astimezone(SYD)
- t1_syd = t1_u.astimezone(SYD)
-
- self.assertEqual(t0_syd.replace(tzinfo=None), t_n)
-
- self.assertEqual(t1_syd.replace(tzinfo=None), t_n)
-
- self.assertEqual(t0_syd.utcoffset(), timedelta(hours=11))
- self.assertEqual(t1_syd.utcoffset(), timedelta(hours=10))
- self.assertNotEqual(t0_syd.tzname(), t1_syd.tzname())
-
- def testGapPositiveUTCOffset(self):
- # Test that we don't have a problem around gaps.
- tzname = 'AUS Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- SYD = self.tzclass(*args)
-
- t_n, t0_u, t1_u = self.get_utc_transitions(SYD, 2012, True)
-
- t0 = t0_u.astimezone(SYD)
- t1 = t1_u.astimezone(SYD)
-
- self.assertEqual(t0.replace(tzinfo=None), t_n)
-
- self.assertEqual(t1.replace(tzinfo=None), t_n + timedelta(hours=2))
-
- self.assertEqual(t0.utcoffset(), timedelta(hours=10))
- self.assertEqual(t1.utcoffset(), timedelta(hours=11))
-
- def testFoldNegativeUTCOffset(self):
- # Test that we can resolve ambiguous times
- tzname = 'Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- TOR = self.tzclass(*args)
-
- t_n, t0_u, t1_u = self.get_utc_transitions(TOR, 2011, False)
-
- t0_tor = t0_u.astimezone(TOR)
- t1_tor = t1_u.astimezone(TOR)
-
- self.assertEqual(t0_tor.replace(tzinfo=None), t_n)
- self.assertEqual(t1_tor.replace(tzinfo=None), t_n)
-
- self.assertNotEqual(t0_tor.tzname(), t1_tor.tzname())
- self.assertEqual(t0_tor.utcoffset(), timedelta(hours=-4.0))
- self.assertEqual(t1_tor.utcoffset(), timedelta(hours=-5.0))
-
- def testGapNegativeUTCOffset(self):
- # Test that we don't have a problem around gaps.
- tzname = 'Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- TOR = self.tzclass(*args)
-
- t_n, t0_u, t1_u = self.get_utc_transitions(TOR, 2011, True)
-
- t0 = t0_u.astimezone(TOR)
- t1 = t1_u.astimezone(TOR)
-
- self.assertEqual(t0.replace(tzinfo=None),
- t_n)
-
- self.assertEqual(t1.replace(tzinfo=None),
- t_n + timedelta(hours=2))
-
- self.assertNotEqual(t0.tzname(), t1.tzname())
- self.assertEqual(t0.utcoffset(), timedelta(hours=-5.0))
- self.assertEqual(t1.utcoffset(), timedelta(hours=-4.0))
-
- def testFoldIndependence(self):
- tzname = 'Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- NYC = self.tzclass(*args)
+ t_n += timedelta(hours=1) # Naive ambiguous date
+ t0_u = t0_u + timedelta(hours=1) # First ambiguous date
+ t1_u = t0_u + timedelta(hours=1) # Second ambiguous date
+
+ return t_n, t0_u, t1_u
+
+ def testFoldPositiveUTCOffset(self):
+ # Test that we can resolve ambiguous times
+ tzname = 'AUS Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ # Calling fromutc() alters the tzfile object
+ SYD = self.tzclass(*args)
+
+ # Get the transition time in UTC from the object, because
+ # Windows doesn't store historical info
+ t_n, t0_u, t1_u = self.get_utc_transitions(SYD, 2012, False)
+
+ # Using fresh tzfiles
+ t0_syd = t0_u.astimezone(SYD)
+ t1_syd = t1_u.astimezone(SYD)
+
+ self.assertEqual(t0_syd.replace(tzinfo=None), t_n)
+
+ self.assertEqual(t1_syd.replace(tzinfo=None), t_n)
+
+ self.assertEqual(t0_syd.utcoffset(), timedelta(hours=11))
+ self.assertEqual(t1_syd.utcoffset(), timedelta(hours=10))
+ self.assertNotEqual(t0_syd.tzname(), t1_syd.tzname())
+
+ def testGapPositiveUTCOffset(self):
+ # Test that we don't have a problem around gaps.
+ tzname = 'AUS Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ SYD = self.tzclass(*args)
+
+ t_n, t0_u, t1_u = self.get_utc_transitions(SYD, 2012, True)
+
+ t0 = t0_u.astimezone(SYD)
+ t1 = t1_u.astimezone(SYD)
+
+ self.assertEqual(t0.replace(tzinfo=None), t_n)
+
+ self.assertEqual(t1.replace(tzinfo=None), t_n + timedelta(hours=2))
+
+ self.assertEqual(t0.utcoffset(), timedelta(hours=10))
+ self.assertEqual(t1.utcoffset(), timedelta(hours=11))
+
+ def testFoldNegativeUTCOffset(self):
+ # Test that we can resolve ambiguous times
+ tzname = 'Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ TOR = self.tzclass(*args)
+
+ t_n, t0_u, t1_u = self.get_utc_transitions(TOR, 2011, False)
+
+ t0_tor = t0_u.astimezone(TOR)
+ t1_tor = t1_u.astimezone(TOR)
+
+ self.assertEqual(t0_tor.replace(tzinfo=None), t_n)
+ self.assertEqual(t1_tor.replace(tzinfo=None), t_n)
+
+ self.assertNotEqual(t0_tor.tzname(), t1_tor.tzname())
+ self.assertEqual(t0_tor.utcoffset(), timedelta(hours=-4.0))
+ self.assertEqual(t1_tor.utcoffset(), timedelta(hours=-5.0))
+
+ def testGapNegativeUTCOffset(self):
+ # Test that we don't have a problem around gaps.
+ tzname = 'Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ TOR = self.tzclass(*args)
+
+ t_n, t0_u, t1_u = self.get_utc_transitions(TOR, 2011, True)
+
+ t0 = t0_u.astimezone(TOR)
+ t1 = t1_u.astimezone(TOR)
+
+ self.assertEqual(t0.replace(tzinfo=None),
+ t_n)
+
+ self.assertEqual(t1.replace(tzinfo=None),
+ t_n + timedelta(hours=2))
+
+ self.assertNotEqual(t0.tzname(), t1.tzname())
+ self.assertEqual(t0.utcoffset(), timedelta(hours=-5.0))
+ self.assertEqual(t1.utcoffset(), timedelta(hours=-4.0))
+
+ def testFoldIndependence(self):
+ tzname = 'Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ NYC = self.tzclass(*args)
UTC = tz.UTC
- hour = timedelta(hours=1)
-
- # Firmly 2015-11-01 0:30 EDT-4
- t_n, t0_u, t1_u = self.get_utc_transitions(NYC, 2015, False)
-
- pre_dst = (t_n - hour).replace(tzinfo=NYC)
-
- # Currently, there's no way around the fact that this resolves to an
- # ambiguous date, which defaults to EST. I'm not hard-coding in the
- # answer, though, because the preferred behavior would be that this
- # results in a time on the EDT side.
-
- # Ambiguous between 2015-11-01 1:30 EDT-4 and 2015-11-01 1:30 EST-5
- in_dst = pre_dst + hour
- in_dst_tzname_0 = in_dst.tzname() # Stash the tzname - EDT
-
- # Doing the arithmetic in UTC creates a date that is unambiguously
- # 2015-11-01 1:30 EDT-5
- in_dst_via_utc = (pre_dst.astimezone(UTC) + 2*hour).astimezone(NYC)
-
- # Make sure we got the right folding behavior
- self.assertNotEqual(in_dst_via_utc.tzname(), in_dst_tzname_0)
-
- # Now check to make sure in_dst's tzname hasn't changed
- self.assertEqual(in_dst_tzname_0, in_dst.tzname())
-
- def testInZoneFoldEquality(self):
- # Two datetimes in the same zone are considered to be equal if their
- # wall times are equal, even if they have different absolute times.
- tzname = 'Eastern Standard Time'
- args = self.get_args(tzname)
-
- with self.context(tzname):
- NYC = self.tzclass(*args)
+ hour = timedelta(hours=1)
+
+ # Firmly 2015-11-01 0:30 EDT-4
+ t_n, t0_u, t1_u = self.get_utc_transitions(NYC, 2015, False)
+
+ pre_dst = (t_n - hour).replace(tzinfo=NYC)
+
+ # Currently, there's no way around the fact that this resolves to an
+ # ambiguous date, which defaults to EST. I'm not hard-coding in the
+ # answer, though, because the preferred behavior would be that this
+ # results in a time on the EDT side.
+
+ # Ambiguous between 2015-11-01 1:30 EDT-4 and 2015-11-01 1:30 EST-5
+ in_dst = pre_dst + hour
+ in_dst_tzname_0 = in_dst.tzname() # Stash the tzname - EDT
+
+ # Doing the arithmetic in UTC creates a date that is unambiguously
+ # 2015-11-01 1:30 EDT-5
+ in_dst_via_utc = (pre_dst.astimezone(UTC) + 2*hour).astimezone(NYC)
+
+ # Make sure we got the right folding behavior
+ self.assertNotEqual(in_dst_via_utc.tzname(), in_dst_tzname_0)
+
+ # Now check to make sure in_dst's tzname hasn't changed
+ self.assertEqual(in_dst_tzname_0, in_dst.tzname())
+
+ def testInZoneFoldEquality(self):
+ # Two datetimes in the same zone are considered to be equal if their
+ # wall times are equal, even if they have different absolute times.
+ tzname = 'Eastern Standard Time'
+ args = self.get_args(tzname)
+
+ with self.context(tzname):
+ NYC = self.tzclass(*args)
UTC = tz.UTC
-
- t_n, t0_u, t1_u = self.get_utc_transitions(NYC, 2011, False)
-
- dt0 = t_n.replace(tzinfo=NYC)
- dt1 = tz.enfold(dt0, fold=1)
-
- # Make sure these actually represent different times
- self.assertNotEqual(dt0.astimezone(UTC), dt1.astimezone(UTC))
-
- # Test that they compare equal
- self.assertEqual(dt0, dt1)
-
-###
-# Test Cases
-class TzUTCTest(unittest.TestCase):
- def testSingleton(self):
- UTC_0 = tz.tzutc()
- UTC_1 = tz.tzutc()
-
- self.assertIs(UTC_0, UTC_1)
-
- def testOffset(self):
- ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
-
- self.assertEqual(ct.utcoffset(), timedelta(seconds=0))
-
- def testDst(self):
- ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
-
- self.assertEqual(ct.dst(), timedelta(seconds=0))
-
- def testTzName(self):
- ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
- self.assertEqual(ct.tzname(), 'UTC')
-
- def testEquality(self):
- UTC0 = tz.tzutc()
- UTC1 = tz.tzutc()
-
- self.assertEqual(UTC0, UTC1)
-
- def testInequality(self):
- UTC = tz.tzutc()
- UTCp4 = tz.tzoffset('UTC+4', 14400)
-
- self.assertNotEqual(UTC, UTCp4)
-
- def testInequalityInteger(self):
- self.assertFalse(tz.tzutc() == 7)
- self.assertNotEqual(tz.tzutc(), 7)
-
- def testInequalityUnsupported(self):
- self.assertEqual(tz.tzutc(), ComparesEqual)
-
- def testRepr(self):
- UTC = tz.tzutc()
- self.assertEqual(repr(UTC), 'tzutc()')
-
- def testTimeOnlyUTC(self):
- # https://github.com/dateutil/dateutil/issues/132
- # tzutc doesn't care
- tz_utc = tz.tzutc()
- self.assertEqual(dt_time(13, 20, tzinfo=tz_utc).utcoffset(),
- timedelta(0))
-
- def testAmbiguity(self):
- # Pick an arbitrary datetime, this should always return False.
- dt = datetime(2011, 9, 1, 2, 30, tzinfo=tz.tzutc())
-
- self.assertFalse(tz.datetime_ambiguous(dt))
-
-
-@pytest.mark.tzoffset
-class TzOffsetTest(unittest.TestCase):
- def testTimedeltaOffset(self):
- est = tz.tzoffset('EST', timedelta(hours=-5))
- est_s = tz.tzoffset('EST', -18000)
-
- self.assertEqual(est, est_s)
-
- def testTzNameNone(self):
- gmt5 = tz.tzoffset(None, -18000) # -5:00
- self.assertIs(datetime(2003, 10, 26, 0, 0, tzinfo=gmt5).tzname(),
- None)
-
- def testTimeOnlyOffset(self):
- # tzoffset doesn't care
- tz_offset = tz.tzoffset('+3', 3600)
- self.assertEqual(dt_time(13, 20, tzinfo=tz_offset).utcoffset(),
- timedelta(seconds=3600))
-
- def testTzOffsetRepr(self):
- tname = 'EST'
- tzo = tz.tzoffset(tname, -5 * 3600)
- self.assertEqual(repr(tzo), "tzoffset(" + repr(tname) + ", -18000)")
-
- def testEquality(self):
- utc = tz.tzoffset('UTC', 0)
- gmt = tz.tzoffset('GMT', 0)
-
- self.assertEqual(utc, gmt)
-
- def testUTCEquality(self):
+
+ t_n, t0_u, t1_u = self.get_utc_transitions(NYC, 2011, False)
+
+ dt0 = t_n.replace(tzinfo=NYC)
+ dt1 = tz.enfold(dt0, fold=1)
+
+ # Make sure these actually represent different times
+ self.assertNotEqual(dt0.astimezone(UTC), dt1.astimezone(UTC))
+
+ # Test that they compare equal
+ self.assertEqual(dt0, dt1)
+
+###
+# Test Cases
+class TzUTCTest(unittest.TestCase):
+ def testSingleton(self):
+ UTC_0 = tz.tzutc()
+ UTC_1 = tz.tzutc()
+
+ self.assertIs(UTC_0, UTC_1)
+
+ def testOffset(self):
+ ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
+
+ self.assertEqual(ct.utcoffset(), timedelta(seconds=0))
+
+ def testDst(self):
+ ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
+
+ self.assertEqual(ct.dst(), timedelta(seconds=0))
+
+ def testTzName(self):
+ ct = datetime(2009, 4, 1, 12, 11, 13, tzinfo=tz.tzutc())
+ self.assertEqual(ct.tzname(), 'UTC')
+
+ def testEquality(self):
+ UTC0 = tz.tzutc()
+ UTC1 = tz.tzutc()
+
+ self.assertEqual(UTC0, UTC1)
+
+ def testInequality(self):
+ UTC = tz.tzutc()
+ UTCp4 = tz.tzoffset('UTC+4', 14400)
+
+ self.assertNotEqual(UTC, UTCp4)
+
+ def testInequalityInteger(self):
+ self.assertFalse(tz.tzutc() == 7)
+ self.assertNotEqual(tz.tzutc(), 7)
+
+ def testInequalityUnsupported(self):
+ self.assertEqual(tz.tzutc(), ComparesEqual)
+
+ def testRepr(self):
+ UTC = tz.tzutc()
+ self.assertEqual(repr(UTC), 'tzutc()')
+
+ def testTimeOnlyUTC(self):
+ # https://github.com/dateutil/dateutil/issues/132
+ # tzutc doesn't care
+ tz_utc = tz.tzutc()
+ self.assertEqual(dt_time(13, 20, tzinfo=tz_utc).utcoffset(),
+ timedelta(0))
+
+ def testAmbiguity(self):
+ # Pick an arbitrary datetime, this should always return False.
+ dt = datetime(2011, 9, 1, 2, 30, tzinfo=tz.tzutc())
+
+ self.assertFalse(tz.datetime_ambiguous(dt))
+
+
+@pytest.mark.tzoffset
+class TzOffsetTest(unittest.TestCase):
+ def testTimedeltaOffset(self):
+ est = tz.tzoffset('EST', timedelta(hours=-5))
+ est_s = tz.tzoffset('EST', -18000)
+
+ self.assertEqual(est, est_s)
+
+ def testTzNameNone(self):
+ gmt5 = tz.tzoffset(None, -18000) # -5:00
+ self.assertIs(datetime(2003, 10, 26, 0, 0, tzinfo=gmt5).tzname(),
+ None)
+
+ def testTimeOnlyOffset(self):
+ # tzoffset doesn't care
+ tz_offset = tz.tzoffset('+3', 3600)
+ self.assertEqual(dt_time(13, 20, tzinfo=tz_offset).utcoffset(),
+ timedelta(seconds=3600))
+
+ def testTzOffsetRepr(self):
+ tname = 'EST'
+ tzo = tz.tzoffset(tname, -5 * 3600)
+ self.assertEqual(repr(tzo), "tzoffset(" + repr(tname) + ", -18000)")
+
+ def testEquality(self):
+ utc = tz.tzoffset('UTC', 0)
+ gmt = tz.tzoffset('GMT', 0)
+
+ self.assertEqual(utc, gmt)
+
+ def testUTCEquality(self):
utc = tz.UTC
- o_utc = tz.tzoffset('UTC', 0)
-
- self.assertEqual(utc, o_utc)
- self.assertEqual(o_utc, utc)
-
- def testInequalityInvalid(self):
- tzo = tz.tzoffset('-3', -3 * 3600)
- self.assertFalse(tzo == -3)
- self.assertNotEqual(tzo, -3)
-
- def testInequalityUnsupported(self):
- tzo = tz.tzoffset('-5', -5 * 3600)
-
- self.assertTrue(tzo == ComparesEqual)
- self.assertFalse(tzo != ComparesEqual)
- self.assertEqual(tzo, ComparesEqual)
-
- def testAmbiguity(self):
- # Pick an arbitrary datetime, this should always return False.
- dt = datetime(2011, 9, 1, 2, 30, tzinfo=tz.tzoffset("EST", -5 * 3600))
-
- self.assertFalse(tz.datetime_ambiguous(dt))
-
- def testTzOffsetInstance(self):
- tz1 = tz.tzoffset.instance('EST', timedelta(hours=-5))
- tz2 = tz.tzoffset.instance('EST', timedelta(hours=-5))
-
- assert tz1 is not tz2
-
- def testTzOffsetSingletonDifferent(self):
- tz1 = tz.tzoffset('EST', timedelta(hours=-5))
- tz2 = tz.tzoffset('EST', -18000)
-
- assert tz1 is tz2
-
+ o_utc = tz.tzoffset('UTC', 0)
+
+ self.assertEqual(utc, o_utc)
+ self.assertEqual(o_utc, utc)
+
+ def testInequalityInvalid(self):
+ tzo = tz.tzoffset('-3', -3 * 3600)
+ self.assertFalse(tzo == -3)
+ self.assertNotEqual(tzo, -3)
+
+ def testInequalityUnsupported(self):
+ tzo = tz.tzoffset('-5', -5 * 3600)
+
+ self.assertTrue(tzo == ComparesEqual)
+ self.assertFalse(tzo != ComparesEqual)
+ self.assertEqual(tzo, ComparesEqual)
+
+ def testAmbiguity(self):
+ # Pick an arbitrary datetime, this should always return False.
+ dt = datetime(2011, 9, 1, 2, 30, tzinfo=tz.tzoffset("EST", -5 * 3600))
+
+ self.assertFalse(tz.datetime_ambiguous(dt))
+
+ def testTzOffsetInstance(self):
+ tz1 = tz.tzoffset.instance('EST', timedelta(hours=-5))
+ tz2 = tz.tzoffset.instance('EST', timedelta(hours=-5))
+
+ assert tz1 is not tz2
+
+ def testTzOffsetSingletonDifferent(self):
+ tz1 = tz.tzoffset('EST', timedelta(hours=-5))
+ tz2 = tz.tzoffset('EST', -18000)
+
+ assert tz1 is tz2
+
@pytest.mark.smoke
-@pytest.mark.tzoffset
+@pytest.mark.tzoffset
def test_tzoffset_weakref():
UTC1 = tz.tzoffset('UTC', 0)
UTC_ref = weakref.ref(tz.tzoffset('UTC', 0))
@@ -758,18 +758,18 @@ def test_tzoffset_weakref():
@pytest.mark.tzoffset
-@pytest.mark.parametrize('args', [
- ('UTC', 0),
- ('EST', -18000),
- ('EST', timedelta(hours=-5)),
- (None, timedelta(hours=3)),
-])
-def test_tzoffset_singleton(args):
- tz1 = tz.tzoffset(*args)
- tz2 = tz.tzoffset(*args)
-
- assert tz1 is tz2
-
+@pytest.mark.parametrize('args', [
+ ('UTC', 0),
+ ('EST', -18000),
+ ('EST', timedelta(hours=-5)),
+ (None, timedelta(hours=3)),
+])
+def test_tzoffset_singleton(args):
+ tz1 = tz.tzoffset(*args)
+ tz2 = tz.tzoffset(*args)
+
+ assert tz1 is tz2
+
@pytest.mark.tzoffset
@pytest.mark.skipif(not SUPPORTS_SUB_MINUTE_OFFSETS,
@@ -789,297 +789,297 @@ def test_tzoffset_sub_minute_rounding():
assert test_date.utcoffset() == timedelta(hours=12, minutes=1)
-@pytest.mark.tzlocal
-class TzLocalTest(unittest.TestCase):
- def testEquality(self):
- tz1 = tz.tzlocal()
- tz2 = tz.tzlocal()
-
- # Explicitly calling == and != here to ensure the operators work
- self.assertTrue(tz1 == tz2)
- self.assertFalse(tz1 != tz2)
-
- def testInequalityFixedOffset(self):
- tzl = tz.tzlocal()
- tzos = tz.tzoffset('LST', tzl._std_offset.total_seconds())
- tzod = tz.tzoffset('LDT', tzl._std_offset.total_seconds())
-
- self.assertFalse(tzl == tzos)
- self.assertFalse(tzl == tzod)
- self.assertTrue(tzl != tzos)
- self.assertTrue(tzl != tzod)
-
- def testInequalityInvalid(self):
- tzl = tz.tzlocal()
-
- self.assertTrue(tzl != 1)
- self.assertFalse(tzl == 1)
-
- # TODO: Use some sort of universal local mocking so that it's clear
- # that we're expecting tzlocal to *not* be Pacific/Kiritimati
- LINT = tz.gettz('Pacific/Kiritimati')
- self.assertTrue(tzl != LINT)
- self.assertFalse(tzl == LINT)
-
- def testInequalityUnsupported(self):
- tzl = tz.tzlocal()
-
- self.assertTrue(tzl == ComparesEqual)
- self.assertFalse(tzl != ComparesEqual)
-
- def testRepr(self):
- tzl = tz.tzlocal()
-
- self.assertEqual(repr(tzl), 'tzlocal()')
-
-
-@pytest.mark.parametrize('args,kwargs', [
- (('EST', -18000), {}),
- (('EST', timedelta(hours=-5)), {}),
- (('EST',), {'offset': -18000}),
- (('EST',), {'offset': timedelta(hours=-5)}),
- (tuple(), {'name': 'EST', 'offset': -18000})
-])
-def test_tzoffset_is(args, kwargs):
- tz_ref = tz.tzoffset('EST', -18000)
- assert tz.tzoffset(*args, **kwargs) is tz_ref
-
-
-def test_tzoffset_is_not():
- assert tz.tzoffset('EDT', -14400) is not tz.tzoffset('EST', -18000)
-
-
-@pytest.mark.tzlocal
-@unittest.skipIf(IS_WIN, "requires Unix")
-class TzLocalNixTest(unittest.TestCase, TzFoldMixin):
- # This is a set of tests for `tzlocal()` on *nix systems
-
- # POSIX string indicating change to summer time on the 2nd Sunday in March
- # at 2AM, and ending the 1st Sunday in November at 2AM. (valid >= 2007)
- TZ_EST = 'EST+5EDT,M3.2.0/2,M11.1.0/2'
-
- # POSIX string for AEST/AEDT (valid >= 2008)
- TZ_AEST = 'AEST-10AEDT,M10.1.0/2,M4.1.0/3'
-
- # POSIX string for BST/GMT
- TZ_LON = 'GMT0BST,M3.5.0,M10.5.0'
-
- # POSIX string for UTC
- UTC = 'UTC'
-
- def gettz(self, tzname):
- # Actual time zone changes are handled by the _gettz_context function
- return tz.tzlocal()
-
- def _gettz_context(self, tzname):
- tzname_map = {'Australia/Sydney': self.TZ_AEST,
- 'America/Toronto': self.TZ_EST,
- 'America/New_York': self.TZ_EST,
- 'Europe/London': self.TZ_LON}
-
- return TZEnvContext(tzname_map.get(tzname, tzname))
-
- def _testTzFunc(self, tzval, func, std_val, dst_val):
- """
- This generates tests about how the behavior of a function ``func``
- changes between STD and DST (e.g. utcoffset, tzname, dst).
-
- It assume that DST starts the 2nd Sunday in March and ends the 1st
- Sunday in November
- """
- with TZEnvContext(tzval):
- dt1 = datetime(2015, 2, 1, 12, 0, tzinfo=tz.tzlocal()) # STD
- dt2 = datetime(2015, 5, 1, 12, 0, tzinfo=tz.tzlocal()) # DST
-
- self.assertEqual(func(dt1), std_val)
- self.assertEqual(func(dt2), dst_val)
-
- def _testTzName(self, tzval, std_name, dst_name):
- func = datetime.tzname
-
- self._testTzFunc(tzval, func, std_name, dst_name)
-
- def testTzNameDST(self):
- # Test tzname in a zone with DST
- self._testTzName(self.TZ_EST, 'EST', 'EDT')
-
- def testTzNameUTC(self):
- # Test tzname in a zone without DST
- self._testTzName(self.UTC, 'UTC', 'UTC')
-
- def _testOffset(self, tzval, std_off, dst_off):
- func = datetime.utcoffset
-
- self._testTzFunc(tzval, func, std_off, dst_off)
-
- def testOffsetDST(self):
- self._testOffset(self.TZ_EST, timedelta(hours=-5), timedelta(hours=-4))
-
- def testOffsetUTC(self):
- self._testOffset(self.UTC, timedelta(0), timedelta(0))
-
- def _testDST(self, tzval, dst_dst):
- func = datetime.dst
- std_dst = timedelta(0)
-
- self._testTzFunc(tzval, func, std_dst, dst_dst)
-
- def testDSTDST(self):
- self._testDST(self.TZ_EST, timedelta(hours=1))
-
- def testDSTUTC(self):
- self._testDST(self.UTC, timedelta(0))
-
- def testTimeOnlyOffsetLocalUTC(self):
- with TZEnvContext(self.UTC):
- self.assertEqual(dt_time(13, 20, tzinfo=tz.tzlocal()).utcoffset(),
- timedelta(0))
-
- def testTimeOnlyOffsetLocalDST(self):
- with TZEnvContext(self.TZ_EST):
- self.assertIs(dt_time(13, 20, tzinfo=tz.tzlocal()).utcoffset(),
- None)
-
- def testTimeOnlyDSTLocalUTC(self):
- with TZEnvContext(self.UTC):
- self.assertEqual(dt_time(13, 20, tzinfo=tz.tzlocal()).dst(),
- timedelta(0))
-
- def testTimeOnlyDSTLocalDST(self):
- with TZEnvContext(self.TZ_EST):
- self.assertIs(dt_time(13, 20, tzinfo=tz.tzlocal()).dst(),
- None)
-
- def testUTCEquality(self):
- with TZEnvContext(self.UTC):
+@pytest.mark.tzlocal
+class TzLocalTest(unittest.TestCase):
+ def testEquality(self):
+ tz1 = tz.tzlocal()
+ tz2 = tz.tzlocal()
+
+ # Explicitly calling == and != here to ensure the operators work
+ self.assertTrue(tz1 == tz2)
+ self.assertFalse(tz1 != tz2)
+
+ def testInequalityFixedOffset(self):
+ tzl = tz.tzlocal()
+ tzos = tz.tzoffset('LST', tzl._std_offset.total_seconds())
+ tzod = tz.tzoffset('LDT', tzl._std_offset.total_seconds())
+
+ self.assertFalse(tzl == tzos)
+ self.assertFalse(tzl == tzod)
+ self.assertTrue(tzl != tzos)
+ self.assertTrue(tzl != tzod)
+
+ def testInequalityInvalid(self):
+ tzl = tz.tzlocal()
+
+ self.assertTrue(tzl != 1)
+ self.assertFalse(tzl == 1)
+
+ # TODO: Use some sort of universal local mocking so that it's clear
+ # that we're expecting tzlocal to *not* be Pacific/Kiritimati
+ LINT = tz.gettz('Pacific/Kiritimati')
+ self.assertTrue(tzl != LINT)
+ self.assertFalse(tzl == LINT)
+
+ def testInequalityUnsupported(self):
+ tzl = tz.tzlocal()
+
+ self.assertTrue(tzl == ComparesEqual)
+ self.assertFalse(tzl != ComparesEqual)
+
+ def testRepr(self):
+ tzl = tz.tzlocal()
+
+ self.assertEqual(repr(tzl), 'tzlocal()')
+
+
+@pytest.mark.parametrize('args,kwargs', [
+ (('EST', -18000), {}),
+ (('EST', timedelta(hours=-5)), {}),
+ (('EST',), {'offset': -18000}),
+ (('EST',), {'offset': timedelta(hours=-5)}),
+ (tuple(), {'name': 'EST', 'offset': -18000})
+])
+def test_tzoffset_is(args, kwargs):
+ tz_ref = tz.tzoffset('EST', -18000)
+ assert tz.tzoffset(*args, **kwargs) is tz_ref
+
+
+def test_tzoffset_is_not():
+ assert tz.tzoffset('EDT', -14400) is not tz.tzoffset('EST', -18000)
+
+
+@pytest.mark.tzlocal
+@unittest.skipIf(IS_WIN, "requires Unix")
+class TzLocalNixTest(unittest.TestCase, TzFoldMixin):
+ # This is a set of tests for `tzlocal()` on *nix systems
+
+ # POSIX string indicating change to summer time on the 2nd Sunday in March
+ # at 2AM, and ending the 1st Sunday in November at 2AM. (valid >= 2007)
+ TZ_EST = 'EST+5EDT,M3.2.0/2,M11.1.0/2'
+
+ # POSIX string for AEST/AEDT (valid >= 2008)
+ TZ_AEST = 'AEST-10AEDT,M10.1.0/2,M4.1.0/3'
+
+ # POSIX string for BST/GMT
+ TZ_LON = 'GMT0BST,M3.5.0,M10.5.0'
+
+ # POSIX string for UTC
+ UTC = 'UTC'
+
+ def gettz(self, tzname):
+ # Actual time zone changes are handled by the _gettz_context function
+ return tz.tzlocal()
+
+ def _gettz_context(self, tzname):
+ tzname_map = {'Australia/Sydney': self.TZ_AEST,
+ 'America/Toronto': self.TZ_EST,
+ 'America/New_York': self.TZ_EST,
+ 'Europe/London': self.TZ_LON}
+
+ return TZEnvContext(tzname_map.get(tzname, tzname))
+
+ def _testTzFunc(self, tzval, func, std_val, dst_val):
+ """
+ This generates tests about how the behavior of a function ``func``
+ changes between STD and DST (e.g. utcoffset, tzname, dst).
+
+ It assume that DST starts the 2nd Sunday in March and ends the 1st
+ Sunday in November
+ """
+ with TZEnvContext(tzval):
+ dt1 = datetime(2015, 2, 1, 12, 0, tzinfo=tz.tzlocal()) # STD
+ dt2 = datetime(2015, 5, 1, 12, 0, tzinfo=tz.tzlocal()) # DST
+
+ self.assertEqual(func(dt1), std_val)
+ self.assertEqual(func(dt2), dst_val)
+
+ def _testTzName(self, tzval, std_name, dst_name):
+ func = datetime.tzname
+
+ self._testTzFunc(tzval, func, std_name, dst_name)
+
+ def testTzNameDST(self):
+ # Test tzname in a zone with DST
+ self._testTzName(self.TZ_EST, 'EST', 'EDT')
+
+ def testTzNameUTC(self):
+ # Test tzname in a zone without DST
+ self._testTzName(self.UTC, 'UTC', 'UTC')
+
+ def _testOffset(self, tzval, std_off, dst_off):
+ func = datetime.utcoffset
+
+ self._testTzFunc(tzval, func, std_off, dst_off)
+
+ def testOffsetDST(self):
+ self._testOffset(self.TZ_EST, timedelta(hours=-5), timedelta(hours=-4))
+
+ def testOffsetUTC(self):
+ self._testOffset(self.UTC, timedelta(0), timedelta(0))
+
+ def _testDST(self, tzval, dst_dst):
+ func = datetime.dst
+ std_dst = timedelta(0)
+
+ self._testTzFunc(tzval, func, std_dst, dst_dst)
+
+ def testDSTDST(self):
+ self._testDST(self.TZ_EST, timedelta(hours=1))
+
+ def testDSTUTC(self):
+ self._testDST(self.UTC, timedelta(0))
+
+ def testTimeOnlyOffsetLocalUTC(self):
+ with TZEnvContext(self.UTC):
+ self.assertEqual(dt_time(13, 20, tzinfo=tz.tzlocal()).utcoffset(),
+ timedelta(0))
+
+ def testTimeOnlyOffsetLocalDST(self):
+ with TZEnvContext(self.TZ_EST):
+ self.assertIs(dt_time(13, 20, tzinfo=tz.tzlocal()).utcoffset(),
+ None)
+
+ def testTimeOnlyDSTLocalUTC(self):
+ with TZEnvContext(self.UTC):
+ self.assertEqual(dt_time(13, 20, tzinfo=tz.tzlocal()).dst(),
+ timedelta(0))
+
+ def testTimeOnlyDSTLocalDST(self):
+ with TZEnvContext(self.TZ_EST):
+ self.assertIs(dt_time(13, 20, tzinfo=tz.tzlocal()).dst(),
+ None)
+
+ def testUTCEquality(self):
+ with TZEnvContext(self.UTC):
assert tz.tzlocal() == tz.UTC
-
-
-# TODO: Maybe a better hack than this?
-def mark_tzlocal_nix(f):
- marks = [
- pytest.mark.tzlocal,
- pytest.mark.skipif(IS_WIN, reason='requires Unix'),
- ]
-
- for mark in reversed(marks):
- f = mark(f)
-
- return f
-
-
-@mark_tzlocal_nix
-@pytest.mark.parametrize('tzvar', ['UTC', 'GMT0', 'UTC0'])
-def test_tzlocal_utc_equal(tzvar):
- with TZEnvContext(tzvar):
- assert tz.tzlocal() == tz.UTC
-
-
-@mark_tzlocal_nix
-@pytest.mark.parametrize('tzvar', [
- 'Europe/London', 'America/New_York',
- 'GMT0BST', 'EST5EDT'])
-def test_tzlocal_utc_unequal(tzvar):
- with TZEnvContext(tzvar):
- assert tz.tzlocal() != tz.UTC
-
-
-@mark_tzlocal_nix
-def test_tzlocal_local_time_trim_colon():
- with TZEnvContext(':/etc/localtime'):
- assert tz.gettz() is not None
-
-
-@mark_tzlocal_nix
-@pytest.mark.parametrize('tzvar, tzoff', [
- ('EST5', tz.tzoffset('EST', -18000)),
+
+
+# TODO: Maybe a better hack than this?
+def mark_tzlocal_nix(f):
+ marks = [
+ pytest.mark.tzlocal,
+ pytest.mark.skipif(IS_WIN, reason='requires Unix'),
+ ]
+
+ for mark in reversed(marks):
+ f = mark(f)
+
+ return f
+
+
+@mark_tzlocal_nix
+@pytest.mark.parametrize('tzvar', ['UTC', 'GMT0', 'UTC0'])
+def test_tzlocal_utc_equal(tzvar):
+ with TZEnvContext(tzvar):
+ assert tz.tzlocal() == tz.UTC
+
+
+@mark_tzlocal_nix
+@pytest.mark.parametrize('tzvar', [
+ 'Europe/London', 'America/New_York',
+ 'GMT0BST', 'EST5EDT'])
+def test_tzlocal_utc_unequal(tzvar):
+ with TZEnvContext(tzvar):
+ assert tz.tzlocal() != tz.UTC
+
+
+@mark_tzlocal_nix
+def test_tzlocal_local_time_trim_colon():
+ with TZEnvContext(':/etc/localtime'):
+ assert tz.gettz() is not None
+
+
+@mark_tzlocal_nix
+@pytest.mark.parametrize('tzvar, tzoff', [
+ ('EST5', tz.tzoffset('EST', -18000)),
('GMT0', tz.tzoffset('GMT', 0)),
- ('YAKT-9', tz.tzoffset('YAKT', timedelta(hours=9))),
- ('JST-9', tz.tzoffset('JST', timedelta(hours=9))),
-])
-def test_tzlocal_offset_equal(tzvar, tzoff):
- with TZEnvContext(tzvar):
- # Including both to test both __eq__ and __ne__
- assert tz.tzlocal() == tzoff
- assert not (tz.tzlocal() != tzoff)
-
-
-@mark_tzlocal_nix
-@pytest.mark.parametrize('tzvar, tzoff', [
- ('EST5EDT', tz.tzoffset('EST', -18000)),
- ('GMT0BST', tz.tzoffset('GMT', 0)),
- ('EST5', tz.tzoffset('EST', -14400)),
- ('YAKT-9', tz.tzoffset('JST', timedelta(hours=9))),
- ('JST-9', tz.tzoffset('YAKT', timedelta(hours=9))),
-])
-def test_tzlocal_offset_unequal(tzvar, tzoff):
- with TZEnvContext(tzvar):
- # Including both to test both __eq__ and __ne__
- assert tz.tzlocal() != tzoff
- assert not (tz.tzlocal() == tzoff)
-
-
-@pytest.mark.gettz
-class GettzTest(unittest.TestCase, TzFoldMixin):
- gettz = staticmethod(tz.gettz)
-
- def testGettz(self):
- # bug 892569
- str(self.gettz('UTC'))
-
- def testGetTzEquality(self):
- self.assertEqual(self.gettz('UTC'), self.gettz('UTC'))
-
- def testTimeOnlyGettz(self):
- # gettz returns None
- tz_get = self.gettz('Europe/Minsk')
- self.assertIs(dt_time(13, 20, tzinfo=tz_get).utcoffset(), None)
-
- def testTimeOnlyGettzDST(self):
- # gettz returns None
- tz_get = self.gettz('Europe/Minsk')
- self.assertIs(dt_time(13, 20, tzinfo=tz_get).dst(), None)
-
- def testTimeOnlyGettzTzName(self):
- tz_get = self.gettz('Europe/Minsk')
- self.assertIs(dt_time(13, 20, tzinfo=tz_get).tzname(), None)
-
- def testTimeOnlyFormatZ(self):
- tz_get = self.gettz('Europe/Minsk')
- t = dt_time(13, 20, tzinfo=tz_get)
-
- self.assertEqual(t.strftime('%H%M%Z'), '1320')
-
- def testPortugalDST(self):
- # In 1996, Portugal changed from CET to WET
- PORTUGAL = self.gettz('Portugal')
-
- t_cet = datetime(1996, 3, 31, 1, 59, tzinfo=PORTUGAL)
-
- self.assertEqual(t_cet.tzname(), 'CET')
- self.assertEqual(t_cet.utcoffset(), timedelta(hours=1))
- self.assertEqual(t_cet.dst(), timedelta(0))
-
- t_west = datetime(1996, 3, 31, 2, 1, tzinfo=PORTUGAL)
-
- self.assertEqual(t_west.tzname(), 'WEST')
- self.assertEqual(t_west.utcoffset(), timedelta(hours=1))
- self.assertEqual(t_west.dst(), timedelta(hours=1))
-
- def testGettzCacheTzFile(self):
- NYC1 = tz.gettz('America/New_York')
- NYC2 = tz.gettz('America/New_York')
-
- assert NYC1 is NYC2
-
- def testGettzCacheTzLocal(self):
- local1 = tz.gettz()
- local2 = tz.gettz()
-
- assert local1 is not local2
-
-
-@pytest.mark.gettz
+ ('YAKT-9', tz.tzoffset('YAKT', timedelta(hours=9))),
+ ('JST-9', tz.tzoffset('JST', timedelta(hours=9))),
+])
+def test_tzlocal_offset_equal(tzvar, tzoff):
+ with TZEnvContext(tzvar):
+ # Including both to test both __eq__ and __ne__
+ assert tz.tzlocal() == tzoff
+ assert not (tz.tzlocal() != tzoff)
+
+
+@mark_tzlocal_nix
+@pytest.mark.parametrize('tzvar, tzoff', [
+ ('EST5EDT', tz.tzoffset('EST', -18000)),
+ ('GMT0BST', tz.tzoffset('GMT', 0)),
+ ('EST5', tz.tzoffset('EST', -14400)),
+ ('YAKT-9', tz.tzoffset('JST', timedelta(hours=9))),
+ ('JST-9', tz.tzoffset('YAKT', timedelta(hours=9))),
+])
+def test_tzlocal_offset_unequal(tzvar, tzoff):
+ with TZEnvContext(tzvar):
+ # Including both to test both __eq__ and __ne__
+ assert tz.tzlocal() != tzoff
+ assert not (tz.tzlocal() == tzoff)
+
+
+@pytest.mark.gettz
+class GettzTest(unittest.TestCase, TzFoldMixin):
+ gettz = staticmethod(tz.gettz)
+
+ def testGettz(self):
+ # bug 892569
+ str(self.gettz('UTC'))
+
+ def testGetTzEquality(self):
+ self.assertEqual(self.gettz('UTC'), self.gettz('UTC'))
+
+ def testTimeOnlyGettz(self):
+ # gettz returns None
+ tz_get = self.gettz('Europe/Minsk')
+ self.assertIs(dt_time(13, 20, tzinfo=tz_get).utcoffset(), None)
+
+ def testTimeOnlyGettzDST(self):
+ # gettz returns None
+ tz_get = self.gettz('Europe/Minsk')
+ self.assertIs(dt_time(13, 20, tzinfo=tz_get).dst(), None)
+
+ def testTimeOnlyGettzTzName(self):
+ tz_get = self.gettz('Europe/Minsk')
+ self.assertIs(dt_time(13, 20, tzinfo=tz_get).tzname(), None)
+
+ def testTimeOnlyFormatZ(self):
+ tz_get = self.gettz('Europe/Minsk')
+ t = dt_time(13, 20, tzinfo=tz_get)
+
+ self.assertEqual(t.strftime('%H%M%Z'), '1320')
+
+ def testPortugalDST(self):
+ # In 1996, Portugal changed from CET to WET
+ PORTUGAL = self.gettz('Portugal')
+
+ t_cet = datetime(1996, 3, 31, 1, 59, tzinfo=PORTUGAL)
+
+ self.assertEqual(t_cet.tzname(), 'CET')
+ self.assertEqual(t_cet.utcoffset(), timedelta(hours=1))
+ self.assertEqual(t_cet.dst(), timedelta(0))
+
+ t_west = datetime(1996, 3, 31, 2, 1, tzinfo=PORTUGAL)
+
+ self.assertEqual(t_west.tzname(), 'WEST')
+ self.assertEqual(t_west.utcoffset(), timedelta(hours=1))
+ self.assertEqual(t_west.dst(), timedelta(hours=1))
+
+ def testGettzCacheTzFile(self):
+ NYC1 = tz.gettz('America/New_York')
+ NYC2 = tz.gettz('America/New_York')
+
+ assert NYC1 is NYC2
+
+ def testGettzCacheTzLocal(self):
+ local1 = tz.gettz()
+ local2 = tz.gettz()
+
+ assert local1 is not local2
+
+
+@pytest.mark.gettz
def test_gettz_same_result_for_none_and_empty_string():
local_from_none = tz.gettz()
local_from_empty_string = tz.gettz("")
@@ -1137,21 +1137,21 @@ def test_gettz_zone_wrong_type(badzone, exc_reason):
@pytest.mark.gettz
-@pytest.mark.xfail(IS_WIN, reason='zoneinfo separately cached')
-def test_gettz_cache_clear():
- NYC1 = tz.gettz('America/New_York')
- tz.gettz.cache_clear()
-
- NYC2 = tz.gettz('America/New_York')
-
- assert NYC1 is not NYC2
-
+@pytest.mark.xfail(IS_WIN, reason='zoneinfo separately cached')
+def test_gettz_cache_clear():
+ NYC1 = tz.gettz('America/New_York')
+ tz.gettz.cache_clear()
+
+ NYC2 = tz.gettz('America/New_York')
+
+ assert NYC1 is not NYC2
+
@pytest.mark.gettz
@pytest.mark.xfail(IS_WIN, reason='zoneinfo separately cached')
def test_gettz_set_cache_size():
tz.gettz.cache_clear()
tz.gettz.set_cache_size(3)
-
+
MONACO_ref = weakref.ref(tz.gettz('Europe/Monaco'))
EASTER_ref = weakref.ref(tz.gettz('Pacific/Easter'))
CURRIE_ref = weakref.ref(tz.gettz('Australia/Currie'))
@@ -1194,335 +1194,335 @@ def test_gettz_weakref():
assert tz.gettz('America/New_York') is not NYC_ref()
class ZoneInfoGettzTest(GettzTest):
- def gettz(self, name):
- zoneinfo_file = zoneinfo.get_zonefile_instance()
- return zoneinfo_file.get(name)
-
- def testZoneInfoFileStart1(self):
- tz = self.gettz("EST5EDT")
- self.assertEqual(datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname(), "EST",
- MISSING_TARBALL)
- self.assertEqual(datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname(), "EDT")
-
- def testZoneInfoFileEnd1(self):
- tzc = self.gettz("EST5EDT")
- self.assertEqual(datetime(2003, 10, 26, 0, 59, tzinfo=tzc).tzname(),
- "EDT", MISSING_TARBALL)
-
- end_est = tz.enfold(datetime(2003, 10, 26, 1, 00, tzinfo=tzc), fold=1)
- self.assertEqual(end_est.tzname(), "EST")
-
- def testZoneInfoOffsetSignal(self):
- utc = self.gettz("UTC")
- nyc = self.gettz("America/New_York")
- self.assertNotEqual(utc, None, MISSING_TARBALL)
- self.assertNotEqual(nyc, None)
- t0 = datetime(2007, 11, 4, 0, 30, tzinfo=nyc)
- t1 = t0.astimezone(utc)
- t2 = t1.astimezone(nyc)
- self.assertEqual(t0, t2)
- self.assertEqual(nyc.dst(t0), timedelta(hours=1))
-
- def testZoneInfoCopy(self):
- # copy.copy() called on a ZoneInfo file was returning the same instance
- CHI = self.gettz('America/Chicago')
- CHI_COPY = copy.copy(CHI)
-
- self.assertIsNot(CHI, CHI_COPY)
- self.assertEqual(CHI, CHI_COPY)
-
- def testZoneInfoDeepCopy(self):
- CHI = self.gettz('America/Chicago')
- CHI_COPY = copy.deepcopy(CHI)
-
- self.assertIsNot(CHI, CHI_COPY)
- self.assertEqual(CHI, CHI_COPY)
-
- def testZoneInfoInstanceCaching(self):
- zif_0 = zoneinfo.get_zonefile_instance()
- zif_1 = zoneinfo.get_zonefile_instance()
-
- self.assertIs(zif_0, zif_1)
-
- def testZoneInfoNewInstance(self):
- zif_0 = zoneinfo.get_zonefile_instance()
- zif_1 = zoneinfo.get_zonefile_instance(new_instance=True)
- zif_2 = zoneinfo.get_zonefile_instance()
-
- self.assertIsNot(zif_0, zif_1)
- self.assertIs(zif_1, zif_2)
-
- def testZoneInfoDeprecated(self):
+ def gettz(self, name):
+ zoneinfo_file = zoneinfo.get_zonefile_instance()
+ return zoneinfo_file.get(name)
+
+ def testZoneInfoFileStart1(self):
+ tz = self.gettz("EST5EDT")
+ self.assertEqual(datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname(), "EST",
+ MISSING_TARBALL)
+ self.assertEqual(datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname(), "EDT")
+
+ def testZoneInfoFileEnd1(self):
+ tzc = self.gettz("EST5EDT")
+ self.assertEqual(datetime(2003, 10, 26, 0, 59, tzinfo=tzc).tzname(),
+ "EDT", MISSING_TARBALL)
+
+ end_est = tz.enfold(datetime(2003, 10, 26, 1, 00, tzinfo=tzc), fold=1)
+ self.assertEqual(end_est.tzname(), "EST")
+
+ def testZoneInfoOffsetSignal(self):
+ utc = self.gettz("UTC")
+ nyc = self.gettz("America/New_York")
+ self.assertNotEqual(utc, None, MISSING_TARBALL)
+ self.assertNotEqual(nyc, None)
+ t0 = datetime(2007, 11, 4, 0, 30, tzinfo=nyc)
+ t1 = t0.astimezone(utc)
+ t2 = t1.astimezone(nyc)
+ self.assertEqual(t0, t2)
+ self.assertEqual(nyc.dst(t0), timedelta(hours=1))
+
+ def testZoneInfoCopy(self):
+ # copy.copy() called on a ZoneInfo file was returning the same instance
+ CHI = self.gettz('America/Chicago')
+ CHI_COPY = copy.copy(CHI)
+
+ self.assertIsNot(CHI, CHI_COPY)
+ self.assertEqual(CHI, CHI_COPY)
+
+ def testZoneInfoDeepCopy(self):
+ CHI = self.gettz('America/Chicago')
+ CHI_COPY = copy.deepcopy(CHI)
+
+ self.assertIsNot(CHI, CHI_COPY)
+ self.assertEqual(CHI, CHI_COPY)
+
+ def testZoneInfoInstanceCaching(self):
+ zif_0 = zoneinfo.get_zonefile_instance()
+ zif_1 = zoneinfo.get_zonefile_instance()
+
+ self.assertIs(zif_0, zif_1)
+
+ def testZoneInfoNewInstance(self):
+ zif_0 = zoneinfo.get_zonefile_instance()
+ zif_1 = zoneinfo.get_zonefile_instance(new_instance=True)
+ zif_2 = zoneinfo.get_zonefile_instance()
+
+ self.assertIsNot(zif_0, zif_1)
+ self.assertIs(zif_1, zif_2)
+
+ def testZoneInfoDeprecated(self):
with pytest.warns(DeprecationWarning):
- zoneinfo.gettz('US/Eastern')
-
- def testZoneInfoMetadataDeprecated(self):
+ zoneinfo.gettz('US/Eastern')
+
+ def testZoneInfoMetadataDeprecated(self):
with pytest.warns(DeprecationWarning):
- zoneinfo.gettz_db_metadata()
-
-
-class TZRangeTest(unittest.TestCase, TzFoldMixin):
- TZ_EST = tz.tzrange('EST', timedelta(hours=-5),
- 'EDT', timedelta(hours=-4),
- start=relativedelta(month=3, day=1, hour=2,
- weekday=SU(+2)),
- end=relativedelta(month=11, day=1, hour=1,
- weekday=SU(+1)))
-
- TZ_AEST = tz.tzrange('AEST', timedelta(hours=10),
- 'AEDT', timedelta(hours=11),
- start=relativedelta(month=10, day=1, hour=2,
- weekday=SU(+1)),
- end=relativedelta(month=4, day=1, hour=2,
- weekday=SU(+1)))
-
- TZ_LON = tz.tzrange('GMT', timedelta(hours=0),
- 'BST', timedelta(hours=1),
- start=relativedelta(month=3, day=31, weekday=SU(-1),
- hours=2),
- end=relativedelta(month=10, day=31, weekday=SU(-1),
- hours=1))
- # POSIX string for UTC
- UTC = 'UTC'
-
- def gettz(self, tzname):
- tzname_map = {'Australia/Sydney': self.TZ_AEST,
- 'America/Toronto': self.TZ_EST,
- 'America/New_York': self.TZ_EST,
- 'Europe/London': self.TZ_LON}
-
- return tzname_map[tzname]
-
- def testRangeCmp1(self):
- self.assertEqual(tz.tzstr("EST5EDT"),
- tz.tzrange("EST", -18000, "EDT", -14400,
- relativedelta(hours=+2,
- month=4, day=1,
- weekday=SU(+1)),
- relativedelta(hours=+1,
- month=10, day=31,
- weekday=SU(-1))))
-
- def testRangeCmp2(self):
- self.assertEqual(tz.tzstr("EST5EDT"),
- tz.tzrange("EST", -18000, "EDT"))
-
- def testRangeOffsets(self):
- TZR = tz.tzrange('EST', -18000, 'EDT', -14400,
- start=relativedelta(hours=2, month=4, day=1,
- weekday=SU(+2)),
- end=relativedelta(hours=1, month=10, day=31,
- weekday=SU(-1)))
-
- dt_std = datetime(2014, 4, 11, 12, 0, tzinfo=TZR) # STD
- dt_dst = datetime(2016, 4, 11, 12, 0, tzinfo=TZR) # DST
-
- dst_zero = timedelta(0)
- dst_hour = timedelta(hours=1)
-
- std_offset = timedelta(hours=-5)
- dst_offset = timedelta(hours=-4)
-
- # Check dst()
- self.assertEqual(dt_std.dst(), dst_zero)
- self.assertEqual(dt_dst.dst(), dst_hour)
-
- # Check utcoffset()
- self.assertEqual(dt_std.utcoffset(), std_offset)
- self.assertEqual(dt_dst.utcoffset(), dst_offset)
-
- # Check tzname
- self.assertEqual(dt_std.tzname(), 'EST')
- self.assertEqual(dt_dst.tzname(), 'EDT')
-
- def testTimeOnlyRangeFixed(self):
- # This is a fixed-offset zone, so tzrange allows this
- tz_range = tz.tzrange('dflt', stdoffset=timedelta(hours=-3))
- self.assertEqual(dt_time(13, 20, tzinfo=tz_range).utcoffset(),
- timedelta(hours=-3))
-
- def testTimeOnlyRange(self):
- # tzrange returns None because this zone has DST
- tz_range = tz.tzrange('EST', timedelta(hours=-5),
- 'EDT', timedelta(hours=-4))
- self.assertIs(dt_time(13, 20, tzinfo=tz_range).utcoffset(), None)
-
- def testBrokenIsDstHandling(self):
- # tzrange._isdst() was using a date() rather than a datetime().
- # Issue reported by Lennart Regebro.
+ zoneinfo.gettz_db_metadata()
+
+
+class TZRangeTest(unittest.TestCase, TzFoldMixin):
+ TZ_EST = tz.tzrange('EST', timedelta(hours=-5),
+ 'EDT', timedelta(hours=-4),
+ start=relativedelta(month=3, day=1, hour=2,
+ weekday=SU(+2)),
+ end=relativedelta(month=11, day=1, hour=1,
+ weekday=SU(+1)))
+
+ TZ_AEST = tz.tzrange('AEST', timedelta(hours=10),
+ 'AEDT', timedelta(hours=11),
+ start=relativedelta(month=10, day=1, hour=2,
+ weekday=SU(+1)),
+ end=relativedelta(month=4, day=1, hour=2,
+ weekday=SU(+1)))
+
+ TZ_LON = tz.tzrange('GMT', timedelta(hours=0),
+ 'BST', timedelta(hours=1),
+ start=relativedelta(month=3, day=31, weekday=SU(-1),
+ hours=2),
+ end=relativedelta(month=10, day=31, weekday=SU(-1),
+ hours=1))
+ # POSIX string for UTC
+ UTC = 'UTC'
+
+ def gettz(self, tzname):
+ tzname_map = {'Australia/Sydney': self.TZ_AEST,
+ 'America/Toronto': self.TZ_EST,
+ 'America/New_York': self.TZ_EST,
+ 'Europe/London': self.TZ_LON}
+
+ return tzname_map[tzname]
+
+ def testRangeCmp1(self):
+ self.assertEqual(tz.tzstr("EST5EDT"),
+ tz.tzrange("EST", -18000, "EDT", -14400,
+ relativedelta(hours=+2,
+ month=4, day=1,
+ weekday=SU(+1)),
+ relativedelta(hours=+1,
+ month=10, day=31,
+ weekday=SU(-1))))
+
+ def testRangeCmp2(self):
+ self.assertEqual(tz.tzstr("EST5EDT"),
+ tz.tzrange("EST", -18000, "EDT"))
+
+ def testRangeOffsets(self):
+ TZR = tz.tzrange('EST', -18000, 'EDT', -14400,
+ start=relativedelta(hours=2, month=4, day=1,
+ weekday=SU(+2)),
+ end=relativedelta(hours=1, month=10, day=31,
+ weekday=SU(-1)))
+
+ dt_std = datetime(2014, 4, 11, 12, 0, tzinfo=TZR) # STD
+ dt_dst = datetime(2016, 4, 11, 12, 0, tzinfo=TZR) # DST
+
+ dst_zero = timedelta(0)
+ dst_hour = timedelta(hours=1)
+
+ std_offset = timedelta(hours=-5)
+ dst_offset = timedelta(hours=-4)
+
+ # Check dst()
+ self.assertEqual(dt_std.dst(), dst_zero)
+ self.assertEqual(dt_dst.dst(), dst_hour)
+
+ # Check utcoffset()
+ self.assertEqual(dt_std.utcoffset(), std_offset)
+ self.assertEqual(dt_dst.utcoffset(), dst_offset)
+
+ # Check tzname
+ self.assertEqual(dt_std.tzname(), 'EST')
+ self.assertEqual(dt_dst.tzname(), 'EDT')
+
+ def testTimeOnlyRangeFixed(self):
+ # This is a fixed-offset zone, so tzrange allows this
+ tz_range = tz.tzrange('dflt', stdoffset=timedelta(hours=-3))
+ self.assertEqual(dt_time(13, 20, tzinfo=tz_range).utcoffset(),
+ timedelta(hours=-3))
+
+ def testTimeOnlyRange(self):
+ # tzrange returns None because this zone has DST
+ tz_range = tz.tzrange('EST', timedelta(hours=-5),
+ 'EDT', timedelta(hours=-4))
+ self.assertIs(dt_time(13, 20, tzinfo=tz_range).utcoffset(), None)
+
+ def testBrokenIsDstHandling(self):
+ # tzrange._isdst() was using a date() rather than a datetime().
+ # Issue reported by Lennart Regebro.
dt = datetime(2007, 8, 6, 4, 10, tzinfo=tz.UTC)
- self.assertEqual(dt.astimezone(tz=tz.gettz("GMT+2")),
- datetime(2007, 8, 6, 6, 10, tzinfo=tz.tzstr("GMT+2")))
-
- def testRangeTimeDelta(self):
- # Test that tzrange can be specified with a timedelta instead of an int.
- EST5EDT_td = tz.tzrange('EST', timedelta(hours=-5),
- 'EDT', timedelta(hours=-4))
-
- EST5EDT_sec = tz.tzrange('EST', -18000,
- 'EDT', -14400)
-
- self.assertEqual(EST5EDT_td, EST5EDT_sec)
-
- def testRangeEquality(self):
- TZR1 = tz.tzrange('EST', -18000, 'EDT', -14400)
-
- # Standard abbreviation different
- TZR2 = tz.tzrange('ET', -18000, 'EDT', -14400)
- self.assertNotEqual(TZR1, TZR2)
-
- # DST abbreviation different
- TZR3 = tz.tzrange('EST', -18000, 'EMT', -14400)
- self.assertNotEqual(TZR1, TZR3)
-
- # STD offset different
- TZR4 = tz.tzrange('EST', -14000, 'EDT', -14400)
- self.assertNotEqual(TZR1, TZR4)
-
- # DST offset different
- TZR5 = tz.tzrange('EST', -18000, 'EDT', -18000)
- self.assertNotEqual(TZR1, TZR5)
-
- # Start delta different
- TZR6 = tz.tzrange('EST', -18000, 'EDT', -14400,
- start=relativedelta(hours=+1, month=3,
- day=1, weekday=SU(+2)))
- self.assertNotEqual(TZR1, TZR6)
-
- # End delta different
- TZR7 = tz.tzrange('EST', -18000, 'EDT', -14400,
- end=relativedelta(hours=+1, month=11,
- day=1, weekday=SU(+2)))
- self.assertNotEqual(TZR1, TZR7)
-
- def testRangeInequalityUnsupported(self):
- TZR = tz.tzrange('EST', -18000, 'EDT', -14400)
-
- self.assertFalse(TZR == 4)
- self.assertTrue(TZR == ComparesEqual)
- self.assertFalse(TZR != ComparesEqual)
-
-
-@pytest.mark.tzstr
-class TZStrTest(unittest.TestCase, TzFoldMixin):
- # POSIX string indicating change to summer time on the 2nd Sunday in March
- # at 2AM, and ending the 1st Sunday in November at 2AM. (valid >= 2007)
- TZ_EST = 'EST+5EDT,M3.2.0/2,M11.1.0/2'
-
- # POSIX string for AEST/AEDT (valid >= 2008)
- TZ_AEST = 'AEST-10AEDT,M10.1.0/2,M4.1.0/3'
-
- # POSIX string for GMT/BST
- TZ_LON = 'GMT0BST,M3.5.0,M10.5.0'
-
- def gettz(self, tzname):
- # Actual time zone changes are handled by the _gettz_context function
- tzname_map = {'Australia/Sydney': self.TZ_AEST,
- 'America/Toronto': self.TZ_EST,
- 'America/New_York': self.TZ_EST,
- 'Europe/London': self.TZ_LON}
-
- return tz.tzstr(tzname_map[tzname])
-
- def testStrStr(self):
- # Test that tz.tzstr() won't throw an error if given a str instead
- # of a unicode literal.
- self.assertEqual(datetime(2003, 4, 6, 1, 59,
- tzinfo=tz.tzstr(str("EST5EDT"))).tzname(), "EST")
- self.assertEqual(datetime(2003, 4, 6, 2, 00,
- tzinfo=tz.tzstr(str("EST5EDT"))).tzname(), "EDT")
-
- def testStrInequality(self):
- TZS1 = tz.tzstr('EST5EDT4')
-
- # Standard abbreviation different
- TZS2 = tz.tzstr('ET5EDT4')
- self.assertNotEqual(TZS1, TZS2)
-
- # DST abbreviation different
- TZS3 = tz.tzstr('EST5EMT')
- self.assertNotEqual(TZS1, TZS3)
-
- # STD offset different
- TZS4 = tz.tzstr('EST4EDT4')
- self.assertNotEqual(TZS1, TZS4)
-
- # DST offset different
- TZS5 = tz.tzstr('EST5EDT3')
- self.assertNotEqual(TZS1, TZS5)
-
- def testStrInequalityStartEnd(self):
- TZS1 = tz.tzstr('EST5EDT4')
-
- # Start delta different
- TZS2 = tz.tzstr('EST5EDT4,M4.2.0/02:00:00,M10-5-0/02:00')
- self.assertNotEqual(TZS1, TZS2)
-
- # End delta different
- TZS3 = tz.tzstr('EST5EDT4,M4.2.0/02:00:00,M11-5-0/02:00')
- self.assertNotEqual(TZS1, TZS3)
-
- def testPosixOffset(self):
- TZ1 = tz.tzstr('UTC-3')
- self.assertEqual(datetime(2015, 1, 1, tzinfo=TZ1).utcoffset(),
- timedelta(hours=-3))
-
- TZ2 = tz.tzstr('UTC-3', posix_offset=True)
- self.assertEqual(datetime(2015, 1, 1, tzinfo=TZ2).utcoffset(),
- timedelta(hours=+3))
-
- def testStrInequalityUnsupported(self):
- TZS = tz.tzstr('EST5EDT')
-
- self.assertFalse(TZS == 4)
- self.assertTrue(TZS == ComparesEqual)
- self.assertFalse(TZS != ComparesEqual)
-
- def testTzStrRepr(self):
- TZS1 = tz.tzstr('EST5EDT4')
- TZS2 = tz.tzstr('EST')
-
- self.assertEqual(repr(TZS1), "tzstr(" + repr('EST5EDT4') + ")")
- self.assertEqual(repr(TZS2), "tzstr(" + repr('EST') + ")")
-
- def testTzStrFailure(self):
- with self.assertRaises(ValueError):
- tz.tzstr('InvalidString;439999')
-
- def testTzStrSingleton(self):
- tz1 = tz.tzstr('EST5EDT')
- tz2 = tz.tzstr('CST4CST')
- tz3 = tz.tzstr('EST5EDT')
-
- self.assertIsNot(tz1, tz2)
- self.assertIs(tz1, tz3)
-
- def testTzStrSingletonPosix(self):
- tz_t1 = tz.tzstr('GMT+3', posix_offset=True)
- tz_f1 = tz.tzstr('GMT+3', posix_offset=False)
-
- tz_t2 = tz.tzstr('GMT+3', posix_offset=True)
- tz_f2 = tz.tzstr('GMT+3', posix_offset=False)
-
- self.assertIs(tz_t1, tz_t2)
- self.assertIsNot(tz_t1, tz_f1)
-
- self.assertIs(tz_f1, tz_f2)
-
- def testTzStrInstance(self):
- tz1 = tz.tzstr('EST5EDT')
- tz2 = tz.tzstr.instance('EST5EDT')
- tz3 = tz.tzstr.instance('EST5EDT')
-
- assert tz1 is not tz2
- assert tz2 is not tz3
-
- # Ensure that these still are all the same zone
- assert tz1 == tz2 == tz3
-
+ self.assertEqual(dt.astimezone(tz=tz.gettz("GMT+2")),
+ datetime(2007, 8, 6, 6, 10, tzinfo=tz.tzstr("GMT+2")))
+
+ def testRangeTimeDelta(self):
+ # Test that tzrange can be specified with a timedelta instead of an int.
+ EST5EDT_td = tz.tzrange('EST', timedelta(hours=-5),
+ 'EDT', timedelta(hours=-4))
+
+ EST5EDT_sec = tz.tzrange('EST', -18000,
+ 'EDT', -14400)
+
+ self.assertEqual(EST5EDT_td, EST5EDT_sec)
+
+ def testRangeEquality(self):
+ TZR1 = tz.tzrange('EST', -18000, 'EDT', -14400)
+
+ # Standard abbreviation different
+ TZR2 = tz.tzrange('ET', -18000, 'EDT', -14400)
+ self.assertNotEqual(TZR1, TZR2)
+
+ # DST abbreviation different
+ TZR3 = tz.tzrange('EST', -18000, 'EMT', -14400)
+ self.assertNotEqual(TZR1, TZR3)
+
+ # STD offset different
+ TZR4 = tz.tzrange('EST', -14000, 'EDT', -14400)
+ self.assertNotEqual(TZR1, TZR4)
+
+ # DST offset different
+ TZR5 = tz.tzrange('EST', -18000, 'EDT', -18000)
+ self.assertNotEqual(TZR1, TZR5)
+
+ # Start delta different
+ TZR6 = tz.tzrange('EST', -18000, 'EDT', -14400,
+ start=relativedelta(hours=+1, month=3,
+ day=1, weekday=SU(+2)))
+ self.assertNotEqual(TZR1, TZR6)
+
+ # End delta different
+ TZR7 = tz.tzrange('EST', -18000, 'EDT', -14400,
+ end=relativedelta(hours=+1, month=11,
+ day=1, weekday=SU(+2)))
+ self.assertNotEqual(TZR1, TZR7)
+
+ def testRangeInequalityUnsupported(self):
+ TZR = tz.tzrange('EST', -18000, 'EDT', -14400)
+
+ self.assertFalse(TZR == 4)
+ self.assertTrue(TZR == ComparesEqual)
+ self.assertFalse(TZR != ComparesEqual)
+
+
+@pytest.mark.tzstr
+class TZStrTest(unittest.TestCase, TzFoldMixin):
+ # POSIX string indicating change to summer time on the 2nd Sunday in March
+ # at 2AM, and ending the 1st Sunday in November at 2AM. (valid >= 2007)
+ TZ_EST = 'EST+5EDT,M3.2.0/2,M11.1.0/2'
+
+ # POSIX string for AEST/AEDT (valid >= 2008)
+ TZ_AEST = 'AEST-10AEDT,M10.1.0/2,M4.1.0/3'
+
+ # POSIX string for GMT/BST
+ TZ_LON = 'GMT0BST,M3.5.0,M10.5.0'
+
+ def gettz(self, tzname):
+ # Actual time zone changes are handled by the _gettz_context function
+ tzname_map = {'Australia/Sydney': self.TZ_AEST,
+ 'America/Toronto': self.TZ_EST,
+ 'America/New_York': self.TZ_EST,
+ 'Europe/London': self.TZ_LON}
+
+ return tz.tzstr(tzname_map[tzname])
+
+ def testStrStr(self):
+ # Test that tz.tzstr() won't throw an error if given a str instead
+ # of a unicode literal.
+ self.assertEqual(datetime(2003, 4, 6, 1, 59,
+ tzinfo=tz.tzstr(str("EST5EDT"))).tzname(), "EST")
+ self.assertEqual(datetime(2003, 4, 6, 2, 00,
+ tzinfo=tz.tzstr(str("EST5EDT"))).tzname(), "EDT")
+
+ def testStrInequality(self):
+ TZS1 = tz.tzstr('EST5EDT4')
+
+ # Standard abbreviation different
+ TZS2 = tz.tzstr('ET5EDT4')
+ self.assertNotEqual(TZS1, TZS2)
+
+ # DST abbreviation different
+ TZS3 = tz.tzstr('EST5EMT')
+ self.assertNotEqual(TZS1, TZS3)
+
+ # STD offset different
+ TZS4 = tz.tzstr('EST4EDT4')
+ self.assertNotEqual(TZS1, TZS4)
+
+ # DST offset different
+ TZS5 = tz.tzstr('EST5EDT3')
+ self.assertNotEqual(TZS1, TZS5)
+
+ def testStrInequalityStartEnd(self):
+ TZS1 = tz.tzstr('EST5EDT4')
+
+ # Start delta different
+ TZS2 = tz.tzstr('EST5EDT4,M4.2.0/02:00:00,M10-5-0/02:00')
+ self.assertNotEqual(TZS1, TZS2)
+
+ # End delta different
+ TZS3 = tz.tzstr('EST5EDT4,M4.2.0/02:00:00,M11-5-0/02:00')
+ self.assertNotEqual(TZS1, TZS3)
+
+ def testPosixOffset(self):
+ TZ1 = tz.tzstr('UTC-3')
+ self.assertEqual(datetime(2015, 1, 1, tzinfo=TZ1).utcoffset(),
+ timedelta(hours=-3))
+
+ TZ2 = tz.tzstr('UTC-3', posix_offset=True)
+ self.assertEqual(datetime(2015, 1, 1, tzinfo=TZ2).utcoffset(),
+ timedelta(hours=+3))
+
+ def testStrInequalityUnsupported(self):
+ TZS = tz.tzstr('EST5EDT')
+
+ self.assertFalse(TZS == 4)
+ self.assertTrue(TZS == ComparesEqual)
+ self.assertFalse(TZS != ComparesEqual)
+
+ def testTzStrRepr(self):
+ TZS1 = tz.tzstr('EST5EDT4')
+ TZS2 = tz.tzstr('EST')
+
+ self.assertEqual(repr(TZS1), "tzstr(" + repr('EST5EDT4') + ")")
+ self.assertEqual(repr(TZS2), "tzstr(" + repr('EST') + ")")
+
+ def testTzStrFailure(self):
+ with self.assertRaises(ValueError):
+ tz.tzstr('InvalidString;439999')
+
+ def testTzStrSingleton(self):
+ tz1 = tz.tzstr('EST5EDT')
+ tz2 = tz.tzstr('CST4CST')
+ tz3 = tz.tzstr('EST5EDT')
+
+ self.assertIsNot(tz1, tz2)
+ self.assertIs(tz1, tz3)
+
+ def testTzStrSingletonPosix(self):
+ tz_t1 = tz.tzstr('GMT+3', posix_offset=True)
+ tz_f1 = tz.tzstr('GMT+3', posix_offset=False)
+
+ tz_t2 = tz.tzstr('GMT+3', posix_offset=True)
+ tz_f2 = tz.tzstr('GMT+3', posix_offset=False)
+
+ self.assertIs(tz_t1, tz_t2)
+ self.assertIsNot(tz_t1, tz_f1)
+
+ self.assertIs(tz_f1, tz_f2)
+
+ def testTzStrInstance(self):
+ tz1 = tz.tzstr('EST5EDT')
+ tz2 = tz.tzstr.instance('EST5EDT')
+ tz3 = tz.tzstr.instance('EST5EDT')
+
+ assert tz1 is not tz2
+ assert tz2 is not tz3
+
+ # Ensure that these still are all the same zone
+ assert tz1 == tz2 == tz3
+
@pytest.mark.smoke
-@pytest.mark.tzstr
+@pytest.mark.tzstr
def test_tzstr_weakref():
tz_t1 = tz.tzstr('EST5EDT')
tz_t2_ref = weakref.ref(tz.tzstr('EST5EDT'))
@@ -1543,547 +1543,547 @@ def test_tzstr_weakref():
@pytest.mark.tzstr
-@pytest.mark.parametrize('tz_str,expected', [
- # From https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
- ('', tz.tzrange(None)), # TODO: Should change this so tz.tzrange('') works
- ('EST+5EDT,M3.2.0/2,M11.1.0/12',
- tz.tzrange('EST', -18000, 'EDT', -14400,
- start=relativedelta(month=3, day=1, weekday=SU(2), hours=2),
- end=relativedelta(month=11, day=1, weekday=SU(1), hours=11))),
- ('WART4WARST,J1/0,J365/25', # This is DST all year, Western Argentina Summer Time
- tz.tzrange('WART', timedelta(hours=-4), 'WARST',
- start=relativedelta(month=1, day=1, hours=0),
- end=relativedelta(month=12, day=31, days=1))),
- ('IST-2IDT,M3.4.4/26,M10.5.0', # Israel Standard / Daylight Time
- tz.tzrange('IST', timedelta(hours=2), 'IDT',
- start=relativedelta(month=3, day=1, weekday=TH(4), days=1, hours=2),
- end=relativedelta(month=10, day=31, weekday=SU(-1), hours=1))),
- ('WGT3WGST,M3.5.0/2,M10.5.0/1',
- tz.tzrange('WGT', timedelta(hours=-3), 'WGST',
- start=relativedelta(month=3, day=31, weekday=SU(-1), hours=2),
- end=relativedelta(month=10, day=31, weekday=SU(-1), hours=0))),
-
- # Different offset specifications
- ('WGT0300WGST',
- tz.tzrange('WGT', timedelta(hours=-3), 'WGST')),
- ('WGT03:00WGST',
- tz.tzrange('WGT', timedelta(hours=-3), 'WGST')),
- ('AEST-1100AEDT',
- tz.tzrange('AEST', timedelta(hours=11), 'AEDT')),
- ('AEST-11:00AEDT',
- tz.tzrange('AEST', timedelta(hours=11), 'AEDT')),
-
- # Different time formats
- ('EST5EDT,M3.2.0/4:00,M11.1.0/3:00',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
- end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
- ('EST5EDT,M3.2.0/04:00,M11.1.0/03:00',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
- end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
- ('EST5EDT,M3.2.0/0400,M11.1.0/0300',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
- end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
-])
-def test_valid_GNU_tzstr(tz_str, expected):
- tzi = tz.tzstr(tz_str)
-
- assert tzi == expected
-
-
-@pytest.mark.tzstr
-@pytest.mark.parametrize('tz_str, expected', [
- ('EST5EDT,5,4,0,7200,11,3,0,7200',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(month=5, day=1, weekday=SU(+4), hours=+2),
- end=relativedelta(month=11, day=1, weekday=SU(+3), hours=+1))),
- ('EST5EDT,5,-4,0,7200,11,3,0,7200',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(hours=+2, month=5, day=31, weekday=SU(-4)),
- end=relativedelta(hours=+1, month=11, day=1, weekday=SU(+3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200,3600',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200,3600',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200,-3600',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT', timedelta(hours=-6),
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=+3, month=11, day=31, weekday=SU(-3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200,+7200',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT', timedelta(hours=-3),
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=0, month=11, day=31, weekday=SU(-3)))),
- ('EST5EDT,5,4,0,7200,11,-3,0,7200,+3600',
- tz.tzrange('EST', timedelta(hours=-5), 'EDT',
- start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
- end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
-])
-def test_valid_dateutil_format(tz_str, expected):
- # This tests the dateutil-specific format that is used widely in the tests
- # and examples. It is unclear where this format originated from.
- with pytest.warns(tz.DeprecatedTzFormatWarning):
- tzi = tz.tzstr.instance(tz_str)
-
- assert tzi == expected
-
-
-@pytest.mark.tzstr
-@pytest.mark.parametrize('tz_str', [
- 'hdfiughdfuig,dfughdfuigpu87ñ::',
- ',dfughdfuigpu87ñ::',
- '-1:WART4WARST,J1,J365/25',
- 'WART4WARST,J1,J365/-25',
- 'IST-2IDT,M3.4.-1/26,M10.5.0',
- 'IST-2IDT,M3,2000,1/26,M10,5,0'
-])
-def test_invalid_GNU_tzstr(tz_str):
- with pytest.raises(ValueError):
- tz.tzstr(tz_str)
-
-
-# Different representations of the same default rule set
-DEFAULT_TZSTR_RULES_EQUIV_2003 = [
- 'EST5EDT',
- 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00',
- 'EST5EDT4,95/02:00:00,298/02:00',
- 'EST5EDT4,J96/02:00:00,J299/02:00',
- 'EST5EDT4,J96/02:00:00,J299/02'
-]
-
-
-@pytest.mark.tzstr
-@pytest.mark.parametrize('tz_str', DEFAULT_TZSTR_RULES_EQUIV_2003)
-def test_tzstr_default_start(tz_str):
- tzi = tz.tzstr(tz_str)
- dt_std = datetime(2003, 4, 6, 1, 59, tzinfo=tzi)
- dt_dst = datetime(2003, 4, 6, 2, 00, tzinfo=tzi)
-
- assert get_timezone_tuple(dt_std) == EST_TUPLE
- assert get_timezone_tuple(dt_dst) == EDT_TUPLE
-
-
-@pytest.mark.tzstr
-@pytest.mark.parametrize('tz_str', DEFAULT_TZSTR_RULES_EQUIV_2003)
-def test_tzstr_default_end(tz_str):
- tzi = tz.tzstr(tz_str)
- dt_dst = datetime(2003, 10, 26, 0, 59, tzinfo=tzi)
- dt_dst_ambig = datetime(2003, 10, 26, 1, 00, tzinfo=tzi)
- dt_std_ambig = tz.enfold(dt_dst_ambig, fold=1)
- dt_std = datetime(2003, 10, 26, 2, 00, tzinfo=tzi)
-
- assert get_timezone_tuple(dt_dst) == EDT_TUPLE
- assert get_timezone_tuple(dt_dst_ambig) == EDT_TUPLE
- assert get_timezone_tuple(dt_std_ambig) == EST_TUPLE
- assert get_timezone_tuple(dt_std) == EST_TUPLE
-
-
-@pytest.mark.tzstr
-@pytest.mark.parametrize('tzstr_1', ['EST5EDT',
- 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00'])
-@pytest.mark.parametrize('tzstr_2', ['EST5EDT',
- 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00'])
-def test_tzstr_default_cmp(tzstr_1, tzstr_2):
- tz1 = tz.tzstr(tzstr_1)
- tz2 = tz.tzstr(tzstr_2)
-
- assert tz1 == tz2
-
-class TZICalTest(unittest.TestCase, TzFoldMixin):
- def _gettz_str_tuple(self, tzname):
- TZ_EST = (
- 'BEGIN:VTIMEZONE',
- 'TZID:US-Eastern',
- 'BEGIN:STANDARD',
- 'DTSTART:19971029T020000',
- 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=11',
- 'TZOFFSETFROM:-0400',
- 'TZOFFSETTO:-0500',
- 'TZNAME:EST',
- 'END:STANDARD',
- 'BEGIN:DAYLIGHT',
- 'DTSTART:19980301T020000',
- 'RRULE:FREQ=YEARLY;BYDAY=+2SU;BYMONTH=03',
- 'TZOFFSETFROM:-0500',
- 'TZOFFSETTO:-0400',
- 'TZNAME:EDT',
- 'END:DAYLIGHT',
- 'END:VTIMEZONE'
- )
-
- TZ_PST = (
- 'BEGIN:VTIMEZONE',
- 'TZID:US-Pacific',
- 'BEGIN:STANDARD',
- 'DTSTART:19971029T020000',
- 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=11',
- 'TZOFFSETFROM:-0700',
- 'TZOFFSETTO:-0800',
- 'TZNAME:PST',
- 'END:STANDARD',
- 'BEGIN:DAYLIGHT',
- 'DTSTART:19980301T020000',
- 'RRULE:FREQ=YEARLY;BYDAY=+2SU;BYMONTH=03',
- 'TZOFFSETFROM:-0800',
- 'TZOFFSETTO:-0700',
- 'TZNAME:PDT',
- 'END:DAYLIGHT',
- 'END:VTIMEZONE'
- )
-
- TZ_AEST = (
- 'BEGIN:VTIMEZONE',
- 'TZID:Australia-Sydney',
- 'BEGIN:STANDARD',
- 'DTSTART:19980301T030000',
- 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=04',
- 'TZOFFSETFROM:+1100',
- 'TZOFFSETTO:+1000',
- 'TZNAME:AEST',
- 'END:STANDARD',
- 'BEGIN:DAYLIGHT',
- 'DTSTART:19971029T020000',
- 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=10',
- 'TZOFFSETFROM:+1000',
- 'TZOFFSETTO:+1100',
- 'TZNAME:AEDT',
- 'END:DAYLIGHT',
- 'END:VTIMEZONE'
- )
-
- TZ_LON = (
- 'BEGIN:VTIMEZONE',
- 'TZID:Europe-London',
- 'BEGIN:STANDARD',
- 'DTSTART:19810301T030000',
- 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;BYHOUR=02',
- 'TZOFFSETFROM:+0100',
- 'TZOFFSETTO:+0000',
- 'TZNAME:GMT',
- 'END:STANDARD',
- 'BEGIN:DAYLIGHT',
- 'DTSTART:19961001T030000',
- 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=03;BYHOUR=01',
- 'TZOFFSETFROM:+0000',
- 'TZOFFSETTO:+0100',
- 'TZNAME:BST',
- 'END:DAYLIGHT',
- 'END:VTIMEZONE'
- )
-
- tzname_map = {'Australia/Sydney': TZ_AEST,
- 'America/Toronto': TZ_EST,
- 'America/New_York': TZ_EST,
- 'America/Los_Angeles': TZ_PST,
- 'Europe/London': TZ_LON}
-
- return tzname_map[tzname]
-
- def _gettz_str(self, tzname):
- return '\n'.join(self._gettz_str_tuple(tzname))
-
- def _tzstr_dtstart_with_params(self, tzname, param_str):
- # Adds parameters to the DTSTART values of a given tzstr
- tz_str_tuple = self._gettz_str_tuple(tzname)
-
- out_tz = []
- for line in tz_str_tuple:
- if line.startswith('DTSTART'):
- name, value = line.split(':', 1)
- line = name + ';' + param_str + ':' + value
-
- out_tz.append(line)
-
- return '\n'.join(out_tz)
-
- def gettz(self, tzname):
- tz_str = self._gettz_str(tzname)
-
- tzc = tz.tzical(StringIO(tz_str)).get()
-
- return tzc
-
- def testRepr(self):
- instr = StringIO(TZICAL_PST8PDT)
- instr.name = 'StringIO(PST8PDT)'
- tzc = tz.tzical(instr)
-
- self.assertEqual(repr(tzc), "tzical(" + repr(instr.name) + ")")
-
- # Test performance
- def _test_us_zone(self, tzc, func, values, start):
- if start:
- dt1 = datetime(2003, 3, 9, 1, 59)
- dt2 = datetime(2003, 3, 9, 2, 00)
- fold = [0, 0]
- else:
- dt1 = datetime(2003, 11, 2, 0, 59)
- dt2 = datetime(2003, 11, 2, 1, 00)
- fold = [0, 1]
-
- dts = (tz.enfold(dt.replace(tzinfo=tzc), fold=f)
- for dt, f in zip((dt1, dt2), fold))
-
- for value, dt in zip(values, dts):
- self.assertEqual(func(dt), value)
-
- def _test_multi_zones(self, tzstrs, tzids, func, values, start):
- tzic = tz.tzical(StringIO('\n'.join(tzstrs)))
- for tzid, vals in zip(tzids, values):
- tzc = tzic.get(tzid)
-
- self._test_us_zone(tzc, func, vals, start)
-
- def _prepare_EST(self):
- tz_str = self._gettz_str('America/New_York')
- return tz.tzical(StringIO(tz_str)).get()
-
- def _testEST(self, start, test_type, tzc=None):
- if tzc is None:
- tzc = self._prepare_EST()
-
- argdict = {
- 'name': (datetime.tzname, ('EST', 'EDT')),
- 'offset': (datetime.utcoffset, (timedelta(hours=-5),
- timedelta(hours=-4))),
- 'dst': (datetime.dst, (timedelta(hours=0),
- timedelta(hours=1)))
- }
-
- func, values = argdict[test_type]
-
- if not start:
- values = reversed(values)
-
- self._test_us_zone(tzc, func, values, start=start)
-
- def testESTStartName(self):
- self._testEST(start=True, test_type='name')
-
- def testESTEndName(self):
- self._testEST(start=False, test_type='name')
-
- def testESTStartOffset(self):
- self._testEST(start=True, test_type='offset')
-
- def testESTEndOffset(self):
- self._testEST(start=False, test_type='offset')
-
- def testESTStartDST(self):
- self._testEST(start=True, test_type='dst')
-
- def testESTEndDST(self):
- self._testEST(start=False, test_type='dst')
-
- def testESTValueDatetime(self):
- # Violating one-test-per-test rule because we're not set up to do
- # parameterized tests and the manual proliferation is getting a bit
- # out of hand.
- tz_str = self._tzstr_dtstart_with_params('America/New_York',
- 'VALUE=DATE-TIME')
-
- tzc = tz.tzical(StringIO(tz_str)).get()
-
- for start in (True, False):
- for test_type in ('name', 'offset', 'dst'):
- self._testEST(start=start, test_type=test_type, tzc=tzc)
-
- def _testMultizone(self, start, test_type):
- tzstrs = (self._gettz_str('America/New_York'),
- self._gettz_str('America/Los_Angeles'))
- tzids = ('US-Eastern', 'US-Pacific')
-
- argdict = {
- 'name': (datetime.tzname, (('EST', 'EDT'),
- ('PST', 'PDT'))),
- 'offset': (datetime.utcoffset, ((timedelta(hours=-5),
- timedelta(hours=-4)),
- (timedelta(hours=-8),
- timedelta(hours=-7)))),
- 'dst': (datetime.dst, ((timedelta(hours=0),
- timedelta(hours=1)),
- (timedelta(hours=0),
- timedelta(hours=1))))
- }
-
- func, values = argdict[test_type]
-
- if not start:
- values = map(reversed, values)
-
- self._test_multi_zones(tzstrs, tzids, func, values, start)
-
- def testMultiZoneStartName(self):
- self._testMultizone(start=True, test_type='name')
-
- def testMultiZoneEndName(self):
- self._testMultizone(start=False, test_type='name')
-
- def testMultiZoneStartOffset(self):
- self._testMultizone(start=True, test_type='offset')
-
- def testMultiZoneEndOffset(self):
- self._testMultizone(start=False, test_type='offset')
-
- def testMultiZoneStartDST(self):
- self._testMultizone(start=True, test_type='dst')
-
- def testMultiZoneEndDST(self):
- self._testMultizone(start=False, test_type='dst')
-
- def testMultiZoneKeys(self):
- est_str = self._gettz_str('America/New_York')
- pst_str = self._gettz_str('America/Los_Angeles')
- tzic = tz.tzical(StringIO('\n'.join((est_str, pst_str))))
-
- # Sort keys because they are in a random order, being dictionary keys
- keys = sorted(tzic.keys())
-
- self.assertEqual(keys, ['US-Eastern', 'US-Pacific'])
-
- # Test error conditions
- def testEmptyString(self):
- with self.assertRaises(ValueError):
- tz.tzical(StringIO(""))
-
- def testMultiZoneGet(self):
- tzic = tz.tzical(StringIO(TZICAL_EST5EDT + TZICAL_PST8PDT))
-
- with self.assertRaises(ValueError):
- tzic.get()
-
- def testDtstartDate(self):
- tz_str = self._tzstr_dtstart_with_params('America/New_York',
- 'VALUE=DATE')
- with self.assertRaises(ValueError):
- tz.tzical(StringIO(tz_str))
-
- def testDtstartTzid(self):
- tz_str = self._tzstr_dtstart_with_params('America/New_York',
- 'TZID=UTC')
- with self.assertRaises(ValueError):
- tz.tzical(StringIO(tz_str))
-
- def testDtstartBadParam(self):
- tz_str = self._tzstr_dtstart_with_params('America/New_York',
- 'FOO=BAR')
- with self.assertRaises(ValueError):
- tz.tzical(StringIO(tz_str))
-
- # Test Parsing
- def testGap(self):
- tzic = tz.tzical(StringIO('\n'.join((TZICAL_EST5EDT, TZICAL_PST8PDT))))
-
- keys = sorted(tzic.keys())
- self.assertEqual(keys, ['US-Eastern', 'US-Pacific'])
-
-
-class TZTest(unittest.TestCase):
- def testFileStart1(self):
- tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
- self.assertEqual(datetime(2003, 4, 6, 1, 59, tzinfo=tzc).tzname(), "EST")
- self.assertEqual(datetime(2003, 4, 6, 2, 00, tzinfo=tzc).tzname(), "EDT")
-
- def testFileEnd1(self):
- tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
- self.assertEqual(datetime(2003, 10, 26, 0, 59, tzinfo=tzc).tzname(),
- "EDT")
- end_est = tz.enfold(datetime(2003, 10, 26, 1, 00, tzinfo=tzc))
- self.assertEqual(end_est.tzname(), "EST")
-
- def testFileLastTransition(self):
- # After the last transition, it goes to standard time in perpetuity
- tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
- self.assertEqual(datetime(2037, 10, 25, 0, 59, tzinfo=tzc).tzname(),
- "EDT")
-
- last_date = tz.enfold(datetime(2037, 10, 25, 1, 00, tzinfo=tzc), fold=1)
- self.assertEqual(last_date.tzname(),
- "EST")
-
- self.assertEqual(datetime(2038, 5, 25, 12, 0, tzinfo=tzc).tzname(),
- "EST")
-
- def testInvalidFile(self):
- # Should throw a ValueError if an invalid file is passed
- with self.assertRaises(ValueError):
- tz.tzfile(BytesIO(b'BadFile'))
-
- def testFilestreamWithNameRepr(self):
- # If fileobj is a filestream with a "name" attribute this name should
- # be reflected in the tz object's repr
- fileobj = BytesIO(base64.b64decode(TZFILE_EST5EDT))
- fileobj.name = 'foo'
- tzc = tz.tzfile(fileobj)
- self.assertEqual(repr(tzc), 'tzfile(' + repr('foo') + ')')
-
- def testLeapCountDecodesProperly(self):
- # This timezone has leapcnt, and failed to decode until
- # Eugene Oden notified about the issue.
-
- # As leap information is currently unused (and unstored) by tzfile() we
- # can only indirectly test this: Take advantage of tzfile() not closing
- # the input file if handed in as an opened file and assert that the
- # full file content has been read by tzfile(). Note: For this test to
- # work NEW_YORK must be in TZif version 1 format i.e. no more data
- # after TZif v1 header + data has been read
- fileobj = BytesIO(base64.b64decode(NEW_YORK))
- tz.tzfile(fileobj)
- # we expect no remaining file content now, i.e. zero-length; if there's
- # still data we haven't read the file format correctly
- remaining_tzfile_content = fileobj.read()
- self.assertEqual(len(remaining_tzfile_content), 0)
-
- def testIsStd(self):
- # NEW_YORK tzfile contains this isstd information:
- isstd_expected = (0, 0, 0, 1)
- tzc = tz.tzfile(BytesIO(base64.b64decode(NEW_YORK)))
- # gather the actual information as parsed by the tzfile class
- isstd = []
- for ttinfo in tzc._ttinfo_list:
- # ttinfo objects contain boolean values
- isstd.append(int(ttinfo.isstd))
- # ttinfo list may contain more entries than isstd file content
- isstd = tuple(isstd[:len(isstd_expected)])
- self.assertEqual(
- isstd_expected, isstd,
- "isstd UTC/local indicators parsed: %s != tzfile contents: %s"
- % (isstd, isstd_expected))
-
- def testGMTHasNoDaylight(self):
- # tz.tzstr("GMT+2") improperly considered daylight saving time.
- # Issue reported by Lennart Regebro.
- dt = datetime(2007, 8, 6, 4, 10)
- self.assertEqual(tz.gettz("GMT+2").dst(dt), timedelta(0))
-
- def testGMTOffset(self):
- # GMT and UTC offsets have inverted signal when compared to the
- # usual TZ variable handling.
+@pytest.mark.parametrize('tz_str,expected', [
+ # From https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ ('', tz.tzrange(None)), # TODO: Should change this so tz.tzrange('') works
+ ('EST+5EDT,M3.2.0/2,M11.1.0/12',
+ tz.tzrange('EST', -18000, 'EDT', -14400,
+ start=relativedelta(month=3, day=1, weekday=SU(2), hours=2),
+ end=relativedelta(month=11, day=1, weekday=SU(1), hours=11))),
+ ('WART4WARST,J1/0,J365/25', # This is DST all year, Western Argentina Summer Time
+ tz.tzrange('WART', timedelta(hours=-4), 'WARST',
+ start=relativedelta(month=1, day=1, hours=0),
+ end=relativedelta(month=12, day=31, days=1))),
+ ('IST-2IDT,M3.4.4/26,M10.5.0', # Israel Standard / Daylight Time
+ tz.tzrange('IST', timedelta(hours=2), 'IDT',
+ start=relativedelta(month=3, day=1, weekday=TH(4), days=1, hours=2),
+ end=relativedelta(month=10, day=31, weekday=SU(-1), hours=1))),
+ ('WGT3WGST,M3.5.0/2,M10.5.0/1',
+ tz.tzrange('WGT', timedelta(hours=-3), 'WGST',
+ start=relativedelta(month=3, day=31, weekday=SU(-1), hours=2),
+ end=relativedelta(month=10, day=31, weekday=SU(-1), hours=0))),
+
+ # Different offset specifications
+ ('WGT0300WGST',
+ tz.tzrange('WGT', timedelta(hours=-3), 'WGST')),
+ ('WGT03:00WGST',
+ tz.tzrange('WGT', timedelta(hours=-3), 'WGST')),
+ ('AEST-1100AEDT',
+ tz.tzrange('AEST', timedelta(hours=11), 'AEDT')),
+ ('AEST-11:00AEDT',
+ tz.tzrange('AEST', timedelta(hours=11), 'AEDT')),
+
+ # Different time formats
+ ('EST5EDT,M3.2.0/4:00,M11.1.0/3:00',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
+ end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
+ ('EST5EDT,M3.2.0/04:00,M11.1.0/03:00',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
+ end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
+ ('EST5EDT,M3.2.0/0400,M11.1.0/0300',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(month=3, day=1, weekday=SU(2), hours=4),
+ end=relativedelta(month=11, day=1, weekday=SU(1), hours=2))),
+])
+def test_valid_GNU_tzstr(tz_str, expected):
+ tzi = tz.tzstr(tz_str)
+
+ assert tzi == expected
+
+
+@pytest.mark.tzstr
+@pytest.mark.parametrize('tz_str, expected', [
+ ('EST5EDT,5,4,0,7200,11,3,0,7200',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(month=5, day=1, weekday=SU(+4), hours=+2),
+ end=relativedelta(month=11, day=1, weekday=SU(+3), hours=+1))),
+ ('EST5EDT,5,-4,0,7200,11,3,0,7200',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(hours=+2, month=5, day=31, weekday=SU(-4)),
+ end=relativedelta(hours=+1, month=11, day=1, weekday=SU(+3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200,3600',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200,3600',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200,-3600',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT', timedelta(hours=-6),
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=+3, month=11, day=31, weekday=SU(-3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200,+7200',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT', timedelta(hours=-3),
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=0, month=11, day=31, weekday=SU(-3)))),
+ ('EST5EDT,5,4,0,7200,11,-3,0,7200,+3600',
+ tz.tzrange('EST', timedelta(hours=-5), 'EDT',
+ start=relativedelta(hours=+2, month=5, day=1, weekday=SU(+4)),
+ end=relativedelta(hours=+1, month=11, day=31, weekday=SU(-3)))),
+])
+def test_valid_dateutil_format(tz_str, expected):
+ # This tests the dateutil-specific format that is used widely in the tests
+ # and examples. It is unclear where this format originated from.
+ with pytest.warns(tz.DeprecatedTzFormatWarning):
+ tzi = tz.tzstr.instance(tz_str)
+
+ assert tzi == expected
+
+
+@pytest.mark.tzstr
+@pytest.mark.parametrize('tz_str', [
+ 'hdfiughdfuig,dfughdfuigpu87ñ::',
+ ',dfughdfuigpu87ñ::',
+ '-1:WART4WARST,J1,J365/25',
+ 'WART4WARST,J1,J365/-25',
+ 'IST-2IDT,M3.4.-1/26,M10.5.0',
+ 'IST-2IDT,M3,2000,1/26,M10,5,0'
+])
+def test_invalid_GNU_tzstr(tz_str):
+ with pytest.raises(ValueError):
+ tz.tzstr(tz_str)
+
+
+# Different representations of the same default rule set
+DEFAULT_TZSTR_RULES_EQUIV_2003 = [
+ 'EST5EDT',
+ 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00',
+ 'EST5EDT4,95/02:00:00,298/02:00',
+ 'EST5EDT4,J96/02:00:00,J299/02:00',
+ 'EST5EDT4,J96/02:00:00,J299/02'
+]
+
+
+@pytest.mark.tzstr
+@pytest.mark.parametrize('tz_str', DEFAULT_TZSTR_RULES_EQUIV_2003)
+def test_tzstr_default_start(tz_str):
+ tzi = tz.tzstr(tz_str)
+ dt_std = datetime(2003, 4, 6, 1, 59, tzinfo=tzi)
+ dt_dst = datetime(2003, 4, 6, 2, 00, tzinfo=tzi)
+
+ assert get_timezone_tuple(dt_std) == EST_TUPLE
+ assert get_timezone_tuple(dt_dst) == EDT_TUPLE
+
+
+@pytest.mark.tzstr
+@pytest.mark.parametrize('tz_str', DEFAULT_TZSTR_RULES_EQUIV_2003)
+def test_tzstr_default_end(tz_str):
+ tzi = tz.tzstr(tz_str)
+ dt_dst = datetime(2003, 10, 26, 0, 59, tzinfo=tzi)
+ dt_dst_ambig = datetime(2003, 10, 26, 1, 00, tzinfo=tzi)
+ dt_std_ambig = tz.enfold(dt_dst_ambig, fold=1)
+ dt_std = datetime(2003, 10, 26, 2, 00, tzinfo=tzi)
+
+ assert get_timezone_tuple(dt_dst) == EDT_TUPLE
+ assert get_timezone_tuple(dt_dst_ambig) == EDT_TUPLE
+ assert get_timezone_tuple(dt_std_ambig) == EST_TUPLE
+ assert get_timezone_tuple(dt_std) == EST_TUPLE
+
+
+@pytest.mark.tzstr
+@pytest.mark.parametrize('tzstr_1', ['EST5EDT',
+ 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00'])
+@pytest.mark.parametrize('tzstr_2', ['EST5EDT',
+ 'EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00'])
+def test_tzstr_default_cmp(tzstr_1, tzstr_2):
+ tz1 = tz.tzstr(tzstr_1)
+ tz2 = tz.tzstr(tzstr_2)
+
+ assert tz1 == tz2
+
+class TZICalTest(unittest.TestCase, TzFoldMixin):
+ def _gettz_str_tuple(self, tzname):
+ TZ_EST = (
+ 'BEGIN:VTIMEZONE',
+ 'TZID:US-Eastern',
+ 'BEGIN:STANDARD',
+ 'DTSTART:19971029T020000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=11',
+ 'TZOFFSETFROM:-0400',
+ 'TZOFFSETTO:-0500',
+ 'TZNAME:EST',
+ 'END:STANDARD',
+ 'BEGIN:DAYLIGHT',
+ 'DTSTART:19980301T020000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+2SU;BYMONTH=03',
+ 'TZOFFSETFROM:-0500',
+ 'TZOFFSETTO:-0400',
+ 'TZNAME:EDT',
+ 'END:DAYLIGHT',
+ 'END:VTIMEZONE'
+ )
+
+ TZ_PST = (
+ 'BEGIN:VTIMEZONE',
+ 'TZID:US-Pacific',
+ 'BEGIN:STANDARD',
+ 'DTSTART:19971029T020000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=11',
+ 'TZOFFSETFROM:-0700',
+ 'TZOFFSETTO:-0800',
+ 'TZNAME:PST',
+ 'END:STANDARD',
+ 'BEGIN:DAYLIGHT',
+ 'DTSTART:19980301T020000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+2SU;BYMONTH=03',
+ 'TZOFFSETFROM:-0800',
+ 'TZOFFSETTO:-0700',
+ 'TZNAME:PDT',
+ 'END:DAYLIGHT',
+ 'END:VTIMEZONE'
+ )
+
+ TZ_AEST = (
+ 'BEGIN:VTIMEZONE',
+ 'TZID:Australia-Sydney',
+ 'BEGIN:STANDARD',
+ 'DTSTART:19980301T030000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=04',
+ 'TZOFFSETFROM:+1100',
+ 'TZOFFSETTO:+1000',
+ 'TZNAME:AEST',
+ 'END:STANDARD',
+ 'BEGIN:DAYLIGHT',
+ 'DTSTART:19971029T020000',
+ 'RRULE:FREQ=YEARLY;BYDAY=+1SU;BYMONTH=10',
+ 'TZOFFSETFROM:+1000',
+ 'TZOFFSETTO:+1100',
+ 'TZNAME:AEDT',
+ 'END:DAYLIGHT',
+ 'END:VTIMEZONE'
+ )
+
+ TZ_LON = (
+ 'BEGIN:VTIMEZONE',
+ 'TZID:Europe-London',
+ 'BEGIN:STANDARD',
+ 'DTSTART:19810301T030000',
+ 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;BYHOUR=02',
+ 'TZOFFSETFROM:+0100',
+ 'TZOFFSETTO:+0000',
+ 'TZNAME:GMT',
+ 'END:STANDARD',
+ 'BEGIN:DAYLIGHT',
+ 'DTSTART:19961001T030000',
+ 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=03;BYHOUR=01',
+ 'TZOFFSETFROM:+0000',
+ 'TZOFFSETTO:+0100',
+ 'TZNAME:BST',
+ 'END:DAYLIGHT',
+ 'END:VTIMEZONE'
+ )
+
+ tzname_map = {'Australia/Sydney': TZ_AEST,
+ 'America/Toronto': TZ_EST,
+ 'America/New_York': TZ_EST,
+ 'America/Los_Angeles': TZ_PST,
+ 'Europe/London': TZ_LON}
+
+ return tzname_map[tzname]
+
+ def _gettz_str(self, tzname):
+ return '\n'.join(self._gettz_str_tuple(tzname))
+
+ def _tzstr_dtstart_with_params(self, tzname, param_str):
+ # Adds parameters to the DTSTART values of a given tzstr
+ tz_str_tuple = self._gettz_str_tuple(tzname)
+
+ out_tz = []
+ for line in tz_str_tuple:
+ if line.startswith('DTSTART'):
+ name, value = line.split(':', 1)
+ line = name + ';' + param_str + ':' + value
+
+ out_tz.append(line)
+
+ return '\n'.join(out_tz)
+
+ def gettz(self, tzname):
+ tz_str = self._gettz_str(tzname)
+
+ tzc = tz.tzical(StringIO(tz_str)).get()
+
+ return tzc
+
+ def testRepr(self):
+ instr = StringIO(TZICAL_PST8PDT)
+ instr.name = 'StringIO(PST8PDT)'
+ tzc = tz.tzical(instr)
+
+ self.assertEqual(repr(tzc), "tzical(" + repr(instr.name) + ")")
+
+ # Test performance
+ def _test_us_zone(self, tzc, func, values, start):
+ if start:
+ dt1 = datetime(2003, 3, 9, 1, 59)
+ dt2 = datetime(2003, 3, 9, 2, 00)
+ fold = [0, 0]
+ else:
+ dt1 = datetime(2003, 11, 2, 0, 59)
+ dt2 = datetime(2003, 11, 2, 1, 00)
+ fold = [0, 1]
+
+ dts = (tz.enfold(dt.replace(tzinfo=tzc), fold=f)
+ for dt, f in zip((dt1, dt2), fold))
+
+ for value, dt in zip(values, dts):
+ self.assertEqual(func(dt), value)
+
+ def _test_multi_zones(self, tzstrs, tzids, func, values, start):
+ tzic = tz.tzical(StringIO('\n'.join(tzstrs)))
+ for tzid, vals in zip(tzids, values):
+ tzc = tzic.get(tzid)
+
+ self._test_us_zone(tzc, func, vals, start)
+
+ def _prepare_EST(self):
+ tz_str = self._gettz_str('America/New_York')
+ return tz.tzical(StringIO(tz_str)).get()
+
+ def _testEST(self, start, test_type, tzc=None):
+ if tzc is None:
+ tzc = self._prepare_EST()
+
+ argdict = {
+ 'name': (datetime.tzname, ('EST', 'EDT')),
+ 'offset': (datetime.utcoffset, (timedelta(hours=-5),
+ timedelta(hours=-4))),
+ 'dst': (datetime.dst, (timedelta(hours=0),
+ timedelta(hours=1)))
+ }
+
+ func, values = argdict[test_type]
+
+ if not start:
+ values = reversed(values)
+
+ self._test_us_zone(tzc, func, values, start=start)
+
+ def testESTStartName(self):
+ self._testEST(start=True, test_type='name')
+
+ def testESTEndName(self):
+ self._testEST(start=False, test_type='name')
+
+ def testESTStartOffset(self):
+ self._testEST(start=True, test_type='offset')
+
+ def testESTEndOffset(self):
+ self._testEST(start=False, test_type='offset')
+
+ def testESTStartDST(self):
+ self._testEST(start=True, test_type='dst')
+
+ def testESTEndDST(self):
+ self._testEST(start=False, test_type='dst')
+
+ def testESTValueDatetime(self):
+ # Violating one-test-per-test rule because we're not set up to do
+ # parameterized tests and the manual proliferation is getting a bit
+ # out of hand.
+ tz_str = self._tzstr_dtstart_with_params('America/New_York',
+ 'VALUE=DATE-TIME')
+
+ tzc = tz.tzical(StringIO(tz_str)).get()
+
+ for start in (True, False):
+ for test_type in ('name', 'offset', 'dst'):
+ self._testEST(start=start, test_type=test_type, tzc=tzc)
+
+ def _testMultizone(self, start, test_type):
+ tzstrs = (self._gettz_str('America/New_York'),
+ self._gettz_str('America/Los_Angeles'))
+ tzids = ('US-Eastern', 'US-Pacific')
+
+ argdict = {
+ 'name': (datetime.tzname, (('EST', 'EDT'),
+ ('PST', 'PDT'))),
+ 'offset': (datetime.utcoffset, ((timedelta(hours=-5),
+ timedelta(hours=-4)),
+ (timedelta(hours=-8),
+ timedelta(hours=-7)))),
+ 'dst': (datetime.dst, ((timedelta(hours=0),
+ timedelta(hours=1)),
+ (timedelta(hours=0),
+ timedelta(hours=1))))
+ }
+
+ func, values = argdict[test_type]
+
+ if not start:
+ values = map(reversed, values)
+
+ self._test_multi_zones(tzstrs, tzids, func, values, start)
+
+ def testMultiZoneStartName(self):
+ self._testMultizone(start=True, test_type='name')
+
+ def testMultiZoneEndName(self):
+ self._testMultizone(start=False, test_type='name')
+
+ def testMultiZoneStartOffset(self):
+ self._testMultizone(start=True, test_type='offset')
+
+ def testMultiZoneEndOffset(self):
+ self._testMultizone(start=False, test_type='offset')
+
+ def testMultiZoneStartDST(self):
+ self._testMultizone(start=True, test_type='dst')
+
+ def testMultiZoneEndDST(self):
+ self._testMultizone(start=False, test_type='dst')
+
+ def testMultiZoneKeys(self):
+ est_str = self._gettz_str('America/New_York')
+ pst_str = self._gettz_str('America/Los_Angeles')
+ tzic = tz.tzical(StringIO('\n'.join((est_str, pst_str))))
+
+ # Sort keys because they are in a random order, being dictionary keys
+ keys = sorted(tzic.keys())
+
+ self.assertEqual(keys, ['US-Eastern', 'US-Pacific'])
+
+ # Test error conditions
+ def testEmptyString(self):
+ with self.assertRaises(ValueError):
+ tz.tzical(StringIO(""))
+
+ def testMultiZoneGet(self):
+ tzic = tz.tzical(StringIO(TZICAL_EST5EDT + TZICAL_PST8PDT))
+
+ with self.assertRaises(ValueError):
+ tzic.get()
+
+ def testDtstartDate(self):
+ tz_str = self._tzstr_dtstart_with_params('America/New_York',
+ 'VALUE=DATE')
+ with self.assertRaises(ValueError):
+ tz.tzical(StringIO(tz_str))
+
+ def testDtstartTzid(self):
+ tz_str = self._tzstr_dtstart_with_params('America/New_York',
+ 'TZID=UTC')
+ with self.assertRaises(ValueError):
+ tz.tzical(StringIO(tz_str))
+
+ def testDtstartBadParam(self):
+ tz_str = self._tzstr_dtstart_with_params('America/New_York',
+ 'FOO=BAR')
+ with self.assertRaises(ValueError):
+ tz.tzical(StringIO(tz_str))
+
+ # Test Parsing
+ def testGap(self):
+ tzic = tz.tzical(StringIO('\n'.join((TZICAL_EST5EDT, TZICAL_PST8PDT))))
+
+ keys = sorted(tzic.keys())
+ self.assertEqual(keys, ['US-Eastern', 'US-Pacific'])
+
+
+class TZTest(unittest.TestCase):
+ def testFileStart1(self):
+ tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
+ self.assertEqual(datetime(2003, 4, 6, 1, 59, tzinfo=tzc).tzname(), "EST")
+ self.assertEqual(datetime(2003, 4, 6, 2, 00, tzinfo=tzc).tzname(), "EDT")
+
+ def testFileEnd1(self):
+ tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
+ self.assertEqual(datetime(2003, 10, 26, 0, 59, tzinfo=tzc).tzname(),
+ "EDT")
+ end_est = tz.enfold(datetime(2003, 10, 26, 1, 00, tzinfo=tzc))
+ self.assertEqual(end_est.tzname(), "EST")
+
+ def testFileLastTransition(self):
+ # After the last transition, it goes to standard time in perpetuity
+ tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
+ self.assertEqual(datetime(2037, 10, 25, 0, 59, tzinfo=tzc).tzname(),
+ "EDT")
+
+ last_date = tz.enfold(datetime(2037, 10, 25, 1, 00, tzinfo=tzc), fold=1)
+ self.assertEqual(last_date.tzname(),
+ "EST")
+
+ self.assertEqual(datetime(2038, 5, 25, 12, 0, tzinfo=tzc).tzname(),
+ "EST")
+
+ def testInvalidFile(self):
+ # Should throw a ValueError if an invalid file is passed
+ with self.assertRaises(ValueError):
+ tz.tzfile(BytesIO(b'BadFile'))
+
+ def testFilestreamWithNameRepr(self):
+ # If fileobj is a filestream with a "name" attribute this name should
+ # be reflected in the tz object's repr
+ fileobj = BytesIO(base64.b64decode(TZFILE_EST5EDT))
+ fileobj.name = 'foo'
+ tzc = tz.tzfile(fileobj)
+ self.assertEqual(repr(tzc), 'tzfile(' + repr('foo') + ')')
+
+ def testLeapCountDecodesProperly(self):
+ # This timezone has leapcnt, and failed to decode until
+ # Eugene Oden notified about the issue.
+
+ # As leap information is currently unused (and unstored) by tzfile() we
+ # can only indirectly test this: Take advantage of tzfile() not closing
+ # the input file if handed in as an opened file and assert that the
+ # full file content has been read by tzfile(). Note: For this test to
+ # work NEW_YORK must be in TZif version 1 format i.e. no more data
+ # after TZif v1 header + data has been read
+ fileobj = BytesIO(base64.b64decode(NEW_YORK))
+ tz.tzfile(fileobj)
+ # we expect no remaining file content now, i.e. zero-length; if there's
+ # still data we haven't read the file format correctly
+ remaining_tzfile_content = fileobj.read()
+ self.assertEqual(len(remaining_tzfile_content), 0)
+
+ def testIsStd(self):
+ # NEW_YORK tzfile contains this isstd information:
+ isstd_expected = (0, 0, 0, 1)
+ tzc = tz.tzfile(BytesIO(base64.b64decode(NEW_YORK)))
+ # gather the actual information as parsed by the tzfile class
+ isstd = []
+ for ttinfo in tzc._ttinfo_list:
+ # ttinfo objects contain boolean values
+ isstd.append(int(ttinfo.isstd))
+ # ttinfo list may contain more entries than isstd file content
+ isstd = tuple(isstd[:len(isstd_expected)])
+ self.assertEqual(
+ isstd_expected, isstd,
+ "isstd UTC/local indicators parsed: %s != tzfile contents: %s"
+ % (isstd, isstd_expected))
+
+ def testGMTHasNoDaylight(self):
+ # tz.tzstr("GMT+2") improperly considered daylight saving time.
+ # Issue reported by Lennart Regebro.
+ dt = datetime(2007, 8, 6, 4, 10)
+ self.assertEqual(tz.gettz("GMT+2").dst(dt), timedelta(0))
+
+ def testGMTOffset(self):
+ # GMT and UTC offsets have inverted signal when compared to the
+ # usual TZ variable handling.
dt = datetime(2007, 8, 6, 4, 10, tzinfo=tz.UTC)
- self.assertEqual(dt.astimezone(tz=tz.tzstr("GMT+2")),
- datetime(2007, 8, 6, 6, 10, tzinfo=tz.tzstr("GMT+2")))
- self.assertEqual(dt.astimezone(tz=tz.gettz("UTC-2")),
- datetime(2007, 8, 6, 2, 10, tzinfo=tz.tzstr("UTC-2")))
-
+ self.assertEqual(dt.astimezone(tz=tz.tzstr("GMT+2")),
+ datetime(2007, 8, 6, 6, 10, tzinfo=tz.tzstr("GMT+2")))
+ self.assertEqual(dt.astimezone(tz=tz.gettz("UTC-2")),
+ datetime(2007, 8, 6, 2, 10, tzinfo=tz.tzstr("UTC-2")))
+
@unittest.skipIf(IS_WIN, "requires Unix")
- def testTZSetDoesntCorrupt(self):
- # if we start in non-UTC then tzset UTC make sure parse doesn't get
- # confused
- with TZEnvContext('UTC'):
- # this should parse to UTC timezone not the original timezone
- dt = parse('2014-07-20T12:34:56+00:00')
- self.assertEqual(str(dt), '2014-07-20 12:34:56+00:00')
-
-
+ def testTZSetDoesntCorrupt(self):
+ # if we start in non-UTC then tzset UTC make sure parse doesn't get
+ # confused
+ with TZEnvContext('UTC'):
+ # this should parse to UTC timezone not the original timezone
+ dt = parse('2014-07-20T12:34:56+00:00')
+ self.assertEqual(str(dt), '2014-07-20 12:34:56+00:00')
+
+
@pytest.mark.tzfile
@pytest.mark.skipif(not SUPPORTS_SUB_MINUTE_OFFSETS,
reason='Sub-minute offsets not supported')
@@ -2119,570 +2119,570 @@ def test_samoa_transition():
@unittest.skipUnless(IS_WIN, "Requires Windows")
-class TzWinTest(unittest.TestCase, TzWinFoldMixin):
- def setUp(self):
- self.tzclass = tzwin.tzwin
-
- def testTzResLoadName(self):
- # This may not work right on non-US locales.
- tzr = tzwin.tzres()
- self.assertEqual(tzr.load_name(112), "Eastern Standard Time")
-
- def testTzResNameFromString(self):
- tzr = tzwin.tzres()
- self.assertEqual(tzr.name_from_string('@tzres.dll,-221'),
- 'Alaskan Daylight Time')
-
- self.assertEqual(tzr.name_from_string('Samoa Daylight Time'),
- 'Samoa Daylight Time')
-
- with self.assertRaises(ValueError):
- tzr.name_from_string('@tzres.dll,100')
-
- def testIsdstZoneWithNoDaylightSaving(self):
- tz = tzwin.tzwin("UTC")
- dt = parse("2013-03-06 19:08:15")
- self.assertFalse(tz._isdst(dt))
-
- def testOffset(self):
- tz = tzwin.tzwin("Cape Verde Standard Time")
- self.assertEqual(tz.utcoffset(datetime(1995, 5, 21, 12, 9, 13)),
- timedelta(-1, 82800))
-
- def testTzwinName(self):
- # https://github.com/dateutil/dateutil/issues/143
- tw = tz.tzwin('Eastern Standard Time')
-
- # Cover the transitions for at least two years.
- ESTs = 'Eastern Standard Time'
- EDTs = 'Eastern Daylight Time'
- transition_dates = [(datetime(2015, 3, 8, 0, 59), ESTs),
- (datetime(2015, 3, 8, 3, 1), EDTs),
- (datetime(2015, 11, 1, 0, 59), EDTs),
- (datetime(2015, 11, 1, 3, 1), ESTs),
- (datetime(2016, 3, 13, 0, 59), ESTs),
- (datetime(2016, 3, 13, 3, 1), EDTs),
- (datetime(2016, 11, 6, 0, 59), EDTs),
- (datetime(2016, 11, 6, 3, 1), ESTs)]
-
- for t_date, expected in transition_dates:
- self.assertEqual(t_date.replace(tzinfo=tw).tzname(), expected)
-
- def testTzwinRepr(self):
- tw = tz.tzwin('Yakutsk Standard Time')
- self.assertEqual(repr(tw), 'tzwin(' +
- repr('Yakutsk Standard Time') + ')')
-
- def testTzWinEquality(self):
- # https://github.com/dateutil/dateutil/issues/151
- tzwin_names = ('Eastern Standard Time',
- 'West Pacific Standard Time',
- 'Yakutsk Standard Time',
- 'Iran Standard Time',
- 'UTC')
-
- for tzwin_name in tzwin_names:
- # Get two different instances to compare
- tw1 = tz.tzwin(tzwin_name)
- tw2 = tz.tzwin(tzwin_name)
-
- self.assertEqual(tw1, tw2)
-
- def testTzWinInequality(self):
- # https://github.com/dateutil/dateutil/issues/151
- # Note these last two currently differ only in their name.
- tzwin_names = (('Eastern Standard Time', 'Yakutsk Standard Time'),
- ('Greenwich Standard Time', 'GMT Standard Time'),
- ('GMT Standard Time', 'UTC'),
- ('E. South America Standard Time',
- 'Argentina Standard Time'))
-
- for tzwn1, tzwn2 in tzwin_names:
- # Get two different instances to compare
- tw1 = tz.tzwin(tzwn1)
- tw2 = tz.tzwin(tzwn2)
-
- self.assertNotEqual(tw1, tw2)
-
- def testTzWinEqualityInvalid(self):
- # Compare to objects that do not implement comparison with this
- # (should default to False)
+class TzWinTest(unittest.TestCase, TzWinFoldMixin):
+ def setUp(self):
+ self.tzclass = tzwin.tzwin
+
+ def testTzResLoadName(self):
+ # This may not work right on non-US locales.
+ tzr = tzwin.tzres()
+ self.assertEqual(tzr.load_name(112), "Eastern Standard Time")
+
+ def testTzResNameFromString(self):
+ tzr = tzwin.tzres()
+ self.assertEqual(tzr.name_from_string('@tzres.dll,-221'),
+ 'Alaskan Daylight Time')
+
+ self.assertEqual(tzr.name_from_string('Samoa Daylight Time'),
+ 'Samoa Daylight Time')
+
+ with self.assertRaises(ValueError):
+ tzr.name_from_string('@tzres.dll,100')
+
+ def testIsdstZoneWithNoDaylightSaving(self):
+ tz = tzwin.tzwin("UTC")
+ dt = parse("2013-03-06 19:08:15")
+ self.assertFalse(tz._isdst(dt))
+
+ def testOffset(self):
+ tz = tzwin.tzwin("Cape Verde Standard Time")
+ self.assertEqual(tz.utcoffset(datetime(1995, 5, 21, 12, 9, 13)),
+ timedelta(-1, 82800))
+
+ def testTzwinName(self):
+ # https://github.com/dateutil/dateutil/issues/143
+ tw = tz.tzwin('Eastern Standard Time')
+
+ # Cover the transitions for at least two years.
+ ESTs = 'Eastern Standard Time'
+ EDTs = 'Eastern Daylight Time'
+ transition_dates = [(datetime(2015, 3, 8, 0, 59), ESTs),
+ (datetime(2015, 3, 8, 3, 1), EDTs),
+ (datetime(2015, 11, 1, 0, 59), EDTs),
+ (datetime(2015, 11, 1, 3, 1), ESTs),
+ (datetime(2016, 3, 13, 0, 59), ESTs),
+ (datetime(2016, 3, 13, 3, 1), EDTs),
+ (datetime(2016, 11, 6, 0, 59), EDTs),
+ (datetime(2016, 11, 6, 3, 1), ESTs)]
+
+ for t_date, expected in transition_dates:
+ self.assertEqual(t_date.replace(tzinfo=tw).tzname(), expected)
+
+ def testTzwinRepr(self):
+ tw = tz.tzwin('Yakutsk Standard Time')
+ self.assertEqual(repr(tw), 'tzwin(' +
+ repr('Yakutsk Standard Time') + ')')
+
+ def testTzWinEquality(self):
+ # https://github.com/dateutil/dateutil/issues/151
+ tzwin_names = ('Eastern Standard Time',
+ 'West Pacific Standard Time',
+ 'Yakutsk Standard Time',
+ 'Iran Standard Time',
+ 'UTC')
+
+ for tzwin_name in tzwin_names:
+ # Get two different instances to compare
+ tw1 = tz.tzwin(tzwin_name)
+ tw2 = tz.tzwin(tzwin_name)
+
+ self.assertEqual(tw1, tw2)
+
+ def testTzWinInequality(self):
+ # https://github.com/dateutil/dateutil/issues/151
+ # Note these last two currently differ only in their name.
+ tzwin_names = (('Eastern Standard Time', 'Yakutsk Standard Time'),
+ ('Greenwich Standard Time', 'GMT Standard Time'),
+ ('GMT Standard Time', 'UTC'),
+ ('E. South America Standard Time',
+ 'Argentina Standard Time'))
+
+ for tzwn1, tzwn2 in tzwin_names:
+ # Get two different instances to compare
+ tw1 = tz.tzwin(tzwn1)
+ tw2 = tz.tzwin(tzwn2)
+
+ self.assertNotEqual(tw1, tw2)
+
+ def testTzWinEqualityInvalid(self):
+ # Compare to objects that do not implement comparison with this
+ # (should default to False)
UTC = tz.UTC
- EST = tz.tzwin('Eastern Standard Time')
-
- self.assertFalse(EST == UTC)
- self.assertFalse(EST == 1)
- self.assertFalse(UTC == EST)
-
- self.assertTrue(EST != UTC)
- self.assertTrue(EST != 1)
-
- def testTzWinInequalityUnsupported(self):
- # Compare it to an object that is promiscuous about equality, but for
- # which tzwin does not implement an equality operator.
- EST = tz.tzwin('Eastern Standard Time')
- self.assertTrue(EST == ComparesEqual)
- self.assertFalse(EST != ComparesEqual)
-
- def testTzwinTimeOnlyDST(self):
- # For zones with DST, .dst() should return None
- tw_est = tz.tzwin('Eastern Standard Time')
- self.assertIs(dt_time(14, 10, tzinfo=tw_est).dst(), None)
-
- # This zone has no DST, so .dst() can return 0
- tw_sast = tz.tzwin('South Africa Standard Time')
- self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).dst(),
- timedelta(0))
-
- def testTzwinTimeOnlyUTCOffset(self):
- # For zones with DST, .utcoffset() should return None
- tw_est = tz.tzwin('Eastern Standard Time')
- self.assertIs(dt_time(14, 10, tzinfo=tw_est).utcoffset(), None)
-
- # This zone has no DST, so .utcoffset() returns standard offset
- tw_sast = tz.tzwin('South Africa Standard Time')
- self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).utcoffset(),
- timedelta(hours=2))
-
- def testTzwinTimeOnlyTZName(self):
- # For zones with DST, the name defaults to standard time
- tw_est = tz.tzwin('Eastern Standard Time')
- self.assertEqual(dt_time(14, 10, tzinfo=tw_est).tzname(),
- 'Eastern Standard Time')
-
- # For zones with no DST, this should work normally.
- tw_sast = tz.tzwin('South Africa Standard Time')
- self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).tzname(),
- 'South Africa Standard Time')
-
-
+ EST = tz.tzwin('Eastern Standard Time')
+
+ self.assertFalse(EST == UTC)
+ self.assertFalse(EST == 1)
+ self.assertFalse(UTC == EST)
+
+ self.assertTrue(EST != UTC)
+ self.assertTrue(EST != 1)
+
+ def testTzWinInequalityUnsupported(self):
+ # Compare it to an object that is promiscuous about equality, but for
+ # which tzwin does not implement an equality operator.
+ EST = tz.tzwin('Eastern Standard Time')
+ self.assertTrue(EST == ComparesEqual)
+ self.assertFalse(EST != ComparesEqual)
+
+ def testTzwinTimeOnlyDST(self):
+ # For zones with DST, .dst() should return None
+ tw_est = tz.tzwin('Eastern Standard Time')
+ self.assertIs(dt_time(14, 10, tzinfo=tw_est).dst(), None)
+
+ # This zone has no DST, so .dst() can return 0
+ tw_sast = tz.tzwin('South Africa Standard Time')
+ self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).dst(),
+ timedelta(0))
+
+ def testTzwinTimeOnlyUTCOffset(self):
+ # For zones with DST, .utcoffset() should return None
+ tw_est = tz.tzwin('Eastern Standard Time')
+ self.assertIs(dt_time(14, 10, tzinfo=tw_est).utcoffset(), None)
+
+ # This zone has no DST, so .utcoffset() returns standard offset
+ tw_sast = tz.tzwin('South Africa Standard Time')
+ self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).utcoffset(),
+ timedelta(hours=2))
+
+ def testTzwinTimeOnlyTZName(self):
+ # For zones with DST, the name defaults to standard time
+ tw_est = tz.tzwin('Eastern Standard Time')
+ self.assertEqual(dt_time(14, 10, tzinfo=tw_est).tzname(),
+ 'Eastern Standard Time')
+
+ # For zones with no DST, this should work normally.
+ tw_sast = tz.tzwin('South Africa Standard Time')
+ self.assertEqual(dt_time(14, 10, tzinfo=tw_sast).tzname(),
+ 'South Africa Standard Time')
+
+
@unittest.skipUnless(IS_WIN, "Requires Windows")
-class TzWinLocalTest(unittest.TestCase, TzWinFoldMixin):
-
- def setUp(self):
- self.tzclass = tzwin.tzwinlocal
- self.context = TZWinContext
-
- def get_args(self, tzname):
- return ()
-
- def testLocal(self):
- # Not sure how to pin a local time zone, so for now we're just going
- # to run this and make sure it doesn't raise an error
+class TzWinLocalTest(unittest.TestCase, TzWinFoldMixin):
+
+ def setUp(self):
+ self.tzclass = tzwin.tzwinlocal
+ self.context = TZWinContext
+
+ def get_args(self, tzname):
+ return ()
+
+ def testLocal(self):
+ # Not sure how to pin a local time zone, so for now we're just going
+ # to run this and make sure it doesn't raise an error
# See GitHub Issue #135: https://github.com/dateutil/dateutil/issues/135
- datetime.now(tzwin.tzwinlocal())
-
- def testTzwinLocalUTCOffset(self):
- with TZWinContext('Eastern Standard Time'):
- tzwl = tzwin.tzwinlocal()
- self.assertEqual(datetime(2014, 3, 11, tzinfo=tzwl).utcoffset(),
- timedelta(hours=-4))
-
- def testTzwinLocalName(self):
- # https://github.com/dateutil/dateutil/issues/143
- ESTs = 'Eastern Standard Time'
- EDTs = 'Eastern Daylight Time'
- transition_dates = [(datetime(2015, 3, 8, 0, 59), ESTs),
- (datetime(2015, 3, 8, 3, 1), EDTs),
- (datetime(2015, 11, 1, 0, 59), EDTs),
- (datetime(2015, 11, 1, 3, 1), ESTs),
- (datetime(2016, 3, 13, 0, 59), ESTs),
- (datetime(2016, 3, 13, 3, 1), EDTs),
- (datetime(2016, 11, 6, 0, 59), EDTs),
- (datetime(2016, 11, 6, 3, 1), ESTs)]
-
- with TZWinContext('Eastern Standard Time'):
- tw = tz.tzwinlocal()
-
- for t_date, expected in transition_dates:
- self.assertEqual(t_date.replace(tzinfo=tw).tzname(), expected)
-
- def testTzWinLocalRepr(self):
- tw = tz.tzwinlocal()
- self.assertEqual(repr(tw), 'tzwinlocal()')
-
- def testTzwinLocalRepr(self):
- # https://github.com/dateutil/dateutil/issues/143
- with TZWinContext('Eastern Standard Time'):
- tw = tz.tzwinlocal()
-
- self.assertEqual(str(tw), 'tzwinlocal(' +
- repr('Eastern Standard Time') + ')')
-
- with TZWinContext('Pacific Standard Time'):
- tw = tz.tzwinlocal()
-
- self.assertEqual(str(tw), 'tzwinlocal(' +
- repr('Pacific Standard Time') + ')')
-
- def testTzwinLocalEquality(self):
- tw_est = tz.tzwin('Eastern Standard Time')
- tw_pst = tz.tzwin('Pacific Standard Time')
-
- with TZWinContext('Eastern Standard Time'):
- twl1 = tz.tzwinlocal()
- twl2 = tz.tzwinlocal()
-
- self.assertEqual(twl1, twl2)
- self.assertEqual(twl1, tw_est)
- self.assertNotEqual(twl1, tw_pst)
-
- with TZWinContext('Pacific Standard Time'):
- twl1 = tz.tzwinlocal()
- twl2 = tz.tzwinlocal()
- tw = tz.tzwin('Pacific Standard Time')
-
- self.assertEqual(twl1, twl2)
- self.assertEqual(twl1, tw)
- self.assertEqual(twl1, tw_pst)
- self.assertNotEqual(twl1, tw_est)
-
- def testTzwinLocalTimeOnlyDST(self):
- # For zones with DST, .dst() should return None
- with TZWinContext('Eastern Standard Time'):
- twl = tz.tzwinlocal()
- self.assertIs(dt_time(14, 10, tzinfo=twl).dst(), None)
-
- # This zone has no DST, so .dst() can return 0
- with TZWinContext('South Africa Standard Time'):
- twl = tz.tzwinlocal()
- self.assertEqual(dt_time(14, 10, tzinfo=twl).dst(), timedelta(0))
-
- def testTzwinLocalTimeOnlyUTCOffset(self):
- # For zones with DST, .utcoffset() should return None
- with TZWinContext('Eastern Standard Time'):
- twl = tz.tzwinlocal()
- self.assertIs(dt_time(14, 10, tzinfo=twl).utcoffset(), None)
-
- # This zone has no DST, so .utcoffset() returns standard offset
- with TZWinContext('South Africa Standard Time'):
- twl = tz.tzwinlocal()
- self.assertEqual(dt_time(14, 10, tzinfo=twl).utcoffset(),
- timedelta(hours=2))
-
- def testTzwinLocalTimeOnlyTZName(self):
- # For zones with DST, the name defaults to standard time
- with TZWinContext('Eastern Standard Time'):
- twl = tz.tzwinlocal()
- self.assertEqual(dt_time(14, 10, tzinfo=twl).tzname(),
- 'Eastern Standard Time')
-
- # For zones with no DST, this should work normally.
- with TZWinContext('South Africa Standard Time'):
- twl = tz.tzwinlocal()
- self.assertEqual(dt_time(14, 10, tzinfo=twl).tzname(),
- 'South Africa Standard Time')
-
-
-class TzPickleTest(PicklableMixin, unittest.TestCase):
- _asfile = False
-
- def setUp(self):
- self.assertPicklable = partial(self.assertPicklable,
- asfile=self._asfile)
-
- def testPickleTzUTC(self):
- self.assertPicklable(tz.tzutc(), singleton=True)
-
- def testPickleTzOffsetZero(self):
- self.assertPicklable(tz.tzoffset('UTC', 0), singleton=True)
-
- def testPickleTzOffsetPos(self):
- self.assertPicklable(tz.tzoffset('UTC+1', 3600), singleton=True)
-
- def testPickleTzOffsetNeg(self):
- self.assertPicklable(tz.tzoffset('UTC-1', -3600), singleton=True)
-
- @pytest.mark.tzlocal
- def testPickleTzLocal(self):
- self.assertPicklable(tz.tzlocal())
-
- def testPickleTzFileEST5EDT(self):
- tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
- self.assertPicklable(tzc)
-
- def testPickleTzFileEurope_Helsinki(self):
- tzc = tz.tzfile(BytesIO(base64.b64decode(EUROPE_HELSINKI)))
- self.assertPicklable(tzc)
-
- def testPickleTzFileNew_York(self):
- tzc = tz.tzfile(BytesIO(base64.b64decode(NEW_YORK)))
- self.assertPicklable(tzc)
-
- @unittest.skip("Known failure")
- def testPickleTzICal(self):
- tzc = tz.tzical(StringIO(TZICAL_EST5EDT)).get()
- self.assertPicklable(tzc)
-
- def testPickleTzGettz(self):
- self.assertPicklable(tz.gettz('America/New_York'))
-
- def testPickleZoneFileGettz(self):
- zoneinfo_file = zoneinfo.get_zonefile_instance()
- tzi = zoneinfo_file.get('America/New_York')
- self.assertIsNot(tzi, None)
- self.assertPicklable(tzi)
-
-
-class TzPickleFileTest(TzPickleTest):
- """ Run all the TzPickleTest tests, using a temporary file """
- _asfile = True
-
-
-class DatetimeAmbiguousTest(unittest.TestCase):
- """ Test the datetime_exists / datetime_ambiguous functions """
-
- def testNoTzSpecified(self):
- with self.assertRaises(ValueError):
- tz.datetime_ambiguous(datetime(2016, 4, 1, 2, 9))
-
- def _get_no_support_tzinfo_class(self, dt_start, dt_end, dst_only=False):
- # Generates a class of tzinfo with no support for is_ambiguous
- # where dates between dt_start and dt_end are ambiguous.
-
- class FoldingTzInfo(tzinfo):
- def utcoffset(self, dt):
- if not dst_only:
- dt_n = dt.replace(tzinfo=None)
-
- if dt_start <= dt_n < dt_end and getattr(dt_n, 'fold', 0):
- return timedelta(hours=-1)
-
- return timedelta(hours=0)
-
- def dst(self, dt):
- dt_n = dt.replace(tzinfo=None)
-
- if dt_start <= dt_n < dt_end and getattr(dt_n, 'fold', 0):
- return timedelta(hours=1)
- else:
- return timedelta(0)
-
- return FoldingTzInfo
-
- def _get_no_support_tzinfo(self, dt_start, dt_end, dst_only=False):
- return self._get_no_support_tzinfo_class(dt_start, dt_end, dst_only)()
-
- def testNoSupportAmbiguityFoldNaive(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
- tz=tzi))
-
- def testNoSupportAmbiguityFoldAware(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30,
- tzinfo=tzi)))
-
- def testNoSupportAmbiguityUnambiguousNaive(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
- tz=tzi))
-
- def testNoSupportAmbiguityUnambiguousAware(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30,
- tzinfo=tzi)))
-
- def testNoSupportAmbiguityFoldDSTOnly(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end, dst_only=True)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
- tz=tzi))
-
- def testNoSupportAmbiguityUnambiguousDSTOnly(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_no_support_tzinfo(dt_start, dt_end, dst_only=True)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
- tz=tzi))
-
- def testSupportAmbiguityFoldNaive(self):
- tzi = tz.gettz('US/Eastern')
-
- dt = datetime(2011, 11, 6, 1, 30)
-
- self.assertTrue(tz.datetime_ambiguous(dt, tz=tzi))
-
- def testSupportAmbiguityFoldAware(self):
- tzi = tz.gettz('US/Eastern')
-
- dt = datetime(2011, 11, 6, 1, 30, tzinfo=tzi)
-
- self.assertTrue(tz.datetime_ambiguous(dt))
-
- def testSupportAmbiguityUnambiguousAware(self):
- tzi = tz.gettz('US/Eastern')
-
- dt = datetime(2011, 11, 6, 4, 30)
-
- self.assertFalse(tz.datetime_ambiguous(dt, tz=tzi))
-
- def testSupportAmbiguityUnambiguousNaive(self):
- tzi = tz.gettz('US/Eastern')
-
- dt = datetime(2011, 11, 6, 4, 30, tzinfo=tzi)
-
- self.assertFalse(tz.datetime_ambiguous(dt))
-
- def _get_ambig_error_tzinfo(self, dt_start, dt_end, dst_only=False):
- cTzInfo = self._get_no_support_tzinfo_class(dt_start, dt_end, dst_only)
-
- # Takes the wrong number of arguments and raises an error anyway.
- class FoldTzInfoRaises(cTzInfo):
- def is_ambiguous(self, dt, other_arg):
- raise NotImplementedError('This is not implemented')
-
- return FoldTzInfoRaises()
-
- def testIncompatibleAmbiguityFoldNaive(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
- tz=tzi))
-
- def testIncompatibleAmbiguityFoldAware(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30,
- tzinfo=tzi)))
-
- def testIncompatibleAmbiguityUnambiguousNaive(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
- tz=tzi))
-
- def testIncompatibleAmbiguityUnambiguousAware(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30,
- tzinfo=tzi)))
-
- def testIncompatibleAmbiguityFoldDSTOnly(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end, dst_only=True)
-
- self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
- tz=tzi))
-
- def testIncompatibleAmbiguityUnambiguousDSTOnly(self):
- dt_start = datetime(2018, 9, 1, 1, 0)
- dt_end = datetime(2018, 9, 1, 2, 0)
-
- tzi = self._get_ambig_error_tzinfo(dt_start, dt_end, dst_only=True)
-
- self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
- tz=tzi))
-
- def testSpecifiedTzOverridesAttached(self):
- # If a tz is specified, the datetime will be treated as naive.
-
- # This is not ambiguous in the local zone
- dt = datetime(2011, 11, 6, 1, 30, tzinfo=tz.gettz('Australia/Sydney'))
-
- self.assertFalse(tz.datetime_ambiguous(dt))
-
- tzi = tz.gettz('US/Eastern')
- self.assertTrue(tz.datetime_ambiguous(dt, tz=tzi))
-
-
-class DatetimeExistsTest(unittest.TestCase):
- def testNoTzSpecified(self):
- with self.assertRaises(ValueError):
- tz.datetime_exists(datetime(2016, 4, 1, 2, 9))
-
- def testInGapNaive(self):
- tzi = tz.gettz('Australia/Sydney')
-
- dt = datetime(2012, 10, 7, 2, 30)
-
- self.assertFalse(tz.datetime_exists(dt, tz=tzi))
-
- def testInGapAware(self):
- tzi = tz.gettz('Australia/Sydney')
-
- dt = datetime(2012, 10, 7, 2, 30, tzinfo=tzi)
-
- self.assertFalse(tz.datetime_exists(dt))
-
- def testExistsNaive(self):
- tzi = tz.gettz('Australia/Sydney')
-
- dt = datetime(2012, 10, 7, 10, 30)
-
- self.assertTrue(tz.datetime_exists(dt, tz=tzi))
-
- def testExistsAware(self):
- tzi = tz.gettz('Australia/Sydney')
-
- dt = datetime(2012, 10, 7, 10, 30, tzinfo=tzi)
-
- self.assertTrue(tz.datetime_exists(dt))
-
- def testSpecifiedTzOverridesAttached(self):
- EST = tz.gettz('US/Eastern')
- AEST = tz.gettz('Australia/Sydney')
-
- dt = datetime(2012, 10, 7, 2, 30, tzinfo=EST) # This time exists
-
- self.assertFalse(tz.datetime_exists(dt, tz=AEST))
-
-
+ datetime.now(tzwin.tzwinlocal())
+
+ def testTzwinLocalUTCOffset(self):
+ with TZWinContext('Eastern Standard Time'):
+ tzwl = tzwin.tzwinlocal()
+ self.assertEqual(datetime(2014, 3, 11, tzinfo=tzwl).utcoffset(),
+ timedelta(hours=-4))
+
+ def testTzwinLocalName(self):
+ # https://github.com/dateutil/dateutil/issues/143
+ ESTs = 'Eastern Standard Time'
+ EDTs = 'Eastern Daylight Time'
+ transition_dates = [(datetime(2015, 3, 8, 0, 59), ESTs),
+ (datetime(2015, 3, 8, 3, 1), EDTs),
+ (datetime(2015, 11, 1, 0, 59), EDTs),
+ (datetime(2015, 11, 1, 3, 1), ESTs),
+ (datetime(2016, 3, 13, 0, 59), ESTs),
+ (datetime(2016, 3, 13, 3, 1), EDTs),
+ (datetime(2016, 11, 6, 0, 59), EDTs),
+ (datetime(2016, 11, 6, 3, 1), ESTs)]
+
+ with TZWinContext('Eastern Standard Time'):
+ tw = tz.tzwinlocal()
+
+ for t_date, expected in transition_dates:
+ self.assertEqual(t_date.replace(tzinfo=tw).tzname(), expected)
+
+ def testTzWinLocalRepr(self):
+ tw = tz.tzwinlocal()
+ self.assertEqual(repr(tw), 'tzwinlocal()')
+
+ def testTzwinLocalRepr(self):
+ # https://github.com/dateutil/dateutil/issues/143
+ with TZWinContext('Eastern Standard Time'):
+ tw = tz.tzwinlocal()
+
+ self.assertEqual(str(tw), 'tzwinlocal(' +
+ repr('Eastern Standard Time') + ')')
+
+ with TZWinContext('Pacific Standard Time'):
+ tw = tz.tzwinlocal()
+
+ self.assertEqual(str(tw), 'tzwinlocal(' +
+ repr('Pacific Standard Time') + ')')
+
+ def testTzwinLocalEquality(self):
+ tw_est = tz.tzwin('Eastern Standard Time')
+ tw_pst = tz.tzwin('Pacific Standard Time')
+
+ with TZWinContext('Eastern Standard Time'):
+ twl1 = tz.tzwinlocal()
+ twl2 = tz.tzwinlocal()
+
+ self.assertEqual(twl1, twl2)
+ self.assertEqual(twl1, tw_est)
+ self.assertNotEqual(twl1, tw_pst)
+
+ with TZWinContext('Pacific Standard Time'):
+ twl1 = tz.tzwinlocal()
+ twl2 = tz.tzwinlocal()
+ tw = tz.tzwin('Pacific Standard Time')
+
+ self.assertEqual(twl1, twl2)
+ self.assertEqual(twl1, tw)
+ self.assertEqual(twl1, tw_pst)
+ self.assertNotEqual(twl1, tw_est)
+
+ def testTzwinLocalTimeOnlyDST(self):
+ # For zones with DST, .dst() should return None
+ with TZWinContext('Eastern Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertIs(dt_time(14, 10, tzinfo=twl).dst(), None)
+
+ # This zone has no DST, so .dst() can return 0
+ with TZWinContext('South Africa Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertEqual(dt_time(14, 10, tzinfo=twl).dst(), timedelta(0))
+
+ def testTzwinLocalTimeOnlyUTCOffset(self):
+ # For zones with DST, .utcoffset() should return None
+ with TZWinContext('Eastern Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertIs(dt_time(14, 10, tzinfo=twl).utcoffset(), None)
+
+ # This zone has no DST, so .utcoffset() returns standard offset
+ with TZWinContext('South Africa Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertEqual(dt_time(14, 10, tzinfo=twl).utcoffset(),
+ timedelta(hours=2))
+
+ def testTzwinLocalTimeOnlyTZName(self):
+ # For zones with DST, the name defaults to standard time
+ with TZWinContext('Eastern Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertEqual(dt_time(14, 10, tzinfo=twl).tzname(),
+ 'Eastern Standard Time')
+
+ # For zones with no DST, this should work normally.
+ with TZWinContext('South Africa Standard Time'):
+ twl = tz.tzwinlocal()
+ self.assertEqual(dt_time(14, 10, tzinfo=twl).tzname(),
+ 'South Africa Standard Time')
+
+
+class TzPickleTest(PicklableMixin, unittest.TestCase):
+ _asfile = False
+
+ def setUp(self):
+ self.assertPicklable = partial(self.assertPicklable,
+ asfile=self._asfile)
+
+ def testPickleTzUTC(self):
+ self.assertPicklable(tz.tzutc(), singleton=True)
+
+ def testPickleTzOffsetZero(self):
+ self.assertPicklable(tz.tzoffset('UTC', 0), singleton=True)
+
+ def testPickleTzOffsetPos(self):
+ self.assertPicklable(tz.tzoffset('UTC+1', 3600), singleton=True)
+
+ def testPickleTzOffsetNeg(self):
+ self.assertPicklable(tz.tzoffset('UTC-1', -3600), singleton=True)
+
+ @pytest.mark.tzlocal
+ def testPickleTzLocal(self):
+ self.assertPicklable(tz.tzlocal())
+
+ def testPickleTzFileEST5EDT(self):
+ tzc = tz.tzfile(BytesIO(base64.b64decode(TZFILE_EST5EDT)))
+ self.assertPicklable(tzc)
+
+ def testPickleTzFileEurope_Helsinki(self):
+ tzc = tz.tzfile(BytesIO(base64.b64decode(EUROPE_HELSINKI)))
+ self.assertPicklable(tzc)
+
+ def testPickleTzFileNew_York(self):
+ tzc = tz.tzfile(BytesIO(base64.b64decode(NEW_YORK)))
+ self.assertPicklable(tzc)
+
+ @unittest.skip("Known failure")
+ def testPickleTzICal(self):
+ tzc = tz.tzical(StringIO(TZICAL_EST5EDT)).get()
+ self.assertPicklable(tzc)
+
+ def testPickleTzGettz(self):
+ self.assertPicklable(tz.gettz('America/New_York'))
+
+ def testPickleZoneFileGettz(self):
+ zoneinfo_file = zoneinfo.get_zonefile_instance()
+ tzi = zoneinfo_file.get('America/New_York')
+ self.assertIsNot(tzi, None)
+ self.assertPicklable(tzi)
+
+
+class TzPickleFileTest(TzPickleTest):
+ """ Run all the TzPickleTest tests, using a temporary file """
+ _asfile = True
+
+
+class DatetimeAmbiguousTest(unittest.TestCase):
+ """ Test the datetime_exists / datetime_ambiguous functions """
+
+ def testNoTzSpecified(self):
+ with self.assertRaises(ValueError):
+ tz.datetime_ambiguous(datetime(2016, 4, 1, 2, 9))
+
+ def _get_no_support_tzinfo_class(self, dt_start, dt_end, dst_only=False):
+ # Generates a class of tzinfo with no support for is_ambiguous
+ # where dates between dt_start and dt_end are ambiguous.
+
+ class FoldingTzInfo(tzinfo):
+ def utcoffset(self, dt):
+ if not dst_only:
+ dt_n = dt.replace(tzinfo=None)
+
+ if dt_start <= dt_n < dt_end and getattr(dt_n, 'fold', 0):
+ return timedelta(hours=-1)
+
+ return timedelta(hours=0)
+
+ def dst(self, dt):
+ dt_n = dt.replace(tzinfo=None)
+
+ if dt_start <= dt_n < dt_end and getattr(dt_n, 'fold', 0):
+ return timedelta(hours=1)
+ else:
+ return timedelta(0)
+
+ return FoldingTzInfo
+
+ def _get_no_support_tzinfo(self, dt_start, dt_end, dst_only=False):
+ return self._get_no_support_tzinfo_class(dt_start, dt_end, dst_only)()
+
+ def testNoSupportAmbiguityFoldNaive(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
+ tz=tzi))
+
+ def testNoSupportAmbiguityFoldAware(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30,
+ tzinfo=tzi)))
+
+ def testNoSupportAmbiguityUnambiguousNaive(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
+ tz=tzi))
+
+ def testNoSupportAmbiguityUnambiguousAware(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30,
+ tzinfo=tzi)))
+
+ def testNoSupportAmbiguityFoldDSTOnly(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end, dst_only=True)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
+ tz=tzi))
+
+ def testNoSupportAmbiguityUnambiguousDSTOnly(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_no_support_tzinfo(dt_start, dt_end, dst_only=True)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
+ tz=tzi))
+
+ def testSupportAmbiguityFoldNaive(self):
+ tzi = tz.gettz('US/Eastern')
+
+ dt = datetime(2011, 11, 6, 1, 30)
+
+ self.assertTrue(tz.datetime_ambiguous(dt, tz=tzi))
+
+ def testSupportAmbiguityFoldAware(self):
+ tzi = tz.gettz('US/Eastern')
+
+ dt = datetime(2011, 11, 6, 1, 30, tzinfo=tzi)
+
+ self.assertTrue(tz.datetime_ambiguous(dt))
+
+ def testSupportAmbiguityUnambiguousAware(self):
+ tzi = tz.gettz('US/Eastern')
+
+ dt = datetime(2011, 11, 6, 4, 30)
+
+ self.assertFalse(tz.datetime_ambiguous(dt, tz=tzi))
+
+ def testSupportAmbiguityUnambiguousNaive(self):
+ tzi = tz.gettz('US/Eastern')
+
+ dt = datetime(2011, 11, 6, 4, 30, tzinfo=tzi)
+
+ self.assertFalse(tz.datetime_ambiguous(dt))
+
+ def _get_ambig_error_tzinfo(self, dt_start, dt_end, dst_only=False):
+ cTzInfo = self._get_no_support_tzinfo_class(dt_start, dt_end, dst_only)
+
+ # Takes the wrong number of arguments and raises an error anyway.
+ class FoldTzInfoRaises(cTzInfo):
+ def is_ambiguous(self, dt, other_arg):
+ raise NotImplementedError('This is not implemented')
+
+ return FoldTzInfoRaises()
+
+ def testIncompatibleAmbiguityFoldNaive(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
+ tz=tzi))
+
+ def testIncompatibleAmbiguityFoldAware(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30,
+ tzinfo=tzi)))
+
+ def testIncompatibleAmbiguityUnambiguousNaive(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
+ tz=tzi))
+
+ def testIncompatibleAmbiguityUnambiguousAware(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30,
+ tzinfo=tzi)))
+
+ def testIncompatibleAmbiguityFoldDSTOnly(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end, dst_only=True)
+
+ self.assertTrue(tz.datetime_ambiguous(datetime(2018, 9, 1, 1, 30),
+ tz=tzi))
+
+ def testIncompatibleAmbiguityUnambiguousDSTOnly(self):
+ dt_start = datetime(2018, 9, 1, 1, 0)
+ dt_end = datetime(2018, 9, 1, 2, 0)
+
+ tzi = self._get_ambig_error_tzinfo(dt_start, dt_end, dst_only=True)
+
+ self.assertFalse(tz.datetime_ambiguous(datetime(2018, 10, 1, 12, 30),
+ tz=tzi))
+
+ def testSpecifiedTzOverridesAttached(self):
+ # If a tz is specified, the datetime will be treated as naive.
+
+ # This is not ambiguous in the local zone
+ dt = datetime(2011, 11, 6, 1, 30, tzinfo=tz.gettz('Australia/Sydney'))
+
+ self.assertFalse(tz.datetime_ambiguous(dt))
+
+ tzi = tz.gettz('US/Eastern')
+ self.assertTrue(tz.datetime_ambiguous(dt, tz=tzi))
+
+
+class DatetimeExistsTest(unittest.TestCase):
+ def testNoTzSpecified(self):
+ with self.assertRaises(ValueError):
+ tz.datetime_exists(datetime(2016, 4, 1, 2, 9))
+
+ def testInGapNaive(self):
+ tzi = tz.gettz('Australia/Sydney')
+
+ dt = datetime(2012, 10, 7, 2, 30)
+
+ self.assertFalse(tz.datetime_exists(dt, tz=tzi))
+
+ def testInGapAware(self):
+ tzi = tz.gettz('Australia/Sydney')
+
+ dt = datetime(2012, 10, 7, 2, 30, tzinfo=tzi)
+
+ self.assertFalse(tz.datetime_exists(dt))
+
+ def testExistsNaive(self):
+ tzi = tz.gettz('Australia/Sydney')
+
+ dt = datetime(2012, 10, 7, 10, 30)
+
+ self.assertTrue(tz.datetime_exists(dt, tz=tzi))
+
+ def testExistsAware(self):
+ tzi = tz.gettz('Australia/Sydney')
+
+ dt = datetime(2012, 10, 7, 10, 30, tzinfo=tzi)
+
+ self.assertTrue(tz.datetime_exists(dt))
+
+ def testSpecifiedTzOverridesAttached(self):
+ EST = tz.gettz('US/Eastern')
+ AEST = tz.gettz('Australia/Sydney')
+
+ dt = datetime(2012, 10, 7, 2, 30, tzinfo=EST) # This time exists
+
+ self.assertFalse(tz.datetime_exists(dt, tz=AEST))
+
+
class TestEnfold:
def test_enter_fold_default(self):
- dt = tz.enfold(datetime(2020, 1, 19, 3, 32))
-
+ dt = tz.enfold(datetime(2020, 1, 19, 3, 32))
+
assert dt.fold == 1
-
+
def test_enter_fold(self):
- dt = tz.enfold(datetime(2020, 1, 19, 3, 32), fold=1)
-
+ dt = tz.enfold(datetime(2020, 1, 19, 3, 32), fold=1)
+
assert dt.fold == 1
-
+
def test_exit_fold(self):
- dt = tz.enfold(datetime(2020, 1, 19, 3, 32), fold=0)
-
- # Before Python 3.6, dt.fold won't exist if fold is 0.
+ dt = tz.enfold(datetime(2020, 1, 19, 3, 32), fold=0)
+
+ # Before Python 3.6, dt.fold won't exist if fold is 0.
assert getattr(dt, 'fold', 0) == 0
-
+
def test_defold(self):
dt = tz.enfold(datetime(2020, 1, 19, 3, 32), fold=1)
-
+
dt2 = tz.enfold(dt, fold=0)
assert getattr(dt2, 'fold', 0) == 0
@@ -2703,109 +2703,109 @@ class TestEnfold:
dt.replace(1950, year=2000)
-@pytest.mark.tz_resolve_imaginary
-class ImaginaryDateTest(unittest.TestCase):
- def testCanberraForward(self):
- tzi = tz.gettz('Australia/Canberra')
- dt = datetime(2018, 10, 7, 2, 30, tzinfo=tzi)
- dt_act = tz.resolve_imaginary(dt)
- dt_exp = datetime(2018, 10, 7, 3, 30, tzinfo=tzi)
- self.assertEqual(dt_act, dt_exp)
-
- def testLondonForward(self):
- tzi = tz.gettz('Europe/London')
- dt = datetime(2018, 3, 25, 1, 30, tzinfo=tzi)
- dt_act = tz.resolve_imaginary(dt)
- dt_exp = datetime(2018, 3, 25, 2, 30, tzinfo=tzi)
- self.assertEqual(dt_act, dt_exp)
-
- def testKeivForward(self):
- tzi = tz.gettz('Europe/Kiev')
- dt = datetime(2018, 3, 25, 3, 30, tzinfo=tzi)
- dt_act = tz.resolve_imaginary(dt)
- dt_exp = datetime(2018, 3, 25, 4, 30, tzinfo=tzi)
- self.assertEqual(dt_act, dt_exp)
-
-
-@pytest.mark.tz_resolve_imaginary
-@pytest.mark.parametrize('dt', [
- datetime(2017, 11, 5, 1, 30, tzinfo=tz.gettz('America/New_York')),
- datetime(2018, 10, 28, 1, 30, tzinfo=tz.gettz('Europe/London')),
- datetime(2017, 4, 2, 2, 30, tzinfo=tz.gettz('Australia/Sydney')),
-])
-def test_resolve_imaginary_ambiguous(dt):
- assert tz.resolve_imaginary(dt) is dt
-
- dt_f = tz.enfold(dt)
- assert dt is not dt_f
- assert tz.resolve_imaginary(dt_f) is dt_f
-
-
-@pytest.mark.tz_resolve_imaginary
-@pytest.mark.parametrize('dt', [
- datetime(2017, 6, 2, 12, 30, tzinfo=tz.gettz('America/New_York')),
- datetime(2018, 4, 2, 9, 30, tzinfo=tz.gettz('Europe/London')),
- datetime(2017, 2, 2, 16, 30, tzinfo=tz.gettz('Australia/Sydney')),
- datetime(2017, 12, 2, 12, 30, tzinfo=tz.gettz('America/New_York')),
- datetime(2018, 12, 2, 9, 30, tzinfo=tz.gettz('Europe/London')),
- datetime(2017, 6, 2, 16, 30, tzinfo=tz.gettz('Australia/Sydney')),
+@pytest.mark.tz_resolve_imaginary
+class ImaginaryDateTest(unittest.TestCase):
+ def testCanberraForward(self):
+ tzi = tz.gettz('Australia/Canberra')
+ dt = datetime(2018, 10, 7, 2, 30, tzinfo=tzi)
+ dt_act = tz.resolve_imaginary(dt)
+ dt_exp = datetime(2018, 10, 7, 3, 30, tzinfo=tzi)
+ self.assertEqual(dt_act, dt_exp)
+
+ def testLondonForward(self):
+ tzi = tz.gettz('Europe/London')
+ dt = datetime(2018, 3, 25, 1, 30, tzinfo=tzi)
+ dt_act = tz.resolve_imaginary(dt)
+ dt_exp = datetime(2018, 3, 25, 2, 30, tzinfo=tzi)
+ self.assertEqual(dt_act, dt_exp)
+
+ def testKeivForward(self):
+ tzi = tz.gettz('Europe/Kiev')
+ dt = datetime(2018, 3, 25, 3, 30, tzinfo=tzi)
+ dt_act = tz.resolve_imaginary(dt)
+ dt_exp = datetime(2018, 3, 25, 4, 30, tzinfo=tzi)
+ self.assertEqual(dt_act, dt_exp)
+
+
+@pytest.mark.tz_resolve_imaginary
+@pytest.mark.parametrize('dt', [
+ datetime(2017, 11, 5, 1, 30, tzinfo=tz.gettz('America/New_York')),
+ datetime(2018, 10, 28, 1, 30, tzinfo=tz.gettz('Europe/London')),
+ datetime(2017, 4, 2, 2, 30, tzinfo=tz.gettz('Australia/Sydney')),
+])
+def test_resolve_imaginary_ambiguous(dt):
+ assert tz.resolve_imaginary(dt) is dt
+
+ dt_f = tz.enfold(dt)
+ assert dt is not dt_f
+ assert tz.resolve_imaginary(dt_f) is dt_f
+
+
+@pytest.mark.tz_resolve_imaginary
+@pytest.mark.parametrize('dt', [
+ datetime(2017, 6, 2, 12, 30, tzinfo=tz.gettz('America/New_York')),
+ datetime(2018, 4, 2, 9, 30, tzinfo=tz.gettz('Europe/London')),
+ datetime(2017, 2, 2, 16, 30, tzinfo=tz.gettz('Australia/Sydney')),
+ datetime(2017, 12, 2, 12, 30, tzinfo=tz.gettz('America/New_York')),
+ datetime(2018, 12, 2, 9, 30, tzinfo=tz.gettz('Europe/London')),
+ datetime(2017, 6, 2, 16, 30, tzinfo=tz.gettz('Australia/Sydney')),
datetime(2025, 9, 25, 1, 17, tzinfo=tz.UTC),
- datetime(2025, 9, 25, 1, 17, tzinfo=tz.tzoffset('EST', -18000)),
- datetime(2019, 3, 4, tzinfo=None)
-])
-def test_resolve_imaginary_existing(dt):
- assert tz.resolve_imaginary(dt) is dt
-
-
-def __get_kiritimati_resolve_imaginary_test():
- # In the 2018d release of the IANA database, the Kiritimati "imaginary day"
- # data was corrected, so if the system zoneinfo is older than 2018d, the
- # Kiritimati test will fail.
-
- tzi = tz.gettz('Pacific/Kiritimati')
- new_version = False
- if not tz.datetime_exists(datetime(1995, 1, 1, 12, 30), tzi):
- zif = zoneinfo.get_zonefile_instance()
- if zif.metadata is not None:
- new_version = zif.metadata['tzversion'] >= '2018d'
-
- if new_version:
- tzi = zif.get('Pacific/Kiritimati')
- else:
- new_version = True
-
- if new_version:
- dates = (datetime(1994, 12, 31, 12, 30), datetime(1995, 1, 1, 12, 30))
- else:
- dates = (datetime(1995, 1, 1, 12, 30), datetime(1995, 1, 2, 12, 30))
-
- return (tzi, ) + dates
-
-
+ datetime(2025, 9, 25, 1, 17, tzinfo=tz.tzoffset('EST', -18000)),
+ datetime(2019, 3, 4, tzinfo=None)
+])
+def test_resolve_imaginary_existing(dt):
+ assert tz.resolve_imaginary(dt) is dt
+
+
+def __get_kiritimati_resolve_imaginary_test():
+ # In the 2018d release of the IANA database, the Kiritimati "imaginary day"
+ # data was corrected, so if the system zoneinfo is older than 2018d, the
+ # Kiritimati test will fail.
+
+ tzi = tz.gettz('Pacific/Kiritimati')
+ new_version = False
+ if not tz.datetime_exists(datetime(1995, 1, 1, 12, 30), tzi):
+ zif = zoneinfo.get_zonefile_instance()
+ if zif.metadata is not None:
+ new_version = zif.metadata['tzversion'] >= '2018d'
+
+ if new_version:
+ tzi = zif.get('Pacific/Kiritimati')
+ else:
+ new_version = True
+
+ if new_version:
+ dates = (datetime(1994, 12, 31, 12, 30), datetime(1995, 1, 1, 12, 30))
+ else:
+ dates = (datetime(1995, 1, 1, 12, 30), datetime(1995, 1, 2, 12, 30))
+
+ return (tzi, ) + dates
+
+
resolve_imaginary_tests = [
- (tz.gettz('Europe/London'),
- datetime(2018, 3, 25, 1, 30), datetime(2018, 3, 25, 2, 30)),
- (tz.gettz('America/New_York'),
- datetime(2017, 3, 12, 2, 30), datetime(2017, 3, 12, 3, 30)),
- (tz.gettz('Australia/Sydney'),
- datetime(2014, 10, 5, 2, 0), datetime(2014, 10, 5, 3, 0)),
- __get_kiritimati_resolve_imaginary_test(),
+ (tz.gettz('Europe/London'),
+ datetime(2018, 3, 25, 1, 30), datetime(2018, 3, 25, 2, 30)),
+ (tz.gettz('America/New_York'),
+ datetime(2017, 3, 12, 2, 30), datetime(2017, 3, 12, 3, 30)),
+ (tz.gettz('Australia/Sydney'),
+ datetime(2014, 10, 5, 2, 0), datetime(2014, 10, 5, 3, 0)),
+ __get_kiritimati_resolve_imaginary_test(),
]
-
-
+
+
if SUPPORTS_SUB_MINUTE_OFFSETS:
resolve_imaginary_tests.append(
(tz.gettz('Africa/Monrovia'),
datetime(1972, 1, 7, 0, 30), datetime(1972, 1, 7, 1, 14, 30)))
-
-@pytest.mark.tz_resolve_imaginary
+
+@pytest.mark.tz_resolve_imaginary
@pytest.mark.parametrize('tzi, dt, dt_exp', resolve_imaginary_tests)
def test_resolve_imaginary(tzi, dt, dt_exp):
dt = dt.replace(tzinfo=tzi)
dt_exp = dt_exp.replace(tzinfo=tzi)
-
- dt_r = tz.resolve_imaginary(dt)
- assert dt_r == dt_exp
- assert dt_r.tzname() == dt_exp.tzname()
- assert dt_r.utcoffset() == dt_exp.utcoffset()
+
+ dt_r = tz.resolve_imaginary(dt)
+ assert dt_r == dt_exp
+ assert dt_r.tzname() == dt_exp.tzname()
+ assert dt_r.utcoffset() == dt_exp.utcoffset()
diff --git a/contrib/python/dateutil/dateutil/test/test_utils.py b/contrib/python/dateutil/dateutil/test/test_utils.py
index 2b41c7ecfe..fe1bfdcb84 100644
--- a/contrib/python/dateutil/dateutil/test/test_utils.py
+++ b/contrib/python/dateutil/dateutil/test/test_utils.py
@@ -1,37 +1,37 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-from datetime import timedelta, datetime
-
-from dateutil import tz
-from dateutil import utils
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from datetime import timedelta, datetime
+
+from dateutil import tz
+from dateutil import utils
from dateutil.tz import UTC
-from dateutil.utils import within_delta
-
-from freezegun import freeze_time
-
-NYC = tz.gettz("America/New_York")
-
-
+from dateutil.utils import within_delta
+
+from freezegun import freeze_time
+
+NYC = tz.gettz("America/New_York")
+
+
@freeze_time(datetime(2014, 12, 15, 1, 21, 33, 4003))
def test_utils_today():
assert utils.today() == datetime(2014, 12, 15, 0, 0, 0)
-
-
+
+
@freeze_time(datetime(2014, 12, 15, 12), tz_offset=5)
def test_utils_today_tz_info():
assert utils.today(NYC) == datetime(2014, 12, 15, 0, 0, 0, tzinfo=NYC)
-
-
+
+
@freeze_time(datetime(2014, 12, 15, 23), tz_offset=5)
def test_utils_today_tz_info_different_day():
assert utils.today(UTC) == datetime(2014, 12, 16, 0, 0, 0, tzinfo=UTC)
-
-
+
+
def test_utils_default_tz_info_naive():
dt = datetime(2014, 9, 14, 9, 30)
assert utils.default_tzinfo(dt, NYC).tzinfo is NYC
-
-
+
+
def test_utils_default_tz_info_aware():
dt = datetime(2014, 9, 14, 9, 30, tzinfo=UTC)
assert utils.default_tzinfo(dt, NYC).tzinfo is UTC
diff --git a/contrib/python/dateutil/dateutil/tz/__init__.py b/contrib/python/dateutil/dateutil/tz/__init__.py
index 98d1589dfb..af1352c472 100644
--- a/contrib/python/dateutil/dateutil/tz/__init__.py
+++ b/contrib/python/dateutil/dateutil/tz/__init__.py
@@ -1,12 +1,12 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
from .tz import *
-from .tz import __doc__
+from .tz import __doc__
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz",
- "enfold", "datetime_ambiguous", "datetime_exists",
- "resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"]
-
-
-class DeprecatedTzFormatWarning(Warning):
- """Warning raised when time zones are parsed from deprecated formats."""
+ "enfold", "datetime_ambiguous", "datetime_exists",
+ "resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"]
+
+
+class DeprecatedTzFormatWarning(Warning):
+ """Warning raised when time zones are parsed from deprecated formats."""
diff --git a/contrib/python/dateutil/dateutil/tz/_common.py b/contrib/python/dateutil/dateutil/tz/_common.py
index 55cbd79170..e6ac118315 100644
--- a/contrib/python/dateutil/dateutil/tz/_common.py
+++ b/contrib/python/dateutil/dateutil/tz/_common.py
@@ -65,36 +65,36 @@ else:
"""
__slots__ = ()
- def replace(self, *args, **kwargs):
- """
- Return a datetime with the same attributes, except for those
- attributes given new values by whichever keyword arguments are
- specified. Note that tzinfo=None can be specified to create a naive
- datetime from an aware datetime with no conversion of date and time
- data.
-
- This is reimplemented in ``_DatetimeWithFold`` because pypy3 will
- return a ``datetime.datetime`` even if ``fold`` is unchanged.
- """
- argnames = (
- 'year', 'month', 'day', 'hour', 'minute', 'second',
- 'microsecond', 'tzinfo'
- )
-
- for arg, argname in zip(args, argnames):
- if argname in kwargs:
- raise TypeError('Duplicate argument: {}'.format(argname))
-
- kwargs[argname] = arg
-
- for argname in argnames:
- if argname not in kwargs:
- kwargs[argname] = getattr(self, argname)
-
- dt_class = self.__class__ if kwargs.get('fold', 1) else datetime
-
- return dt_class(**kwargs)
-
+ def replace(self, *args, **kwargs):
+ """
+ Return a datetime with the same attributes, except for those
+ attributes given new values by whichever keyword arguments are
+ specified. Note that tzinfo=None can be specified to create a naive
+ datetime from an aware datetime with no conversion of date and time
+ data.
+
+ This is reimplemented in ``_DatetimeWithFold`` because pypy3 will
+ return a ``datetime.datetime`` even if ``fold`` is unchanged.
+ """
+ argnames = (
+ 'year', 'month', 'day', 'hour', 'minute', 'second',
+ 'microsecond', 'tzinfo'
+ )
+
+ for arg, argname in zip(args, argnames):
+ if argname in kwargs:
+ raise TypeError('Duplicate argument: {}'.format(argname))
+
+ kwargs[argname] = arg
+
+ for argname in argnames:
+ if argname not in kwargs:
+ kwargs[argname] = getattr(self, argname)
+
+ dt_class = self.__class__ if kwargs.get('fold', 1) else datetime
+
+ return dt_class(**kwargs)
+
@property
def fold(self):
return 1
diff --git a/contrib/python/dateutil/dateutil/tz/_factories.py b/contrib/python/dateutil/dateutil/tz/_factories.py
index fe43054379..f8a65891a0 100644
--- a/contrib/python/dateutil/dateutil/tz/_factories.py
+++ b/contrib/python/dateutil/dateutil/tz/_factories.py
@@ -1,41 +1,41 @@
-from datetime import timedelta
+from datetime import timedelta
import weakref
from collections import OrderedDict
-
+
from six.moves import _thread
-
-
-class _TzSingleton(type):
- def __init__(cls, *args, **kwargs):
- cls.__instance = None
- super(_TzSingleton, cls).__init__(*args, **kwargs)
-
- def __call__(cls):
- if cls.__instance is None:
- cls.__instance = super(_TzSingleton, cls).__call__()
- return cls.__instance
-
-
-class _TzFactory(type):
- def instance(cls, *args, **kwargs):
- """Alternate constructor that returns a fresh instance"""
- return type.__call__(cls, *args, **kwargs)
-
-
-class _TzOffsetFactory(_TzFactory):
- def __init__(cls, *args, **kwargs):
+
+
+class _TzSingleton(type):
+ def __init__(cls, *args, **kwargs):
+ cls.__instance = None
+ super(_TzSingleton, cls).__init__(*args, **kwargs)
+
+ def __call__(cls):
+ if cls.__instance is None:
+ cls.__instance = super(_TzSingleton, cls).__call__()
+ return cls.__instance
+
+
+class _TzFactory(type):
+ def instance(cls, *args, **kwargs):
+ """Alternate constructor that returns a fresh instance"""
+ return type.__call__(cls, *args, **kwargs)
+
+
+class _TzOffsetFactory(_TzFactory):
+ def __init__(cls, *args, **kwargs):
cls.__instances = weakref.WeakValueDictionary()
cls.__strong_cache = OrderedDict()
cls.__strong_cache_size = 8
cls._cache_lock = _thread.allocate_lock()
-
- def __call__(cls, name, offset):
+
+ def __call__(cls, name, offset):
if isinstance(offset, timedelta):
key = (name, offset.total_seconds())
else:
key = (name, offset)
-
+
instance = cls.__instances.get(key, None)
if instance is None:
instance = cls.__instances.setdefault(key,
@@ -49,21 +49,21 @@ class _TzOffsetFactory(_TzFactory):
if len(cls.__strong_cache) > cls.__strong_cache_size:
cls.__strong_cache.popitem(last=False)
- return instance
-
-
-class _TzStrFactory(_TzFactory):
- def __init__(cls, *args, **kwargs):
+ return instance
+
+
+class _TzStrFactory(_TzFactory):
+ def __init__(cls, *args, **kwargs):
cls.__instances = weakref.WeakValueDictionary()
cls.__strong_cache = OrderedDict()
cls.__strong_cache_size = 8
-
+
cls.__cache_lock = _thread.allocate_lock()
- def __call__(cls, s, posix_offset=False):
+ def __call__(cls, s, posix_offset=False):
key = (s, posix_offset)
instance = cls.__instances.get(key, None)
-
+
if instance is None:
instance = cls.__instances.setdefault(key,
cls.instance(s, posix_offset))
@@ -76,5 +76,5 @@ class _TzStrFactory(_TzFactory):
if len(cls.__strong_cache) > cls.__strong_cache_size:
cls.__strong_cache.popitem(last=False)
- return instance
+ return instance
diff --git a/contrib/python/dateutil/dateutil/tz/tz.py b/contrib/python/dateutil/dateutil/tz/tz.py
index 246500e2ce..c67f56d465 100644
--- a/contrib/python/dateutil/dateutil/tz/tz.py
+++ b/contrib/python/dateutil/dateutil/tz/tz.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
"""
This module offers timezone implementations subclassing the abstract
-:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format
-files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,
-etc), TZ environment string (in all known formats), given ranges (with help
-from relative deltas), local machine timezone, fixed offset timezone, and UTC
+:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format
+files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,
+etc), TZ environment string (in all known formats), given ranges (with help
+from relative deltas), local machine timezone, fixed offset timezone, and UTC
timezone.
"""
import datetime
@@ -16,15 +16,15 @@ import bisect
import weakref
from collections import OrderedDict
-import six
+import six
from six import string_types
-from six.moves import _thread
-from ._common import tzname_in_python2, _tzinfo
+from six.moves import _thread
+from ._common import tzname_in_python2, _tzinfo
from ._common import tzrangebase, enfold
from ._common import _validate_fromutc_inputs
-from ._factories import _TzSingleton, _TzOffsetFactory
-from ._factories import _TzStrFactory
+from ._factories import _TzSingleton, _TzOffsetFactory
+from ._factories import _TzStrFactory
try:
from .win import tzwin, tzwinlocal
except ImportError:
@@ -38,38 +38,38 @@ EPOCH = datetime.datetime.utcfromtimestamp(0)
EPOCHORDINAL = EPOCH.toordinal()
-@six.add_metaclass(_TzSingleton)
+@six.add_metaclass(_TzSingleton)
class tzutc(datetime.tzinfo):
"""
This is a tzinfo object that represents the UTC time zone.
-
- **Examples:**
-
- .. doctest::
-
- >>> from datetime import *
- >>> from dateutil.tz import *
-
- >>> datetime.now()
- datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
-
- >>> datetime.now(tzutc())
- datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
-
- >>> datetime.now(tzutc()).tzname()
- 'UTC'
-
- .. versionchanged:: 2.7.0
- ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will
- always return the same object.
-
- .. doctest::
-
- >>> from dateutil.tz import tzutc, UTC
- >>> tzutc() is tzutc()
- True
- >>> tzutc() is UTC
- True
+
+ **Examples:**
+
+ .. doctest::
+
+ >>> from datetime import *
+ >>> from dateutil.tz import *
+
+ >>> datetime.now()
+ datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
+
+ >>> datetime.now(tzutc())
+ datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
+
+ >>> datetime.now(tzutc()).tzname()
+ 'UTC'
+
+ .. versionchanged:: 2.7.0
+ ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will
+ always return the same object.
+
+ .. doctest::
+
+ >>> from dateutil.tz import tzutc, UTC
+ >>> tzutc() is tzutc()
+ True
+ >>> tzutc() is UTC
+ True
"""
def utcoffset(self, dt):
return ZERO
@@ -129,7 +129,7 @@ class tzutc(datetime.tzinfo):
UTC = tzutc()
-@six.add_metaclass(_TzOffsetFactory)
+@six.add_metaclass(_TzOffsetFactory)
class tzoffset(datetime.tzinfo):
"""
A simple class for representing a fixed offset from UTC.
@@ -138,14 +138,14 @@ class tzoffset(datetime.tzinfo):
The timezone name, to be returned when ``tzname()`` is called.
:param offset:
The time zone offset in seconds, or (since version 2.6.0, represented
- as a :py:class:`datetime.timedelta` object).
+ as a :py:class:`datetime.timedelta` object).
"""
def __init__(self, name, offset):
self._name = name
try:
# Allow a timedelta
- offset = offset.total_seconds()
+ offset = offset.total_seconds()
except (TypeError, AttributeError):
pass
@@ -193,7 +193,7 @@ class tzoffset(datetime.tzinfo):
def __repr__(self):
return "%s(%s, %s)" % (self.__class__.__name__,
repr(self._name),
- int(self._offset.total_seconds()))
+ int(self._offset.total_seconds()))
__reduce__ = object.__reduce__
@@ -213,7 +213,7 @@ class tzlocal(_tzinfo):
self._dst_saved = self._dst_offset - self._std_offset
self._hasdst = bool(self._dst_saved)
- self._tznames = tuple(time.tzname)
+ self._tznames = tuple(time.tzname)
def utcoffset(self, dt):
if dt is None and self._hasdst:
@@ -235,7 +235,7 @@ class tzlocal(_tzinfo):
@tzname_in_python2
def tzname(self, dt):
- return self._tznames[self._isdst(dt)]
+ return self._tznames[self._isdst(dt)]
def is_ambiguous(self, dt):
"""
@@ -300,18 +300,18 @@ class tzlocal(_tzinfo):
return dstval
def __eq__(self, other):
- if isinstance(other, tzlocal):
- return (self._std_offset == other._std_offset and
- self._dst_offset == other._dst_offset)
- elif isinstance(other, tzutc):
- return (not self._hasdst and
- self._tznames[0] in {'UTC', 'GMT'} and
- self._std_offset == ZERO)
- elif isinstance(other, tzoffset):
- return (not self._hasdst and
- self._tznames[0] == other._name and
- self._std_offset == other._offset)
- else:
+ if isinstance(other, tzlocal):
+ return (self._std_offset == other._std_offset and
+ self._dst_offset == other._dst_offset)
+ elif isinstance(other, tzutc):
+ return (not self._hasdst and
+ self._tznames[0] in {'UTC', 'GMT'} and
+ self._std_offset == ZERO)
+ elif isinstance(other, tzoffset):
+ return (not self._hasdst and
+ self._tznames[0] == other._name and
+ self._std_offset == other._offset)
+ else:
return NotImplemented
__hash__ = None
@@ -399,60 +399,60 @@ class tzfile(_tzinfo):
``fileobj``'s ``name`` attribute or to ``repr(fileobj)``.
See `Sources for Time Zone and Daylight Saving Time Data
- <https://data.iana.org/time-zones/tz-link.html>`_ for more information.
- Time zone files can be compiled from the `IANA Time Zone database files
+ <https://data.iana.org/time-zones/tz-link.html>`_ for more information.
+ Time zone files can be compiled from the `IANA Time Zone database files
<https://www.iana.org/time-zones>`_ with the `zic time zone compiler
<https://www.freebsd.org/cgi/man.cgi?query=zic&sektion=8>`_
-
- .. note::
-
- Only construct a ``tzfile`` directly if you have a specific timezone
- file on disk that you want to read into a Python ``tzinfo`` object.
- If you want to get a ``tzfile`` representing a specific IANA zone,
- (e.g. ``'America/New_York'``), you should call
- :func:`dateutil.tz.gettz` with the zone identifier.
-
-
- **Examples:**
-
- Using the US Eastern time zone as an example, we can see that a ``tzfile``
- provides time zone information for the standard Daylight Saving offsets:
-
- .. testsetup:: tzfile
-
- from dateutil.tz import gettz
- from datetime import datetime
-
- .. doctest:: tzfile
-
- >>> NYC = gettz('America/New_York')
- >>> NYC
- tzfile('/usr/share/zoneinfo/America/New_York')
-
- >>> print(datetime(2016, 1, 3, tzinfo=NYC)) # EST
- 2016-01-03 00:00:00-05:00
-
- >>> print(datetime(2016, 7, 7, tzinfo=NYC)) # EDT
- 2016-07-07 00:00:00-04:00
-
-
- The ``tzfile`` structure contains a fully history of the time zone,
- so historical dates will also have the right offsets. For example, before
- the adoption of the UTC standards, New York used local solar mean time:
-
- .. doctest:: tzfile
-
- >>> print(datetime(1901, 4, 12, tzinfo=NYC)) # LMT
- 1901-04-12 00:00:00-04:56
-
- And during World War II, New York was on "Eastern War Time", which was a
- state of permanent daylight saving time:
-
- .. doctest:: tzfile
-
- >>> print(datetime(1944, 2, 7, tzinfo=NYC)) # EWT
- 1944-02-07 00:00:00-04:00
-
+
+ .. note::
+
+ Only construct a ``tzfile`` directly if you have a specific timezone
+ file on disk that you want to read into a Python ``tzinfo`` object.
+ If you want to get a ``tzfile`` representing a specific IANA zone,
+ (e.g. ``'America/New_York'``), you should call
+ :func:`dateutil.tz.gettz` with the zone identifier.
+
+
+ **Examples:**
+
+ Using the US Eastern time zone as an example, we can see that a ``tzfile``
+ provides time zone information for the standard Daylight Saving offsets:
+
+ .. testsetup:: tzfile
+
+ from dateutil.tz import gettz
+ from datetime import datetime
+
+ .. doctest:: tzfile
+
+ >>> NYC = gettz('America/New_York')
+ >>> NYC
+ tzfile('/usr/share/zoneinfo/America/New_York')
+
+ >>> print(datetime(2016, 1, 3, tzinfo=NYC)) # EST
+ 2016-01-03 00:00:00-05:00
+
+ >>> print(datetime(2016, 7, 7, tzinfo=NYC)) # EDT
+ 2016-07-07 00:00:00-04:00
+
+
+ The ``tzfile`` structure contains a fully history of the time zone,
+ so historical dates will also have the right offsets. For example, before
+ the adoption of the UTC standards, New York used local solar mean time:
+
+ .. doctest:: tzfile
+
+ >>> print(datetime(1901, 4, 12, tzinfo=NYC)) # LMT
+ 1901-04-12 00:00:00-04:56
+
+ And during World War II, New York was on "Eastern War Time", which was a
+ state of permanent daylight saving time:
+
+ .. doctest:: tzfile
+
+ >>> print(datetime(1944, 2, 7, tzinfo=NYC)) # EWT
+ 1944-02-07 00:00:00-04:00
+
"""
def __init__(self, fileobj, filename=None):
@@ -549,7 +549,7 @@ class tzfile(_tzinfo):
if timecnt:
out.trans_idx = struct.unpack(">%dB" % timecnt,
- fileobj.read(timecnt))
+ fileobj.read(timecnt))
else:
out.trans_idx = []
@@ -722,7 +722,7 @@ class tzfile(_tzinfo):
idx = bisect.bisect_right(trans_list, timestamp)
# We want to know when the previous transition was, so subtract off 1
- return idx - 1
+ return idx - 1
def _get_ttinfo(self, idx):
# For no list or after the last transition, default to _ttinfo_std
@@ -906,9 +906,9 @@ class tzrange(tzrangebase):
:param start:
A :class:`relativedelta.relativedelta` object or equivalent specifying
- the time and time of year that daylight savings time starts. To
- specify, for example, that DST starts at 2AM on the 2nd Sunday in
- March, pass:
+ the time and time of year that daylight savings time starts. To
+ specify, for example, that DST starts at 2AM on the 2nd Sunday in
+ March, pass:
``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))``
@@ -916,12 +916,12 @@ class tzrange(tzrangebase):
value is 2 AM on the first Sunday in April.
:param end:
- A :class:`relativedelta.relativedelta` object or equivalent
- representing the time and time of year that daylight savings time
- ends, with the same specification method as in ``start``. One note is
- that this should point to the first time in the *standard* zone, so if
- a transition occurs at 2AM in the DST zone and the clocks are set back
- 1 hour to 1AM, set the ``hours`` parameter to +1.
+ A :class:`relativedelta.relativedelta` object or equivalent
+ representing the time and time of year that daylight savings time
+ ends, with the same specification method as in ``start``. One note is
+ that this should point to the first time in the *standard* zone, so if
+ a transition occurs at 2AM in the DST zone and the clocks are set back
+ 1 hour to 1AM, set the ``hours`` parameter to +1.
**Examples:**
@@ -957,12 +957,12 @@ class tzrange(tzrangebase):
self._dst_abbr = dstabbr
try:
- stdoffset = stdoffset.total_seconds()
+ stdoffset = stdoffset.total_seconds()
except (TypeError, AttributeError):
pass
try:
- dstoffset = dstoffset.total_seconds()
+ dstoffset = dstoffset.total_seconds()
except (TypeError, AttributeError):
pass
@@ -1033,7 +1033,7 @@ class tzrange(tzrangebase):
return self._dst_base_offset_
-@six.add_metaclass(_TzStrFactory)
+@six.add_metaclass(_TzStrFactory)
class tzstr(tzrange):
"""
``tzstr`` objects are time zone objects specified by a time-zone string as
@@ -1052,38 +1052,38 @@ class tzstr(tzrange):
:param s:
A time zone string in ``TZ`` variable format. This can be a
- :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:
- :class:`unicode`) or a stream emitting unicode characters
- (e.g. :class:`StringIO`).
+ :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:
+ :class:`unicode`) or a stream emitting unicode characters
+ (e.g. :class:`StringIO`).
:param posix_offset:
Optional. If set to ``True``, interpret strings such as ``GMT+3`` or
``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the
POSIX standard.
- .. caution::
-
- Prior to version 2.7.0, this function also supported time zones
- in the format:
-
- * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``
- * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``
-
- This format is non-standard and has been deprecated; this function
- will raise a :class:`DeprecatedTZFormatWarning` until
- support is removed in a future version.
-
+ .. caution::
+
+ Prior to version 2.7.0, this function also supported time zones
+ in the format:
+
+ * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``
+ * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``
+
+ This format is non-standard and has been deprecated; this function
+ will raise a :class:`DeprecatedTZFormatWarning` until
+ support is removed in a future version.
+
.. _`GNU C Library: TZ Variable`:
https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
"""
def __init__(self, s, posix_offset=False):
global parser
- from dateutil.parser import _parser as parser
+ from dateutil.parser import _parser as parser
self._s = s
res = parser._parsetz(s)
- if res is None or res.any_unused_tokens:
+ if res is None or res.any_unused_tokens:
raise ValueError("unknown string format")
# Here we break the compatibility with the TZ variable handling.
@@ -1172,7 +1172,7 @@ class _tzicalvtz(_tzinfo):
self._comps = comps
self._cachedate = []
self._cachecomp = []
- self._cache_lock = _thread.allocate_lock()
+ self._cache_lock = _thread.allocate_lock()
def _find_comp(self, dt):
if len(self._comps) == 1:
@@ -1181,9 +1181,9 @@ class _tzicalvtz(_tzinfo):
dt = dt.replace(tzinfo=None)
try:
- with self._cache_lock:
- return self._cachecomp[self._cachedate.index(
- (dt, self._fold(dt)))]
+ with self._cache_lock:
+ return self._cachecomp[self._cachedate.index(
+ (dt, self._fold(dt)))]
except ValueError:
pass
@@ -1209,13 +1209,13 @@ class _tzicalvtz(_tzinfo):
else:
lastcomp = comp[0]
- with self._cache_lock:
- self._cachedate.insert(0, (dt, self._fold(dt)))
- self._cachecomp.insert(0, lastcomp)
+ with self._cache_lock:
+ self._cachedate.insert(0, (dt, self._fold(dt)))
+ self._cachecomp.insert(0, lastcomp)
- if len(self._cachedate) > 10:
- self._cachedate.pop()
- self._cachecomp.pop()
+ if len(self._cachedate) > 10:
+ self._cachedate.pop()
+ self._cachecomp.pop()
return lastcomp
@@ -1253,13 +1253,13 @@ class _tzicalvtz(_tzinfo):
class tzical(object):
"""
This object is designed to parse an iCalendar-style ``VTIMEZONE`` structure
- as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects.
+ as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects.
:param `fileobj`:
A file or stream in iCalendar format, which should be UTF-8 encoded
with CRLF endings.
- .. _`RFC 5545`: https://tools.ietf.org/html/rfc5545
+ .. _`RFC 5545`: https://tools.ietf.org/html/rfc5545
"""
def __init__(self, fileobj):
global rrule
@@ -1407,13 +1407,13 @@ class tzical(object):
raise ValueError("invalid component end: "+value)
elif comptype:
if name == "DTSTART":
- # DTSTART in VTIMEZONE takes a subset of valid RRULE
- # values under RFC 5545.
- for parm in parms:
- if parm != 'VALUE=DATE-TIME':
- msg = ('Unsupported DTSTART param in ' +
- 'VTIMEZONE: ' + parm)
- raise ValueError(msg)
+ # DTSTART in VTIMEZONE takes a subset of valid RRULE
+ # values under RFC 5545.
+ for parm in parms:
+ if parm != 'VALUE=DATE-TIME':
+ msg = ('Unsupported DTSTART param in ' +
+ 'VTIMEZONE: ' + parm)
+ raise ValueError(msg)
rrulelines.append(line)
founddtstart = True
elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"):
@@ -1467,153 +1467,153 @@ else:
TZPATHS = []
-def __get_gettz():
- tzlocal_classes = (tzlocal,)
- if tzwinlocal is not None:
- tzlocal_classes += (tzwinlocal,)
-
- class GettzFunc(object):
- """
- Retrieve a time zone object from a string representation
-
- This function is intended to retrieve the :py:class:`tzinfo` subclass
- that best represents the time zone that would be used if a POSIX
- `TZ variable`_ were set to the same value.
-
- If no argument or an empty string is passed to ``gettz``, local time
- is returned:
-
- .. code-block:: python3
-
- >>> gettz()
- tzfile('/etc/localtime')
-
- This function is also the preferred way to map IANA tz database keys
- to :class:`tzfile` objects:
-
- .. code-block:: python3
-
- >>> gettz('Pacific/Kiritimati')
- tzfile('/usr/share/zoneinfo/Pacific/Kiritimati')
-
- On Windows, the standard is extended to include the Windows-specific
- zone names provided by the operating system:
-
- .. code-block:: python3
-
- >>> gettz('Egypt Standard Time')
- tzwin('Egypt Standard Time')
-
- Passing a GNU ``TZ`` style string time zone specification returns a
- :class:`tzstr` object:
-
- .. code-block:: python3
-
- >>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
- tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
-
- :param name:
- A time zone name (IANA, or, on Windows, Windows keys), location of
- a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone
- specifier. An empty string, no argument or ``None`` is interpreted
- as local time.
-
- :return:
- Returns an instance of one of ``dateutil``'s :py:class:`tzinfo`
- subclasses.
-
- .. versionchanged:: 2.7.0
-
- After version 2.7.0, any two calls to ``gettz`` using the same
- input strings will return the same object:
-
- .. code-block:: python3
-
- >>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago')
- True
-
- In addition to improving performance, this ensures that
- `"same zone" semantics`_ are used for datetimes in the same zone.
-
-
- .. _`TZ variable`:
- https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
-
- .. _`"same zone" semantics`:
- https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html
- """
- def __init__(self):
-
+def __get_gettz():
+ tzlocal_classes = (tzlocal,)
+ if tzwinlocal is not None:
+ tzlocal_classes += (tzwinlocal,)
+
+ class GettzFunc(object):
+ """
+ Retrieve a time zone object from a string representation
+
+ This function is intended to retrieve the :py:class:`tzinfo` subclass
+ that best represents the time zone that would be used if a POSIX
+ `TZ variable`_ were set to the same value.
+
+ If no argument or an empty string is passed to ``gettz``, local time
+ is returned:
+
+ .. code-block:: python3
+
+ >>> gettz()
+ tzfile('/etc/localtime')
+
+ This function is also the preferred way to map IANA tz database keys
+ to :class:`tzfile` objects:
+
+ .. code-block:: python3
+
+ >>> gettz('Pacific/Kiritimati')
+ tzfile('/usr/share/zoneinfo/Pacific/Kiritimati')
+
+ On Windows, the standard is extended to include the Windows-specific
+ zone names provided by the operating system:
+
+ .. code-block:: python3
+
+ >>> gettz('Egypt Standard Time')
+ tzwin('Egypt Standard Time')
+
+ Passing a GNU ``TZ`` style string time zone specification returns a
+ :class:`tzstr` object:
+
+ .. code-block:: python3
+
+ >>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
+ tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
+
+ :param name:
+ A time zone name (IANA, or, on Windows, Windows keys), location of
+ a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone
+ specifier. An empty string, no argument or ``None`` is interpreted
+ as local time.
+
+ :return:
+ Returns an instance of one of ``dateutil``'s :py:class:`tzinfo`
+ subclasses.
+
+ .. versionchanged:: 2.7.0
+
+ After version 2.7.0, any two calls to ``gettz`` using the same
+ input strings will return the same object:
+
+ .. code-block:: python3
+
+ >>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago')
+ True
+
+ In addition to improving performance, this ensures that
+ `"same zone" semantics`_ are used for datetimes in the same zone.
+
+
+ .. _`TZ variable`:
+ https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+
+ .. _`"same zone" semantics`:
+ https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html
+ """
+ def __init__(self):
+
self.__instances = weakref.WeakValueDictionary()
self.__strong_cache_size = 8
self.__strong_cache = OrderedDict()
- self._cache_lock = _thread.allocate_lock()
-
- def __call__(self, name=None):
- with self._cache_lock:
- rv = self.__instances.get(name, None)
-
- if rv is None:
- rv = self.nocache(name=name)
+ self._cache_lock = _thread.allocate_lock()
+
+ def __call__(self, name=None):
+ with self._cache_lock:
+ rv = self.__instances.get(name, None)
+
+ if rv is None:
+ rv = self.nocache(name=name)
if not (name is None
or isinstance(rv, tzlocal_classes)
or rv is None):
- # tzlocal is slightly more complicated than the other
- # time zone providers because it depends on environment
- # at construction time, so don't cache that.
+ # tzlocal is slightly more complicated than the other
+ # time zone providers because it depends on environment
+ # at construction time, so don't cache that.
#
# We also cannot store weak references to None, so we
# will also not store that.
- self.__instances[name] = rv
+ self.__instances[name] = rv
else:
# No need for strong caching, return immediately
return rv
-
+
self.__strong_cache[name] = self.__strong_cache.pop(name, rv)
if len(self.__strong_cache) > self.__strong_cache_size:
self.__strong_cache.popitem(last=False)
- return rv
-
+ return rv
+
def set_cache_size(self, size):
with self._cache_lock:
self.__strong_cache_size = size
while len(self.__strong_cache) > size:
self.__strong_cache.popitem(last=False)
- def cache_clear(self):
- with self._cache_lock:
+ def cache_clear(self):
+ with self._cache_lock:
self.__instances = weakref.WeakValueDictionary()
self.__strong_cache.clear()
-
- @staticmethod
- def nocache(name=None):
- """A non-cached version of gettz"""
- tz = None
- if not name:
- try:
- name = os.environ["TZ"]
- except KeyError:
- pass
+
+ @staticmethod
+ def nocache(name=None):
+ """A non-cached version of gettz"""
+ tz = None
+ if not name:
+ try:
+ name = os.environ["TZ"]
+ except KeyError:
+ pass
if name is None or name in ("", ":"):
- for filepath in TZFILES:
- if not os.path.isabs(filepath):
- filename = filepath
- for path in TZPATHS:
- filepath = os.path.join(path, filename)
- if os.path.isfile(filepath):
- break
- else:
- continue
- if os.path.isfile(filepath):
- try:
- tz = tzfile(filepath)
- break
- except (IOError, OSError, ValueError):
- pass
- else:
- tz = tzlocal()
+ for filepath in TZFILES:
+ if not os.path.isabs(filepath):
+ filename = filepath
+ for path in TZPATHS:
+ filepath = os.path.join(path, filename)
+ if os.path.isfile(filepath):
+ break
+ else:
+ continue
+ if os.path.isfile(filepath):
+ try:
+ tz = tzfile(filepath)
+ break
+ except (IOError, OSError, ValueError):
+ pass
+ else:
+ tz = tzlocal()
else:
try:
if name.startswith(":"):
@@ -1624,62 +1624,62 @@ def __get_gettz():
six.raise_from(TypeError(new_msg), e)
else:
raise
- if os.path.isabs(name):
- if os.path.isfile(name):
- tz = tzfile(name)
- else:
+ if os.path.isabs(name):
+ if os.path.isfile(name):
+ tz = tzfile(name)
+ else:
tz = None
- else:
- for path in TZPATHS:
- filepath = os.path.join(path, name)
- if not os.path.isfile(filepath):
- filepath = filepath.replace(' ', '_')
- if not os.path.isfile(filepath):
- continue
- try:
- tz = tzfile(filepath)
+ else:
+ for path in TZPATHS:
+ filepath = os.path.join(path, name)
+ if not os.path.isfile(filepath):
+ filepath = filepath.replace(' ', '_')
+ if not os.path.isfile(filepath):
+ continue
+ try:
+ tz = tzfile(filepath)
break
- except (IOError, OSError, ValueError):
- pass
+ except (IOError, OSError, ValueError):
+ pass
else:
- tz = None
- if tzwin is not None:
- try:
- tz = tzwin(name)
+ tz = None
+ if tzwin is not None:
+ try:
+ tz = tzwin(name)
except (WindowsError, UnicodeEncodeError):
# UnicodeEncodeError is for Python 2.7 compat
- tz = None
-
- if not tz:
- from dateutil.zoneinfo import get_zonefile_instance
- tz = get_zonefile_instance().get(name)
-
- if not tz:
- for c in name:
- # name is not a tzstr unless it has at least
- # one offset. For short values of "name", an
- # explicit for loop seems to be the fastest way
- # To determine if a string contains a digit
- if c in "0123456789":
- try:
- tz = tzstr(name)
- except ValueError:
- pass
- break
- else:
- if name in ("GMT", "UTC"):
+ tz = None
+
+ if not tz:
+ from dateutil.zoneinfo import get_zonefile_instance
+ tz = get_zonefile_instance().get(name)
+
+ if not tz:
+ for c in name:
+ # name is not a tzstr unless it has at least
+ # one offset. For short values of "name", an
+ # explicit for loop seems to be the fastest way
+ # To determine if a string contains a digit
+ if c in "0123456789":
+ try:
+ tz = tzstr(name)
+ except ValueError:
+ pass
+ break
+ else:
+ if name in ("GMT", "UTC"):
tz = UTC
- elif name in time.tzname:
- tz = tzlocal()
- return tz
-
- return GettzFunc()
-
-
-gettz = __get_gettz()
-del __get_gettz
-
-
+ elif name in time.tzname:
+ tz = tzlocal()
+ return tz
+
+ return GettzFunc()
+
+
+gettz = __get_gettz()
+del __get_gettz
+
+
def datetime_exists(dt, tz=None):
"""
Given a datetime and a time zone, determine whether or not a given datetime
@@ -1694,10 +1694,10 @@ def datetime_exists(dt, tz=None):
``None`` or not provided, the datetime's own time zone will be used.
:return:
- Returns a boolean value whether or not the "wall time" exists in
- ``tz``.
-
- .. versionadded:: 2.7.0
+ Returns a boolean value whether or not the "wall time" exists in
+ ``tz``.
+
+ .. versionadded:: 2.7.0
"""
if tz is None:
if dt.tzinfo is None:
@@ -1745,7 +1745,7 @@ def datetime_ambiguous(dt, tz=None):
if is_ambiguous_fn is not None:
try:
return tz.is_ambiguous(dt)
- except Exception:
+ except Exception:
pass
# If it doesn't come out and tell us it's ambiguous, we'll just check if
@@ -1760,58 +1760,58 @@ def datetime_ambiguous(dt, tz=None):
return not (same_offset and same_dst)
-def resolve_imaginary(dt):
- """
- Given a datetime that may be imaginary, return an existing datetime.
-
- This function assumes that an imaginary datetime represents what the
- wall time would be in a zone had the offset transition not occurred, so
- it will always fall forward by the transition's change in offset.
-
- .. doctest::
-
- >>> from dateutil import tz
- >>> from datetime import datetime
- >>> NYC = tz.gettz('America/New_York')
- >>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
- 2017-03-12 03:30:00-04:00
-
- >>> KIR = tz.gettz('Pacific/Kiritimati')
- >>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR)))
- 1995-01-02 12:30:00+14:00
-
- As a note, :func:`datetime.astimezone` is guaranteed to produce a valid,
- existing datetime, so a round-trip to and from UTC is sufficient to get
- an extant datetime, however, this generally "falls back" to an earlier time
- rather than falling forward to the STD side (though no guarantees are made
- about this behavior).
-
- :param dt:
- A :class:`datetime.datetime` which may or may not exist.
-
- :return:
- Returns an existing :class:`datetime.datetime`. If ``dt`` was not
- imaginary, the datetime returned is guaranteed to be the same object
- passed to the function.
-
- .. versionadded:: 2.7.0
- """
- if dt.tzinfo is not None and not datetime_exists(dt):
-
- curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset()
- old_offset = (dt - datetime.timedelta(hours=24)).utcoffset()
-
- dt += curr_offset - old_offset
-
- return dt
-
-
+def resolve_imaginary(dt):
+ """
+ Given a datetime that may be imaginary, return an existing datetime.
+
+ This function assumes that an imaginary datetime represents what the
+ wall time would be in a zone had the offset transition not occurred, so
+ it will always fall forward by the transition's change in offset.
+
+ .. doctest::
+
+ >>> from dateutil import tz
+ >>> from datetime import datetime
+ >>> NYC = tz.gettz('America/New_York')
+ >>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
+ 2017-03-12 03:30:00-04:00
+
+ >>> KIR = tz.gettz('Pacific/Kiritimati')
+ >>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR)))
+ 1995-01-02 12:30:00+14:00
+
+ As a note, :func:`datetime.astimezone` is guaranteed to produce a valid,
+ existing datetime, so a round-trip to and from UTC is sufficient to get
+ an extant datetime, however, this generally "falls back" to an earlier time
+ rather than falling forward to the STD side (though no guarantees are made
+ about this behavior).
+
+ :param dt:
+ A :class:`datetime.datetime` which may or may not exist.
+
+ :return:
+ Returns an existing :class:`datetime.datetime`. If ``dt`` was not
+ imaginary, the datetime returned is guaranteed to be the same object
+ passed to the function.
+
+ .. versionadded:: 2.7.0
+ """
+ if dt.tzinfo is not None and not datetime_exists(dt):
+
+ curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset()
+ old_offset = (dt - datetime.timedelta(hours=24)).utcoffset()
+
+ dt += curr_offset - old_offset
+
+ return dt
+
+
def _datetime_to_timestamp(dt):
"""
- Convert a :class:`datetime.datetime` object to an epoch timestamp in
- seconds since January 1, 1970, ignoring the time zone.
+ Convert a :class:`datetime.datetime` object to an epoch timestamp in
+ seconds since January 1, 1970, ignoring the time zone.
"""
- return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
+ return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
if sys.version_info >= (3, 6):
diff --git a/contrib/python/dateutil/dateutil/utils.py b/contrib/python/dateutil/dateutil/utils.py
index a6848ba625..dd2d245a0b 100644
--- a/contrib/python/dateutil/dateutil/utils.py
+++ b/contrib/python/dateutil/dateutil/utils.py
@@ -1,71 +1,71 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers general convenience and utility functions for dealing with
-datetimes.
-
-.. versionadded:: 2.7.0
-"""
-from __future__ import unicode_literals
-
-from datetime import datetime, time
-
-
-def today(tzinfo=None):
- """
- Returns a :py:class:`datetime` representing the current day at midnight
-
- :param tzinfo:
- The time zone to attach (also used to determine the current day).
-
- :return:
- A :py:class:`datetime.datetime` object representing the current day
- at midnight.
- """
-
- dt = datetime.now(tzinfo)
- return datetime.combine(dt.date(), time(0, tzinfo=tzinfo))
-
-
-def default_tzinfo(dt, tzinfo):
- """
+# -*- coding: utf-8 -*-
+"""
+This module offers general convenience and utility functions for dealing with
+datetimes.
+
+.. versionadded:: 2.7.0
+"""
+from __future__ import unicode_literals
+
+from datetime import datetime, time
+
+
+def today(tzinfo=None):
+ """
+ Returns a :py:class:`datetime` representing the current day at midnight
+
+ :param tzinfo:
+ The time zone to attach (also used to determine the current day).
+
+ :return:
+ A :py:class:`datetime.datetime` object representing the current day
+ at midnight.
+ """
+
+ dt = datetime.now(tzinfo)
+ return datetime.combine(dt.date(), time(0, tzinfo=tzinfo))
+
+
+def default_tzinfo(dt, tzinfo):
+ """
Sets the ``tzinfo`` parameter on naive datetimes only
-
- This is useful for example when you are provided a datetime that may have
- either an implicit or explicit time zone, such as when parsing a time zone
- string.
-
- .. doctest::
-
- >>> from dateutil.tz import tzoffset
- >>> from dateutil.parser import parse
- >>> from dateutil.utils import default_tzinfo
- >>> dflt_tz = tzoffset("EST", -18000)
- >>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz))
- 2014-01-01 12:30:00+00:00
- >>> print(default_tzinfo(parse('2014-01-01 12:30'), dflt_tz))
- 2014-01-01 12:30:00-05:00
-
- :param dt:
- The datetime on which to replace the time zone
-
- :param tzinfo:
- The :py:class:`datetime.tzinfo` subclass instance to assign to
- ``dt`` if (and only if) it is naive.
-
- :return:
- Returns an aware :py:class:`datetime.datetime`.
- """
- if dt.tzinfo is not None:
- return dt
- else:
- return dt.replace(tzinfo=tzinfo)
-
-
-def within_delta(dt1, dt2, delta):
- """
+
+ This is useful for example when you are provided a datetime that may have
+ either an implicit or explicit time zone, such as when parsing a time zone
+ string.
+
+ .. doctest::
+
+ >>> from dateutil.tz import tzoffset
+ >>> from dateutil.parser import parse
+ >>> from dateutil.utils import default_tzinfo
+ >>> dflt_tz = tzoffset("EST", -18000)
+ >>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz))
+ 2014-01-01 12:30:00+00:00
+ >>> print(default_tzinfo(parse('2014-01-01 12:30'), dflt_tz))
+ 2014-01-01 12:30:00-05:00
+
+ :param dt:
+ The datetime on which to replace the time zone
+
+ :param tzinfo:
+ The :py:class:`datetime.tzinfo` subclass instance to assign to
+ ``dt`` if (and only if) it is naive.
+
+ :return:
+ Returns an aware :py:class:`datetime.datetime`.
+ """
+ if dt.tzinfo is not None:
+ return dt
+ else:
+ return dt.replace(tzinfo=tzinfo)
+
+
+def within_delta(dt1, dt2, delta):
+ """
Useful for comparing two datetimes that may have a negligible difference
- to be considered equal.
- """
- delta = abs(delta)
- difference = dt1 - dt2
- return -delta <= difference <= delta
+ to be considered equal.
+ """
+ delta = abs(delta)
+ difference = dt1 - dt2
+ return -delta <= difference <= delta
diff --git a/contrib/python/dateutil/dateutil/zoneinfo/__init__.py b/contrib/python/dateutil/dateutil/zoneinfo/__init__.py
index 30d8feff16..34f11ad66c 100644
--- a/contrib/python/dateutil/dateutil/zoneinfo/__init__.py
+++ b/contrib/python/dateutil/dateutil/zoneinfo/__init__.py
@@ -6,15 +6,15 @@ from tarfile import TarFile
from pkgutil import get_data
from io import BytesIO
-from dateutil.tz import tzfile as _tzfile
+from dateutil.tz import tzfile as _tzfile
-__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
+__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
METADATA_FN = 'METADATA'
-class tzfile(_tzfile):
+class tzfile(_tzfile):
def __reduce__(self):
return (gettz, (self._filename,))
@@ -30,15 +30,15 @@ def getzoneinfofile_stream():
class ZoneInfoFile(object):
def __init__(self, zonefile_stream=None):
if zonefile_stream is not None:
- with TarFile.open(fileobj=zonefile_stream) as tf:
- self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
- for zf in tf.getmembers()
- if zf.isfile() and zf.name != METADATA_FN}
+ with TarFile.open(fileobj=zonefile_stream) as tf:
+ self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
+ for zf in tf.getmembers()
+ if zf.isfile() and zf.name != METADATA_FN}
# deal with links: They'll point to their parent object. Less
# waste of memory
- links = {zl.name: self.zones[zl.linkname]
- for zl in tf.getmembers() if
- zl.islnk() or zl.issym()}
+ links = {zl.name: self.zones[zl.linkname]
+ for zl in tf.getmembers() if
+ zl.islnk() or zl.issym()}
self.zones.update(links)
try:
metadata_json = tf.extractfile(tf.getmember(METADATA_FN))
@@ -48,7 +48,7 @@ class ZoneInfoFile(object):
# no metadata in tar file
self.metadata = None
else:
- self.zones = {}
+ self.zones = {}
self.metadata = None
def get(self, name, default=None):
@@ -74,7 +74,7 @@ class ZoneInfoFile(object):
# timezone. Ugly, but adheres to the api.
#
# TODO: Remove after deprecation period.
-_CLASS_ZONE_INSTANCE = []
+_CLASS_ZONE_INSTANCE = []
def get_zonefile_instance(new_instance=False):
diff --git a/contrib/python/dateutil/dateutil/zoneinfo/rebuild.py b/contrib/python/dateutil/dateutil/zoneinfo/rebuild.py
index 42089d57a2..684c6586f0 100644
--- a/contrib/python/dateutil/dateutil/zoneinfo/rebuild.py
+++ b/contrib/python/dateutil/dateutil/zoneinfo/rebuild.py
@@ -4,22 +4,22 @@ import tempfile
import shutil
import json
from subprocess import check_call, check_output
-from tarfile import TarFile
+from tarfile import TarFile
-from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
+from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
- filename is the timezone tarball from ``ftp.iana.org/tz``.
+ filename is the timezone tarball from ``ftp.iana.org/tz``.
"""
tmpdir = tempfile.mkdtemp()
zonedir = os.path.join(tmpdir, "zoneinfo")
moduledir = os.path.dirname(__file__)
try:
- with TarFile.open(filename) as tf:
+ with TarFile.open(filename) as tf:
for name in zonegroups:
tf.extract(name, tmpdir)
filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
@@ -30,7 +30,7 @@ def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
json.dump(metadata, f, indent=4, sort_keys=True)
target = os.path.join(moduledir, ZONEFILENAME)
- with TarFile.open(target, "w:%s" % format) as tf:
+ with TarFile.open(target, "w:%s" % format) as tf:
for entry in os.listdir(zonedir):
entrypath = os.path.join(zonedir, entry)
tf.add(entrypath, entry)
diff --git a/contrib/python/dateutil/tests/ya.make b/contrib/python/dateutil/tests/ya.make
index 11fbc851ad..93c811e26e 100644
--- a/contrib/python/dateutil/tests/ya.make
+++ b/contrib/python/dateutil/tests/ya.make
@@ -1,7 +1,7 @@
PY23_TEST()
OWNER(g:python-contrib)
-
+
PEERDIR(
contrib/python/dateutil
contrib/python/freezegun
diff --git a/contrib/python/dateutil/ya.make b/contrib/python/dateutil/ya.make
index 4a94ea5b1b..0c4102c505 100644
--- a/contrib/python/dateutil/ya.make
+++ b/contrib/python/dateutil/ya.make
@@ -5,7 +5,7 @@ PY23_LIBRARY()
OWNER(g:python-contrib)
VERSION(2.8.2)
-
+
LICENSE(BSD-3-Clause)
PEERDIR(
@@ -25,18 +25,18 @@ PY_SRCS(
dateutil/_common.py
dateutil/_version.py
dateutil/easter.py
- dateutil/parser/__init__.py
- dateutil/parser/_parser.py
- dateutil/parser/isoparser.py
+ dateutil/parser/__init__.py
+ dateutil/parser/_parser.py
+ dateutil/parser/isoparser.py
dateutil/relativedelta.py
dateutil/rrule.py
dateutil/tz/__init__.py
dateutil/tz/_common.py
- dateutil/tz/_factories.py
+ dateutil/tz/_factories.py
dateutil/tz/tz.py
dateutil/tz/win.py
dateutil/tzwin.py
- dateutil/utils.py
+ dateutil/utils.py
dateutil/zoneinfo/__init__.py
dateutil/zoneinfo/rebuild.py
)
@@ -46,8 +46,8 @@ RESOURCE_FILES(
.dist-info/METADATA
.dist-info/top_level.txt
dateutil/zoneinfo/dateutil-zoneinfo.tar.gz
-)
-
+)
+
END()
RECURSE_FOR_TESTS(
diff --git a/contrib/python/ya.make b/contrib/python/ya.make
index 69e0e13fa9..d01ced9f3a 100644
--- a/contrib/python/ya.make
+++ b/contrib/python/ya.make
@@ -42,7 +42,7 @@ RECURSE(
aiozipkin
aiozk
alabaster
- alembic
+ alembic
allpairspy
amqp
aniso8601
@@ -53,7 +53,7 @@ RECURSE(
anyio
anytree
apipkg
- apispec
+ apispec
apispec-flask-restful
appdirs
APScheduler
@@ -127,7 +127,7 @@ RECURSE(
bsddb3
bson
bz2file
- cached-property
+ cached-property
cachelib
cachetools
catalogue
@@ -174,8 +174,8 @@ RECURSE(
contextdecorator
contextlib2
convertdate
- cookies
- cov-core
+ cookies
+ cov-core
coverage
coverage/bin
cpu-cores
@@ -192,7 +192,7 @@ RECURSE(
cytoolz
czipfile
daphne
- dask
+ dask
daphne
databases
dataclasses-json
@@ -355,13 +355,13 @@ RECURSE(
Faker
fakeredis
falcon
- falcon-cors
+ falcon-cors
falcon-multipart
- fallocate
+ fallocate
fancycompleter
fastapi
fastapi-utils
- fastdtw
+ fastdtw
fasteners
fastjsonschema
fastsnmp
@@ -416,14 +416,14 @@ RECURSE(
Flask-UUID
Flask-WTF
flatbuffers
- flex
+ flex
flup
frozendict
frozenlist
fsspec
ftfy
funcparserlib
- funcsigs
+ funcsigs
functools32
furl
future
@@ -472,7 +472,7 @@ RECURSE(
h2
h3
h5py
- hammock
+ hammock
hexdump
hijri-converter
hiredis
@@ -556,7 +556,7 @@ RECURSE(
jsonobject
jsonpath-rw
jsonpickle
- jsonpointer
+ jsonpointer
jsonref
jsonschema
jsonstreams
@@ -579,7 +579,7 @@ RECURSE(
langcodes
lark-parser
lazy
- lazy-object-proxy
+ lazy-object-proxy
lcov_cobertura
lcov_cobertura/bin
legacycontour
@@ -606,10 +606,10 @@ RECURSE(
markdown2
Markdown
MarkupSafe
- marshmallow
+ marshmallow
marshmallow_dataclass
marshmallow-enum
- marshmallow-mongoengine
+ marshmallow-mongoengine
marshmallow-oneofschema
marshmallow-sqlalchemy
marshmallow-union
@@ -681,9 +681,9 @@ RECURSE(
openapi-codec
openapi-core
openapi-schema-validator
- openapi-spec-validator
+ openapi-spec-validator
opencv-python
- openpyxl
+ openpyxl
opensfm
opentok
opentracing
@@ -697,7 +697,7 @@ RECURSE(
os-fast-reservoir
packageurl-python
packaging
- paginate
+ paginate
pamela
pampy
pamqp
@@ -715,7 +715,7 @@ RECURSE(
parsel
Parsley
parso
- partd
+ partd
passlib
patch
patched
@@ -757,7 +757,7 @@ RECURSE(
ppdeep
pq
pql
- prance
+ prance
premailer
preshed
pretend
@@ -852,7 +852,7 @@ RECURSE(
pysctp
pysendfile
pyserial
- PySocks
+ PySocks
pystan
pystan/pystan_model
pysyncobj
@@ -864,7 +864,7 @@ RECURSE(
pytest-datadir
pytest-datafixtures
pytest-django
- pytest-falcon
+ pytest-falcon
pytest-falcon-client
pytest-fixture-config
pytest-flake8
@@ -872,9 +872,9 @@ RECURSE(
pytest-flask
pytest-forked
pytest-freezegun
- pytest-httpretty
+ pytest-httpretty
pytest-lazy-fixture
- pytest-localserver
+ pytest-localserver
pytest-mock
pytest-randomly
pytest-responsemock
@@ -946,7 +946,7 @@ RECURSE(
requests-oauthlib
requests-toolbelt
requests-unixsocket
- responses
+ responses
respx
retry
retrying
@@ -974,7 +974,7 @@ RECURSE(
schema
schematics
schwifty
- scikit-image
+ scikit-image
scikit-learn
scipy
scour
@@ -1072,7 +1072,7 @@ RECURSE(
tldextract
toml
tomli
- toolz
+ toolz
toposort
toredis
tornado