Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 1 addition & 21 deletions pendulum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,27 +206,7 @@ def instance(
"""
Create a DateTime instance from a datetime one.
"""
if not isinstance(dt, _datetime.datetime):
raise ValueError("instance() only accepts datetime objects.")

if isinstance(dt, DateTime):
return dt

tz = dt.tzinfo or tz

if tz is not None:
tz = _safe_timezone(tz, dt=dt)

return datetime(
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second,
dt.microsecond,
tz=cast(Union[str, int, Timezone, FixedTimezone, None], tz),
)
return DateTime._instance(dt, tz)


def now(tz: str | Timezone | None = None) -> DateTime:
Expand Down
84 changes: 57 additions & 27 deletions pendulum/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from typing import Callable
from typing import ClassVar
from typing import Optional
from typing import Union
from typing import cast
from typing import overload

Expand Down Expand Up @@ -123,6 +124,37 @@ def create(
fold=dt.fold,
)

@classmethod
def _instance(
cls,
dt: datetime.datetime,
tz: str | Timezone | FixedTimezone | datetime.tzinfo | None = UTC,
) -> Self:
"""
Create a DateTime instance from a datetime one.
"""
if not isinstance(dt, datetime.datetime):
raise ValueError("instance() only accepts datetime objects.")

if isinstance(dt, cls):
return dt

tz = dt.tzinfo or tz

if tz is not None:
tz = pendulum._safe_timezone(tz, dt=dt)

return cls.create(
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second,
dt.microsecond,
tz=cast(Union[str, int, Timezone, FixedTimezone, None], tz),
)

@overload
@classmethod
def now(cls, tz: datetime.tzinfo | None = None) -> Self:
Expand Down Expand Up @@ -173,8 +205,8 @@ def today(cls) -> Self:
return cls.now()

@classmethod
def strptime(cls, time: str, fmt: str) -> DateTime:
return pendulum.instance(datetime.datetime.strptime(time, fmt))
def strptime(cls, time: str, fmt: str) -> Self:
return cls._instance(datetime.datetime.strptime(time, fmt))

# Getters/Setters

Expand Down Expand Up @@ -473,19 +505,19 @@ def __repr__(self) -> str:
)

# Comparisons
def closest(self, *dts: datetime.datetime) -> DateTime: # type: ignore[override]
def closest(self, *dts: datetime.datetime) -> Self: # type: ignore[override]
"""
Get the farthest date from the instance.
"""
pdts = [pendulum.instance(x) for x in dts]
pdts = [self._instance(x) for x in dts]

return min((abs(self - dt), dt) for dt in pdts)[1]

def farthest(self, *dts: datetime.datetime) -> DateTime: # type: ignore[override]
def farthest(self, *dts: datetime.datetime) -> Self: # type: ignore[override]
"""
Get the farthest date from the instance.
"""
pdts = [pendulum.instance(x) for x in dts]
pdts = [self._instance(x) for x in dts]

return max((abs(self - dt), dt) for dt in pdts)[1]

Expand All @@ -508,7 +540,7 @@ def is_long_year(self) -> bool:
See link `https://en.wikipedia.org/wiki/ISO_8601#Week_dates`_
"""
return (
DateTime.create(self.year, 12, 28, 0, 0, 0, tz=self.tz).isocalendar()[1]
self.create(self.year, 12, 28, 0, 0, 0, tz=self.tz).isocalendar()[1]
== 53
)

Expand All @@ -517,7 +549,7 @@ def is_same_day(self, dt: datetime.datetime) -> bool: # type: ignore[override]
Checks if the passed in date is the same day
as the instance current day.
"""
dt = pendulum.instance(dt)
dt = self._instance(dt)

return self.to_date_string() == dt.to_date_string()

