Created to be used in a project, this package is published to github for ease of management and installation across different modules.
Install from PyPi
pip install cytimesInstall from github
pip install git+https://github.com/AresJef/cyTimes.gitSupports Python 3.10 and above.
cyTimes introduces two classes that simplify and enhance working with datetimes:
Pydt(Pythondatetime.datetime)Pddt(PandasDatetimeIndex)
Both provide similar functionalities:
- Direct drop-in replacements (subclasses) for standard Python
datetimeand PandasDatetimeIndex. - Cython-optimized for high-performance parsing, creation, and calendar manipulation (shifting & replacing).
- Flexible constructors accepting multiple input formats (strings, datetime objects, timestamps, etc.).
- Rich conversion options (ISO strings, ordinals, timestamps, and more).
- Comprehensive manipulation for precise datetime fields adjustments (years, quarters, months, days, time).
- Direct calendar information insights (e.g., days in month, leap years).
- Extended timezone-related capabilities.
- Supports adding or subtracting deltas, and compute delta difference against datetime-like object(s).
The Pydt class is drop-in replacement for Python’s native datetime.datetime, with additional functionalities.
from cytimes import Pydt
import datetime, numpy as np
Pydt(1970, 1, 1, tzinfo="UTC")
>>> 1970-01-01 00:00:00+0000
Pydt.parse("1970 Jan 1 00:00:01 PM")
>>> 1970-01-01 12:00:01
Pydt.now()
>>> 2024-12-06 10:37:25.619593
Pydt.utcnow()
>>> 2024-12-06 09:37:36.743159+0000
Pydt.combine("1970-01-01", "00:00:01")
>>> 1970-01-01 00:00:01
Pydt.fromordinal(1)
>>> 0001-01-01 00:00:00
Pydt.fromseconds(1)
>>> 1970-01-01 00:00:01
Pydt.frommicroseconds(1)
>>> 1970-01-01 00:00:00.000001
Pydt.fromtimestamp(1, datetime.UTC)
>>> 1970-01-01 00:00:01+0000
Pydt.utcfromtimestamp(1)
>>> 1970-01-01 00:00:01+0000
Pydt.fromisoformat("1970-01-01T00:00:01")
>>> 1970-01-01 00:00:01
Pydt.fromisocalendar(1970, 1, 4)
>>> 1970-01-01 00:00:00
Pydt.fromdayofyear(1970, 1)
>>> 1970-01-01 00:00:00
Pydt.fromdate(datetime.date(1970, 1, 1))
>>> 1970-01-01 00:00:00
Pydt.fromdatetime(datetime.datetime(1970, 1, 1))
>>> 1970-01-01 00:00:00
Pydt.fromdatetime64(np.datetime64(1, "s"))
>>> 1970-01-01 00:00:01
Pydt.strptime("00:00:01 1970-01-01", "%H:%M:%S %Y-%m-%d")
>>> 1970-01-01 00:00:01from cytimes import Pydt
dt = Pydt(1970, 1, 1, tzinfo="CET")
dt.ctime()
>>> "Thu Jan 1 00:00:00 1970"
dt.strftime("%Y-%m-%d %H:%M:%S %Z")
>>> "1970-01-01 00:00:00 CET"
dt.isoformat()
>>> "1970-01-01T00:00:00+01:00"
dt.timetuple()
>>> (1970, 1, 1, 0, 0, 0, 3, 1, 0)
dt.toordinal()
>>> 719163
dt.toseconds()
>>> 0.0
dt.tomicroseconds()
>>> 0
dt.timestamp()
>>> -3600.0
dt.date()
>>> 1970-01-01
dt.time()
>>> 00:00:00
dt.timetz()
>>> 00:00:00from cytimes import Pydt
dt = Pydt(1970, 2, 2, 2, 2, 2, 2, "CET")
# . replace
dt.replace(year=2007, microsecond=1, tzinfo="UTC")
>>> 2007-02-02 02:02:02.000001+0000
# . year
dt.to_curr_year(3, 15)
>>> 1970-03-15 02:02:02.000002+0100
dt.to_prev_year("Feb", 30)
>>> 1969-02-28 02:02:02.000002+0100
dt.to_next_year("十二月", 31)
>>> 1971-12-31 02:02:02.000002+0100
dt.to_year(100, "noviembre", 30)
>>> 2070-11-30 02:02:02.000002+0100
# . quarter
dt.to_curr_quarter(3, 15)
>>> 1970-03-15 02:02:02.000002+0100
dt.to_prev_quarter(3, 15)
>>> 1969-12-15 02:02:02.000002+0100
dt.to_next_quarter(3, 15)
>>> 1970-06-15 02:02:02.000002+0100
dt.to_quarter(100, 3, 15)
>>> 1995-03-15 02:02:02.000002+0100
# . month
dt.to_curr_month(15)
>>> 1970-02-15 02:02:02.000002+0100
dt.to_prev_month(15)
>>> 1970-01-15 02:02:02.000002+0100
dt.to_next_month(15)
>>> 1970-03-15 02:02:02.000002+0100
dt.to_month(100, 15)
>>> 1978-06-15 02:02:02.000002+0200
# . weekday
dt.to_monday()
>>> 1970-02-02 02:02:02.000002+0100
dt.to_sunday()
>>> 1970-02-08 02:02:02.000002+0100
dt.to_curr_weekday(4)
>>> 1970-02-06 02:02:02.000002+0100
dt.to_prev_weekday(4)
>>> 1970-01-30 02:02:02.000002+0100
dt.to_next_weekday(4)
>>> 1970-02-13 02:02:02.000002+0100
dt.to_weekday(100, 4)
>>> 1972-01-07 02:02:02.000002+0100
# . day
dt.to_yesterday()
>>> 1970-02-01 02:02:02.000002+0100
dt.to_tomorrow()
>>> 1970-02-03 02:02:02.000002+0100
dt.to_day(100)
>>> 1970-05-13 02:02:02.000002+0100
# . date&time
dt.to_first_of("Y")
>>> 1970-01-01 02:02:02.000002+0100
dt.to_last_of("Q")
>>> 1970-03-31 02:02:02.000002+0100
dt.to_start_of("M")
>>> 1970-02-01 00:00:00+0100
dt.to_end_of("W")
>>> 1970-02-08 23:59:59.999999+0100
dt.to_first_of("Y").is_first_of("Y")
>>> True
dt.to_last_of("Q").is_last_of("Q")
>>> True
dt.to_start_of("M").is_start_of("M")
>>> True
dt.to_end_of("W").is_end_of("W")
>>> True
# . round / ceil / floor
dt.round("h")
>>> 1970-02-02 02:00:00+0100
dt.ceil("m")
>>> 1970-02-02 02:03:00+0100
dt.floor("s")
>>> 1970-02-02 02:02:02+0100from cytimes import Pydt
dt = Pydt(1970, 2, 2, tzinfo="UTC")
# . iso
dt.isocalendar()
>>> {'year': 1970, 'week': 6, 'weekday': 1}
dt.isoyear()
>>> 1970
dt.isoweek()
>>> 6
dt.isoweekday()
>>> 1
# . year
dt.is_leap_year()
>>> False
dt.is_long_year()
>>> True
dt.leap_bt_year(2007)
>>> 9
dt.days_in_year()
>>> 365
dt.days_bf_year()
>>> 719162
dt.days_of_year()
>>> 33
dt.is_year(1970)
>>> True
# . quarter
dt.days_in_quarter()
>>> 90
dt.days_bf_quarter()
>>> 0
dt.days_of_quarter()
>>> 33
dt.is_quarter(1)
>>> True
# . month
dt.days_in_month()
>>> 28
dt.days_bf_month()
>>> 31
dt.days_of_month()
>>> 2
dt.is_month("Feb")
>>> True
dt.month_name("es")
>>> "febrero"
# . weekday
dt.is_weekday("Monday")
>>> True
dt.weekday_name("fr")
>>> "lundi"
# . day
dt.is_day(2)
>>> Truefrom cytimes import Pydt
dt = Pydt(1970, 1, 1, tzinfo="UTC")
dt.is_local()
>>> False
dt.is_utc()
>>> True
dt.is_dst()
>>> False
dt.tzname()
>>> "UTC"
dt.utcoffset()
>>> 0:00:00
dt.utcoffset_seconds()
>>> 0
dt.dst()
>>> None
dt.astimezone("CET")
>>> 1970-01-01 01:00:00+0100
dt.tz_localize(None)
>>> 1970-01-01 00:00:00
dt.tz_convert("CET")
>>> 1970-01-01 01:00:00+0100
dt.tz_switch("CET")
>>> 1970-01-01 01:00:00+0100from cytimes import Pydt
dt = Pydt(1970, 1, 1, tzinfo="UTC")
dt.add(years=1, weeks=1, microseconds=1)
>>> 1971-01-08 00:00:00.000001+0000
dt.sub(quarters=1, days=1, seconds=1)
>>> 1969-09-29 23:59:59+0000
dt.diff("2007-01-01 01:01:01+01:00", "s")
>>> -1167609662from cytimes import Pydt
dt = Pydt(1970, 1, 1)
dt.is_past()
>>> True
dt.is_future()
>>> FalsePddt extends similar functionalities to Pandas DatetimeIndex, making it behave more like native Python datetime.datetime and Pydt, but for arrays of datetime values. It supports:
- Vectorized parsing, creation, and calendar manipulation (shifting & replacing).
- Provides the same functionalities as
Pydt(see examples above), but for datetime index. Pddtisdatetime64[us]focused. It will try to retain nanosecond resolution when possible, but will automatically downcast to microsecond resolution if the value exceeds the bounds ofdatetime64[ns]. This behavior applies to allPddtmethods.
By default, DatetimeIndex uses nanosecond precision 'ns', which cannot represent datetimes outside the range 1677-09-21 to 2262-04-11. Pddt automatically downcasts to microseconds us when encountering out-of-range datetimes, sacrificing nanosecond precision to allow a broader range support.
from cytimes import Pddt
# 1970-01-01: datetime64[ns]
Pddt(["1970-01-01 00:00:00+00:00", "1970-01-02 00:00:00+00:00"])
>>> Pddt(['1970-01-01 00:00:00+00:00', '1970-01-02 00:00:00+00:00'],
dtype='datetime64[ns, UTC]', freq=None)
# 9999-01-01: datetime64[us]
Pddt(["9999-01-01 00:00:00+00:00", "9999-01-02 00:00:00+00:00"])
>>> Pddt(['9999-01-01 00:00:00+00:00', '9999-01-02 00:00:00+00:00'],
dtype='datetime64[us, UTC]', freq=None)Downcasting mechanism also automacially applies to all methods that modifies the date & time when the resulting values are out of the 'ns' range:
from cytimes import Pddt
# 1970-01-01: datetime64[ns]
pt = Pddt(["1970-01-01 00:00:00+00:00", "1970-01-02 00:00:00+00:00"])
>>> Pddt(['1970-01-01 00:00:00+00:00', '1970-01-02 00:00:00+00:00'],
dtype='datetime64[ns, UTC]', freq=None)
# add 1000 years: datetime64[us]
pt.to_year(1000, "Feb", 30)
>>> Pddt(['2970-02-28 00:00:00+00:00', '2970-02-28 00:00:00+00:00'],
dtype='datetime64[us, UTC]', freq=None)cyTimes is based on several open-source repositories.
cyTimes is built on the following open-source repositories:
-
Class
<'Parser'>and<'Delta'>in this package are the cythonized version of<'dateutil.parser'>and<'dateutil.relativedelta'>. Credit and thanks go to the original authors and contributors of thedateutillibrary.