diff options
Diffstat (limited to 'pendulum/__init__.py')
-rw-r--r-- | pendulum/__init__.py | 678 |
1 files changed, 363 insertions, 315 deletions
diff --git a/pendulum/__init__.py b/pendulum/__init__.py index a85ed88..4491244 100644 --- a/pendulum/__init__.py +++ b/pendulum/__init__.py @@ -1,315 +1,363 @@ -from __future__ import absolute_import
-
-import datetime as _datetime
-
-from typing import Optional
-from typing import Union
-
-from .__version__ import __version__
-from .constants import DAYS_PER_WEEK
-from .constants import FRIDAY
-from .constants import HOURS_PER_DAY
-from .constants import MINUTES_PER_HOUR
-from .constants import MONDAY
-from .constants import MONTHS_PER_YEAR
-from .constants import SATURDAY
-from .constants import SECONDS_PER_DAY
-from .constants import SECONDS_PER_HOUR
-from .constants import SECONDS_PER_MINUTE
-from .constants import SUNDAY
-from .constants import THURSDAY
-from .constants import TUESDAY
-from .constants import WEDNESDAY
-from .constants import WEEKS_PER_YEAR
-from .constants import YEARS_PER_CENTURY
-from .constants import YEARS_PER_DECADE
-from .date import Date
-from .datetime import DateTime
-from .duration import Duration
-from .formatting import Formatter
-from .helpers import format_diff
-from .helpers import get_locale
-from .helpers import get_test_now
-from .helpers import has_test_now
-from .helpers import locale
-from .helpers import set_locale
-from .helpers import set_test_now
-from .helpers import test
-from .helpers import week_ends_at
-from .helpers import week_starts_at
-from .parser import parse
-from .period import Period
-from .time import Time
-from .tz import POST_TRANSITION
-from .tz import PRE_TRANSITION
-from .tz import TRANSITION_ERROR
-from .tz import UTC
-from .tz import local_timezone
-from .tz import set_local_timezone
-from .tz import test_local_timezone
-from .tz import timezone
-from .tz import timezones
-from .tz.timezone import Timezone as _Timezone
-from .utils._compat import _HAS_FOLD
-
-
-_TEST_NOW = None # type: Optional[DateTime]
-_LOCALE = "en"
-_WEEK_STARTS_AT = MONDAY
-_WEEK_ENDS_AT = SUNDAY
-
-_formatter = Formatter()
-
-
-def _safe_timezone(obj):
- # type: (Optional[Union[str, float, _datetime.tzinfo, _Timezone]]) -> _Timezone
- """
- Creates a timezone instance
- from a string, Timezone, TimezoneInfo or integer offset.
- """
- if isinstance(obj, _Timezone):
- return obj
-
- if obj is None or obj == "local":
- return local_timezone()
-
- if isinstance(obj, (int, float)):
- obj = int(obj * 60 * 60)
- elif isinstance(obj, _datetime.tzinfo):
- # pytz
- if hasattr(obj, "localize"):
- obj = obj.zone
- elif obj.tzname(None) == "UTC":
- return UTC
- else:
- offset = obj.utcoffset(None)
-
- if offset is None:
- offset = _datetime.timedelta(0)
-
- obj = int(offset.total_seconds())
-
- return timezone(obj)
-
-
-# Public API
-def datetime(
- year, # type: int
- month, # type: int
- day, # type: int
- hour=0, # type: int
- minute=0, # type: int
- second=0, # type: int
- microsecond=0, # type: int
- tz=UTC, # type: Optional[Union[str, float, _Timezone]]
- dst_rule=POST_TRANSITION, # type: str
-): # type: (...) -> DateTime
- """
- Creates a new DateTime instance from a specific date and time.
- """
- if tz is not None:
- tz = _safe_timezone(tz)
-
- if not _HAS_FOLD:
- dt = naive(year, month, day, hour, minute, second, microsecond)
- else:
- dt = _datetime.datetime(year, month, day, hour, minute, second, microsecond)
- if tz is not None:
- dt = tz.convert(dt, dst_rule=dst_rule)
-
- return DateTime(
- dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second,
- dt.microsecond,
- tzinfo=dt.tzinfo,
- fold=dt.fold,
- )
-
-
-def local(
- year, month, day, hour=0, minute=0, second=0, microsecond=0
-): # type: (int, int, int, int, int, int, int) -> DateTime
- """
- Return a DateTime in the local timezone.
- """
- return datetime(
- year, month, day, hour, minute, second, microsecond, tz=local_timezone()
- )
-
-
-def naive(
- year, month, day, hour=0, minute=0, second=0, microsecond=0
-): # type: (int, int, int, int, int, int, int) -> DateTime
- """
- Return a naive DateTime.
- """
- return DateTime(year, month, day, hour, minute, second, microsecond)
-
-
-def date(year, month, day): # type: (int, int, int) -> Date
- """
- Create a new Date instance.
- """
- return Date(year, month, day)
-
-
-def time(hour, minute=0, second=0, microsecond=0): # type: (int, int, int, int) -> Time
- """
- Create a new Time instance.
- """
- return Time(hour, minute, second, microsecond)
-
-
-def instance(
- dt, tz=UTC
-): # type: (_datetime.datetime, Optional[Union[str, _Timezone]]) -> DateTime
- """
- 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
-
- # Checking for pytz/tzinfo
- if isinstance(tz, _datetime.tzinfo) and not isinstance(tz, _Timezone):
- # pytz
- if hasattr(tz, "localize") and tz.zone:
- tz = tz.zone
- else:
- # We have no sure way to figure out
- # the timezone name, we fallback
- # on a fixed offset
- tz = tz.utcoffset(dt).total_seconds() / 3600
-
- return datetime(
- dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tz=tz
- )
-
-
-def now(tz=None): # type: (Optional[Union[str, _Timezone]]) -> DateTime
- """
- Get a DateTime instance for the current date and time.
- """
- if has_test_now():
- test_instance = get_test_now()
- _tz = _safe_timezone(tz)
-
- if tz is not None and _tz != test_instance.timezone:
- test_instance = test_instance.in_tz(_tz)
-
- return test_instance
-
- if tz is None or tz == "local":
- dt = _datetime.datetime.now(local_timezone())
- elif tz is UTC or tz == "UTC":
- dt = _datetime.datetime.now(UTC)
- else:
- dt = _datetime.datetime.now(UTC)
- tz = _safe_timezone(tz)
- dt = tz.convert(dt)
-
- return DateTime(
- dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second,
- dt.microsecond,
- tzinfo=dt.tzinfo,
- fold=dt.fold if _HAS_FOLD else 0,
- )
-
-
-def today(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
- """
- Create a DateTime instance for today.
- """
- return now(tz).start_of("day")
-
-
-def tomorrow(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
- """
- Create a DateTime instance for today.
- """
- return today(tz).add(days=1)
-
-
-def yesterday(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
- """
- Create a DateTime instance for today.
- """
- return today(tz).subtract(days=1)
-
-
-def from_format(
- string, fmt, tz=UTC, locale=None, # noqa
-): # type: (str, str, Union[str, _Timezone], Optional[str]) -> DateTime
- """
- Creates a DateTime instance from a specific format.
- """
- parts = _formatter.parse(string, fmt, now(), locale=locale)
- if parts["tz"] is None:
- parts["tz"] = tz
-
- return datetime(**parts)
-
-
-def from_timestamp(
- timestamp, tz=UTC
-): # type: (Union[int, float], Union[str, _Timezone]) -> DateTime
- """
- Create a DateTime instance from a timestamp.
- """
- dt = _datetime.datetime.utcfromtimestamp(timestamp)
-
- dt = datetime(
- dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond
- )
-
- if tz is not UTC or tz != "UTC":
- dt = dt.in_timezone(tz)
-
- return dt
-
-
-def duration(
- days=0, # type: float
- seconds=0, # type: float
- microseconds=0, # type: float
- milliseconds=0, # type: float
- minutes=0, # type: float
- hours=0, # type: float
- weeks=0, # type: float
- years=0, # type: float
- months=0, # type: float
-): # type: (...) -> Duration
- """
- Create a Duration instance.
- """
- return Duration(
- days=days,
- seconds=seconds,
- microseconds=microseconds,
- milliseconds=milliseconds,
- minutes=minutes,
- hours=hours,
- weeks=weeks,
- years=years,
- months=months,
- )
-
-
-def period(start, end, absolute=False): # type: (DateTime, DateTime, bool) -> Period
- """
- Create a Period instance.
- """
- return Period(start, end, absolute=absolute)
+from __future__ import annotations + +import datetime as _datetime + +from typing import Union +from typing import cast + +from pendulum.__version__ import __version__ +from pendulum.constants import DAYS_PER_WEEK +from pendulum.constants import FRIDAY +from pendulum.constants import HOURS_PER_DAY +from pendulum.constants import MINUTES_PER_HOUR +from pendulum.constants import MONDAY +from pendulum.constants import MONTHS_PER_YEAR +from pendulum.constants import SATURDAY +from pendulum.constants import SECONDS_PER_DAY +from pendulum.constants import SECONDS_PER_HOUR +from pendulum.constants import SECONDS_PER_MINUTE +from pendulum.constants import SUNDAY +from pendulum.constants import THURSDAY +from pendulum.constants import TUESDAY +from pendulum.constants import WEDNESDAY +from pendulum.constants import WEEKS_PER_YEAR +from pendulum.constants import YEARS_PER_CENTURY +from pendulum.constants import YEARS_PER_DECADE +from pendulum.date import Date +from pendulum.datetime import DateTime +from pendulum.duration import Duration +from pendulum.formatting import Formatter +from pendulum.helpers import format_diff +from pendulum.helpers import get_locale +from pendulum.helpers import locale +from pendulum.helpers import set_locale +from pendulum.helpers import week_ends_at +from pendulum.helpers import week_starts_at +from pendulum.interval import Interval +from pendulum.parser import parse +from pendulum.testing.traveller import Traveller +from pendulum.time import Time +from pendulum.tz import UTC +from pendulum.tz import local_timezone +from pendulum.tz import set_local_timezone +from pendulum.tz import test_local_timezone +from pendulum.tz import timezone +from pendulum.tz import timezones +from pendulum.tz.timezone import FixedTimezone +from pendulum.tz.timezone import Timezone + +_TEST_NOW: DateTime | None = None +_LOCALE = "en" +_WEEK_STARTS_AT = MONDAY +_WEEK_ENDS_AT = SUNDAY + +_formatter = Formatter() + + +def _safe_timezone( + obj: str | float | _datetime.tzinfo | Timezone | FixedTimezone | None, + dt: _datetime.datetime | None = None, +) -> Timezone | FixedTimezone: + """ + Creates a timezone instance + from a string, Timezone, TimezoneInfo or integer offset. + """ + if isinstance(obj, (Timezone, FixedTimezone)): + return obj + + if obj is None or obj == "local": + return local_timezone() + + if isinstance(obj, (int, float)): + obj = int(obj * 60 * 60) + elif isinstance(obj, _datetime.tzinfo): + # zoneinfo + if hasattr(obj, "key"): + obj = obj.key # type: ignore + # pytz + elif hasattr(obj, "localize"): + obj = obj.zone # type: ignore + elif obj.tzname(None) == "UTC": + return UTC + else: + offset = obj.utcoffset(dt) + + if offset is None: + offset = _datetime.timedelta(0) + + obj = int(offset.total_seconds()) + + obj = cast(Union[str, int], obj) + + return timezone(obj) + + +# Public API +def datetime( + year: int, + month: int, + day: int, + hour: int = 0, + minute: int = 0, + second: int = 0, + microsecond: int = 0, + tz: str | float | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC, + fold: int = 1, + raise_on_unknown_times: bool = False, +) -> DateTime: + """ + Creates a new DateTime instance from a specific date and time. + """ + return DateTime.create( + year, + month, + day, + hour=hour, + minute=minute, + second=second, + microsecond=microsecond, + tz=tz, + fold=fold, + raise_on_unknown_times=raise_on_unknown_times, + ) + + +def local( + year: int, + month: int, + day: int, + hour: int = 0, + minute: int = 0, + second: int = 0, + microsecond: int = 0, +) -> DateTime: + """ + Return a DateTime in the local timezone. + """ + return datetime( + year, month, day, hour, minute, second, microsecond, tz=local_timezone() + ) + + +def naive( + year: int, + month: int, + day: int, + hour: int = 0, + minute: int = 0, + second: int = 0, + microsecond: int = 0, + fold: int = 1, +) -> DateTime: + """ + Return a naive DateTime. + """ + return DateTime(year, month, day, hour, minute, second, microsecond, fold=fold) + + +def date(year: int, month: int, day: int) -> Date: + """ + Create a new Date instance. + """ + return Date(year, month, day) + + +def time(hour: int, minute: int = 0, second: int = 0, microsecond: int = 0) -> Time: + """ + Create a new Time instance. + """ + return Time(hour, minute, second, microsecond) + + +def instance( + dt: _datetime.datetime, + tz: str | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC, +) -> DateTime: + """ + 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), + ) + + +def now(tz: str | Timezone | None = None) -> DateTime: + """ + Get a DateTime instance for the current date and time. + """ + return DateTime.now(tz) + + +def today(tz: str | Timezone = "local") -> DateTime: + """ + Create a DateTime instance for today. + """ + return now(tz).start_of("day") + + +def tomorrow(tz: str | Timezone = "local") -> DateTime: + """ + Create a DateTime instance for today. + """ + return today(tz).add(days=1) + + +def yesterday(tz: str | Timezone = "local") -> DateTime: + """ + Create a DateTime instance for today. + """ + return today(tz).subtract(days=1) + + +def from_format( + string: str, + fmt: str, + tz: str | Timezone = UTC, + locale: str | None = None, +) -> DateTime: + """ + Creates a DateTime instance from a specific format. + """ + parts = _formatter.parse(string, fmt, now(tz=tz), locale=locale) + if parts["tz"] is None: + parts["tz"] = tz + + return datetime(**parts) + + +def from_timestamp(timestamp: int | float, tz: str | Timezone = UTC) -> DateTime: + """ + Create a DateTime instance from a timestamp. + """ + dt = _datetime.datetime.utcfromtimestamp(timestamp) + + dt = datetime( + dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond + ) + + if tz is not UTC or tz != "UTC": + dt = dt.in_timezone(tz) + + return dt + + +def duration( + days: float = 0, + seconds: float = 0, + microseconds: float = 0, + milliseconds: float = 0, + minutes: float = 0, + hours: float = 0, + weeks: float = 0, + years: float = 0, + months: float = 0, +) -> Duration: + """ + Create a Duration instance. + """ + return Duration( + days=days, + seconds=seconds, + microseconds=microseconds, + milliseconds=milliseconds, + minutes=minutes, + hours=hours, + weeks=weeks, + years=years, + months=months, + ) + + +def interval(start: DateTime, end: DateTime, absolute: bool = False) -> Interval: + """ + Create an Interval instance. + """ + return Interval(start, end, absolute=absolute) + + +# Testing + +_traveller = Traveller(DateTime) + +freeze = _traveller.freeze +travel = _traveller.travel +travel_to = _traveller.travel_to +travel_back = _traveller.travel_back + +__all__ = [ + "__version__", + "DAYS_PER_WEEK", + "FRIDAY", + "HOURS_PER_DAY", + "MINUTES_PER_HOUR", + "MONDAY", + "MONTHS_PER_YEAR", + "SATURDAY", + "SECONDS_PER_DAY", + "SECONDS_PER_HOUR", + "SECONDS_PER_MINUTE", + "SUNDAY", + "THURSDAY", + "TUESDAY", + "WEDNESDAY", + "WEEKS_PER_YEAR", + "YEARS_PER_CENTURY", + "YEARS_PER_DECADE", + "Date", + "DateTime", + "Duration", + "Formatter", + "date", + "datetime", + "duration", + "format_diff", + "freeze", + "from_format", + "from_timestamp", + "get_locale", + "instance", + "interval", + "local", + "locale", + "naive", + "now", + "set_locale", + "week_ends_at", + "week_starts_at", + "parse", + "Interval", + "Time", + "UTC", + "local_timezone", + "set_local_timezone", + "test_local_timezone", + "time", + "timezone", + "timezones", + "today", + "tomorrow", + "travel", + "travel_back", + "travel_to", + "FixedTimezone", + "Timezone", + "yesterday", +] |