Expand All @@ -531,7 +563,7 @@ def is_anniversary( # type: ignore[override]
if dt is None:
dt = self.now(self.tz)

instance = pendulum.instance(dt)
instance = self._instance(dt)

return (self.month, self.day) == (instance.month, instance.day)

Expand Down Expand Up @@ -1177,7 +1209,7 @@ def __sub__(self, other: datetime.datetime | datetime.timedelta) -> Self | Inter

if not isinstance(other, self.__class__):
if other.tzinfo is None:
other = pendulum.naive(
other = self.__class__(
other.year,
other.month,
other.day,
Expand All @@ -1187,7 +1219,7 @@ def __sub__(self, other: datetime.datetime | datetime.timedelta) -> Self | Inter
other.microsecond,
)
else:
other = pendulum.instance(other)
other = self._instance(other)

return other.diff(self, False)

Expand All @@ -1197,7 +1229,7 @@ def __rsub__(self, other: datetime.datetime) -> Interval:

if not isinstance(other, self.__class__):
if other.tzinfo is None:
other = pendulum.naive(
other = self.__class__(
other.year,
other.month,
other.day,
Expand All @@ -1207,7 +1239,7 @@ def __rsub__(self, other: datetime.datetime) -> Interval:
other.microsecond,
)
else:
other = pendulum.instance(other)
other = self._instance(other)

return self.diff(other, False)

Expand All @@ -1231,29 +1263,27 @@ def __radd__(self, other: datetime.timedelta) -> Self:
# Native methods override

@classmethod
def fromtimestamp(cls, t: float, tz: datetime.tzinfo | None = None) -> DateTime:
def fromtimestamp(cls, t: float, tz: datetime.tzinfo | None = None) -> Self:
tzinfo = pendulum._safe_timezone(tz)

return pendulum.instance(
datetime.datetime.fromtimestamp(t, tz=tzinfo), tz=tzinfo
)
return cls._instance(datetime.datetime.fromtimestamp(t, tz=tzinfo), tz=tzinfo)

@classmethod
def utcfromtimestamp(cls, t: float) -> DateTime:
return pendulum.instance(datetime.datetime.utcfromtimestamp(t), tz=None)
def utcfromtimestamp(cls, t: float) -> Self:
return cls._instance(datetime.datetime.utcfromtimestamp(t), tz=None)

@classmethod
def fromordinal(cls, n: int) -> DateTime:
return pendulum.instance(datetime.datetime.fromordinal(n), tz=None)
def fromordinal(cls, n: int) -> Self:
return cls._instance(datetime.datetime.fromordinal(n), tz=None)

@classmethod
def combine(
cls,
date: datetime.date,
time: datetime.time,
tzinfo: datetime.tzinfo | None = None,
) -> DateTime:
return pendulum.instance(datetime.datetime.combine(date, time), tz=tzinfo)
) -> Self:
return cls._instance(datetime.datetime.combine(date, time), tz=tzinfo)

def astimezone(self, tz: datetime.tzinfo | None = None) -> Self:
dt = super().astimezone(tz)
Expand Down Expand Up @@ -1312,11 +1342,11 @@ def replace(
minute,
second,
microsecond,
tz=tzinfo,
tzinfo=tzinfo,
fold=fold,
)

def __getnewargs__(self) -> tuple[DateTime]:
def __getnewargs__(self) -> tuple[Self]:
return (self,)

def _getstate(
Expand All @@ -1336,14 +1366,14 @@ def _getstate(
def __reduce__(
self,
) -> tuple[
type[DateTime], tuple[int, int, int, int, int, int, int, datetime.tzinfo | None]
type[Self], tuple[int, int, int, int, int, int, int, datetime.tzinfo | None]
]:
return self.__reduce_ex__(2)

def __reduce_ex__(
self, protocol: SupportsIndex
) -> tuple[
type[DateTime], tuple[int, int, int, int, int, int, int, datetime.tzinfo | None]
type[Self], tuple[int, int, int, int, int, int, int, datetime.tzinfo | None]
]:
return self.__class__, self._getstate(protocol)

Expand Down