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)