vacanza / holidays

Generate and work with holidays in Python
https://pypi.org/project/holidays
MIT License
1.45k stars 460 forks source link

Replace `datetime::timedelta` with custom function #1785

Closed KJhellico closed 5 months ago

KJhellico commented 5 months ago

Proposed change

Replace datetime::timedelta with simple custom function for adding and subtracting days.

Performance test script:

from datetime import date, timedelta
import timeit

def _delta_days(dt: date, n: int) -> date:
    return date.fromordinal(dt.toordinal() + n)

def with_timedelta():
    dt = date(2024, 1, 1)
    d2 = dt + timedelta(days=10)

def with_delta_days():
    dt = date(2024, 1, 1)
    d2 = _delta_days(dt, 10)

NUM = 10_000_000

t1 = timeit.timeit(with_timedelta, number=NUM)
t2 = timeit.timeit(with_add_days, number=NUM)

print(f"{NUM} times:")
print(f"timedelta = {t1:.3f}")
print(f"_delta_days = {t2:.3f} ({(t2/t1 - 1)*100:.2f}%)")

Result:

timedelta = 5.492
_add_days = 3.810 (-30.63%)

Type of change

Checklist

coveralls commented 5 months ago

Pull Request Test Coverage Report for Build 9018175993

Details


Totals Coverage Status
Change from base Build 8972750703: 0.0%
Covered Lines: 11064
Relevant Lines: 11064

💛 - Coveralls
KJhellico commented 5 months ago

I tried this, but there is no performance gain.

from datetime import date, timedelta
import timeit

class td:
    def __init__(self, days: int = 0):
        self._days = days

    def __radd__(self, other):
        if isinstance(other, date):
            return date.fromordinal(other.toordinal() + self._days)
        return NotImplemented

    def __rsub__(self, other):
        if isinstance(other, date):
            return date.fromordinal(other.toordinal() - self._days)
        return NotImplemented

def _start_days(dt: date, n: int) -> date:
    return date.fromordinal(dt.toordinal() + n)

def with_timedelta():
    dt = date(2024, 1, 1)
    d2 = dt + timedelta(days=10)

def with_start_days():
    dt = date(2024, 1, 1)
    d2 = _start_days(dt, 10)

def with_class_td():
    dt = date(2024, 1, 1)
    d2 = dt + td(10)

NUM = 10_000_000

t1 = timeit.timeit(with_timedelta, number=NUM)
t2 = timeit.timeit(with_start_days, number=NUM)
t3 = timeit.timeit(with_class_td, number=NUM)

print(f"{NUM} times:")
print(f"timedelta = {t1:.3f}")
print(f"_start_days = {t2:.3f} ({(t2/t1 - 1)*100:.2f}%)")
print(f"class td = {t3:.3f} ({(t3/t1 - 1)*100:.2f}%)")

Result:

10000000 times:
timedelta = 5.534
_start_days = 3.749 (-32.25%)
class td = 5.505 (-0.52%)
sonarcloud[bot] commented 5 months ago

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud