Compare commits

..

1 Commits

Author SHA1 Message Date
Timo Furrer fa1c4eb600 Include epoch microseconds in DT comparison methods. Closes #156 2019-08-24 23:22:35 +02:00
7 changed files with 58 additions and 235 deletions
+13 -10
View File
@@ -1,6 +1,6 @@
name: Continuous Integration and Deployment
on: [push, pull_request]
on: [push]
jobs:
build:
@@ -8,14 +8,15 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 4
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
os: [ubuntu-latest, macOS-latest, windows-latest]
python-version: [2.7, 3.5, 3.6, 3.7]
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4.2.0
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Setup build and test environment
@@ -45,9 +46,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v1
- name: Set up Python 3.7
uses: actions/setup-python@v4.2.0
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Setup docs environment
@@ -61,18 +62,20 @@ jobs:
needs: [build, docs]
runs-on: ubuntu-latest
if: startsWith(github.event.ref, 'refs/tags') && github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v1
- name: Set up Python 3.7
uses: actions/setup-python@v4.2.0
if: startsWith(github.event.ref, 'refs/tags')
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Build Package
if: startsWith(github.event.ref, 'refs/tags')
run: |
python -m pip install --upgrade pip setuptools wheel
python setup.py sdist bdist_wheel --universal
- name: Publish Package on PyPI
if: startsWith(github.event.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
+18
View File
@@ -0,0 +1,18 @@
name: "Close Stale Issues and Pull Requests"
on:
schedule:
- cron: "0 * * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 60
days-before-close: 7
stale-issue-label: stale
stale-pr-label: state
stale-issue-message: 'This Issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
stale-pr-message: 'This Pull Request is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
+11 -6
View File
@@ -92,11 +92,6 @@ Behold, datetimes for humans!
>>> dt.snap('@d+3h').rfc2822()
'Mon, 21 Feb 1994 03:00:00 GMT'
# snap modifiers within a timezone
>>> dt = maya.when('Mon, 21 Feb 1994 21:21:42 GMT')
>>> dt.snap_tz('+3h@d', 'Australia/Perth').rfc2822()
'Mon, 21 Feb 1994 16:00:00 GMT'
☤ Advanced Usage of Maya
------------------------
@@ -131,7 +126,7 @@ From here, there are a number of methods available to you, which you can use to
☤ What about Delorean_, Arrow_, & Pendulum_?
--------------------------------------------
-----------------------------------------
All these projects complement each other, and are friends. Pendulum, for example, helps power Maya's parsing.
@@ -154,6 +149,16 @@ Installation is easy, with:
$ pip install maya
☤ Demo
------
Try ``maya`` interactively using this online demo:
.. image:: https://user-images.githubusercontent.com/1155573/49400125-16e73500-f722-11e8-9275-e1d7eb3bbf99.png
:target: https://notebooks.ai/demo/gh/kennethreitz/maya
:alt: Open Live Demo
How to Contribute
-----------------
+1 -1
View File
@@ -73,7 +73,7 @@ release = maya.__version__
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
+15 -52
View File
@@ -78,7 +78,10 @@ class MayaDT(object):
def __init__(self, epoch):
super(MayaDT, self).__init__()
self._epoch = epoch
# round the given epoch's microseconds to 6 digits
# to be compatible with Python's datetime.microseconds.
# See: https://docs.python.org/3/library/datetime.html#datetime.datetime.microsecond
self._epoch = round(epoch, 6)
def __repr__(self):
return "<MayaDT epoch={}>".format(self._epoch)
@@ -92,30 +95,30 @@ class MayaDT(object):
@validate_class_type_arguments("==")
def __eq__(self, maya_dt):
return int(self._epoch) == int(maya_dt._epoch)
return self._epoch == maya_dt._epoch
@validate_class_type_arguments("!=")
def __ne__(self, maya_dt):
return int(self._epoch) != int(maya_dt._epoch)
return self._epoch != maya_dt._epoch
@validate_class_type_arguments("<")
def __lt__(self, maya_dt):
return int(self._epoch) < int(maya_dt._epoch)
return self._epoch < maya_dt._epoch
@validate_class_type_arguments("<=")
def __le__(self, maya_dt):
return int(self._epoch) <= int(maya_dt._epoch)
return self._epoch <= maya_dt._epoch
@validate_class_type_arguments(">")
def __gt__(self, maya_dt):
return int(self._epoch) > int(maya_dt._epoch)
return self._epoch > maya_dt._epoch
@validate_class_type_arguments(">=")
def __ge__(self, maya_dt):
return int(self._epoch) >= int(maya_dt._epoch)
return self._epoch >= maya_dt._epoch
def __hash__(self):
return hash(int(self.epoch))
return hash(self.epoch)
def __add__(self, duration):
return self.add(seconds=_seconds_or_timedelta(duration).total_seconds())
@@ -153,17 +156,6 @@ class MayaDT(object):
"""
return self.from_datetime(snaptime.snap(self.datetime(), instruction))
def snap_tz(self, instruction, in_timezone):
"""
Returns a new MayaDT object modified by the given instruction.
The modifications happen in the given timezone.
Powered by snaptime. See https://github.com/zartstrom/snaptime
for a complete documentation about the snaptime instructions.
"""
dt_tz = self.datetime(to_timezone=in_timezone)
return self.from_datetime(snaptime.snap_tz(dt_tz, instruction, dt_tz.tzinfo))
# Timezone Crap
# -------------
@property
@@ -223,16 +215,6 @@ class MayaDT(object):
"""Returns MayaDT instance from iso8601 string."""
return parse(iso8601_string)
@classmethod
def from_long_count(klass, long_count_string):
"""Returns MayaDT instance from Maya Long Count string."""
days_since_creation = -1856305
factors = (144000, 7200, 360, 20, 1)
for i, value in enumerate(long_count_string.split('.')):
days_since_creation += int(value) * factors[i]
days_since_creation *= 3600 * 24
return klass(epoch=days_since_creation)
@staticmethod
def from_rfc2822(rfc2822_string):
"""Returns MayaDT instance from rfc2822 string."""
@@ -257,10 +239,7 @@ class MayaDT(object):
if to_timezone:
dt = self.datetime().astimezone(pytz.timezone(to_timezone))
else:
try:
dt = Datetime.utcfromtimestamp(self._epoch)
except: # Fallback for before year 1970 issue
dt = Datetime.utcfromtimestamp(0) + timedelta(microseconds=self._epoch*1000000)
dt = Datetime.utcfromtimestamp(self._epoch)
dt.replace(tzinfo=self._tz)
# Strip the timezone info if requested to do so.
if naive:
@@ -293,22 +272,6 @@ class MayaDT(object):
"""Returns an RFC 3339 representation of the MayaDT."""
return self.datetime().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-5] + "Z"
def long_count(self):
"""Returns a Mayan Long Count representation of the Maya DT."""
# Creation (0.0.0.0.0) occurred on -3114-08-11
# 1856305 is distance (in days) between Creation and UNIX epoch
days_since_creation = int(1856305 + self._epoch / (3600 * 24))
caps = (0, 20, 20, 18, 20)
lc_date = [0, 0, 0, 0, days_since_creation]
for i in range(4, 0, -1):
if lc_date[i] >= caps[i]:
lc_date[i - 1] += int(lc_date[i] / caps[i])
lc_date[i] %= caps[i]
elif lc_date[i] < 0:
lc_date[i - 1] += int(lc_date[i] / caps[i])
lc_date[i] = 0
return '.'.join(str(i) for i in lc_date)
# Properties
# ----------
@property
@@ -375,7 +338,7 @@ class MayaDT(object):
except KeyError:
pass
delta = humanize.time._abs_timedelta(
delta = humanize.time.abs_timedelta(
timedelta(seconds=(self.epoch - now().epoch))
)
@@ -616,7 +579,7 @@ class MayaInterval(object):
start += duration
def quantize(self, duration, snap_out=False, timezone="UTC"):
"""Returns a quantized interval."""
"""Returns a quanitzed interval."""
# Convert seconds to timedelta, if appropriate.
duration = _seconds_or_timedelta(duration)
timezone = pytz.timezone(timezone)
@@ -724,7 +687,7 @@ def when(string, timezone="UTC", prefer_dates_from="current_period"):
Keyword Arguments:
string -- string to be parsed
timezone -- timezone referenced from (default: 'UTC')
prefer_dates_from -- what dates are preferred when `string` is ambiguous.
prefer_dates_from -- what dates are prefered when `string` is ambigous.
options are 'past', 'future', and 'current_period'
(default: 'current_period'). see: [1]
-73
View File
@@ -1,6 +1,3 @@
import datetime
import pytz
from freezegun import freeze_time
import pytest
@@ -26,73 +23,3 @@ def frozen_now(request):
now_string, tz_offset = request.param
with freeze_time(now_string, tz_offset=tz_offset):
yield
@pytest.fixture(params=[
datetime.datetime(2020, 8, 10, 22, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 10, 23, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 0, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 1, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 2, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 3, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 4, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 5, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 6, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 7, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 8, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 9, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 10, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 11, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 12, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 13, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 14, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 15, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 16, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 17, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 18, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 19, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 20, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 8, 11, 21, 2, 0, tzinfo=pytz.timezone('UTC')),
], ids=str)
def frozen_2020_08_11_in_paris(request):
"""
fixture setting datetime.now() to every hour of the 11th of august 2020 in Paris
(summer time, GMT+2)
"""
with freeze_time(request.param):
yield
@pytest.fixture(params=[
datetime.datetime(2020, 2, 10, 23, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 0, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 1, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 2, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 3, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 4, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 5, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 6, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 7, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 8, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 9, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 10, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 11, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 12, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 13, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 14, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 15, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 16, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 17, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 18, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 19, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 20, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 21, 2, 0, tzinfo=pytz.timezone('UTC')),
datetime.datetime(2020, 2, 11, 22, 2, 0, tzinfo=pytz.timezone('UTC')),
], ids=str)
def frozen_2020_02_11_in_paris(request):
"""
fixture setting datetime.now() to every hour of the 11th of february 2020 in Paris
(winter time, GMT+1)
"""
with freeze_time(request.param):
yield
-93
View File
@@ -30,21 +30,6 @@ def test_iso8601(string, expected):
assert r == d.iso8601()
@pytest.mark.parametrize(
"string,expected",
[
('January 1, 1970', "12.17.16.7.5"),
('December 21, 2012', "13.0.0.0.0"),
('March 4, 1900', "12.14.5.10.0"),
],
)
def test_long_count(string, expected):
r = maya.parse(string).long_count()
d = maya.MayaDT.from_long_count(r)
assert r == expected
assert r == d.long_count()
@pytest.mark.parametrize(
"string,expected",
[
@@ -86,28 +71,6 @@ def test_issue_104():
t = maya.MayaDT.from_struct(t)
assert str(t) == "Wed, 11 Oct 2017 21:12:11 GMT"
def test_before_1970():
d1 = maya.when("1899-17-11 08:09:10")
assert d1.year == 1899
assert d1.month == 11
assert d1.day == 17
assert d1.week == 46
assert d1.weekday == 5
assert d1.hour == 8
assert d1.minute == 9
assert d1.second == 10
assert d1.microsecond == 0
# Test properties for maya.parse()
d2 = maya.parse("February 29, 1904 13:12:34")
assert d2.year == 1904
assert d2.month == 2
assert d2.day == 29
assert d2.week == 9
assert d2.weekday == 1
assert d2.hour == 13
assert d2.minute == 12
assert d2.second == 34
assert d2.microsecond == 0
def test_human_when():
r1 = maya.when("yesterday")
@@ -115,42 +78,6 @@ def test_human_when():
assert (r2.day - r1.day) in (1, -30, -29, -28, -27)
@pytest.mark.usefixtures("frozen_2020_08_11_in_paris")
def test_human_when_today_with_timezone_summer_time():
d = maya.when("today", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris").date()) == '2020-08-11'
@pytest.mark.usefixtures("frozen_2020_02_11_in_paris")
def test_human_when_today_with_timezone_winter_time():
d = maya.when("today", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris").date()) == '2020-02-11'
@pytest.mark.usefixtures("frozen_2020_08_11_in_paris")
def test_human_when_yesterday_with_timezone_summer_time():
d = maya.when("yesterday", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris").date()) == '2020-08-10'
@pytest.mark.usefixtures("frozen_2020_02_11_in_paris")
def test_human_when_yesterday_with_timezone_winter_time():
d = maya.when("yesterday", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris").date()) == '2020-02-10'
@pytest.mark.usefixtures("frozen_2020_08_11_in_paris")
def test_human_when_midnight_with_timezone_summer_time():
d = maya.when("midnight", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris")) == '2020-08-11 00:00:00+02:00'
@pytest.mark.usefixtures("frozen_2020_02_11_in_paris")
def test_human_when_midnight_with_timezone_winter_time():
d = maya.when("midnight", timezone='Europe/Paris')
assert str(d.datetime(to_timezone="Europe/Paris")) == '2020-02-11 00:00:00+01:00'
def test_machine_parse():
r1 = maya.parse("August 14, 2015")
assert r1.day == 14
@@ -441,23 +368,3 @@ def test_snaptime(when_str, snap_str, expected_when):
dt = dt.snap(snap_str)
# then
assert dt == maya.when(expected_when)
@pytest.mark.parametrize(
"when_str,snap_str,timezone,expected_when",
[
(
"Mon, 21 Feb 1994 21:21:42 GMT",
"@d",
"Australia/Perth",
"Mon, 21 Feb 1994 16:00:00 GMT",
)
],
)
def test_snaptime_tz(when_str, snap_str, timezone, expected_when):
# given
dt = maya.when(when_str)
# when
dt = dt.snap_tz(snap_str, timezone)
# then
assert dt == maya.when(expected_when)