"""Most of the code derived from Python3.5 's datetime.pyi"""
import sys
import datetime as _actual_datetime

from time import struct_time
from typing import Optional, Tuple, overload, ClassVar, Type, TypeVar


__version__: str
__author__: str

_S = TypeVar("_S")
_A = TypeVar("_A")

_Text = str

MINYEAR: int
MAXYEAR: int

NEPAL_TIME_UTC_OFFSET: int


class tzinfo:
    def tzname(self, dt: Optional[datetime]) -> Optional[str]: ...
    def utcoffset(self, dt: Optional[datetime]) -> Optional[_actual_datetime.timedelta]: ...
    def dst(self, dt: Optional[datetime]) -> Optional[_actual_datetime.timedelta]: ...
    def fromutc(self, dt: datetime) -> datetime: ...


class timezone(tzinfo):
    utc: ClassVar[timezone]
    min: ClassVar[timezone]
    max: ClassVar[timezone]

    def __init__(self, offset: _actual_datetime.timedelta, name: str = ...) -> None: ...
    def __hash__(self) -> int: ...


_tzinfo = tzinfo


class date:
    min: ClassVar[date]
    max: ClassVar[date]
    resolution: ClassVar[_actual_datetime.timedelta]

    def __new__(cls: Type[_S], year: int, month: int, day: int) -> _S: ...

    @classmethod
    def fromtimestamp(cls: Type[_S], __timestamp: float) -> _S: ...
    @classmethod
    def today(cls: Type[_S]) -> _S: ...
    @classmethod
    def fromordinal(cls: Type[_S], n: int) -> _S: ...
    @classmethod
    def from_datetime_date(cls, from_date: _A) -> _S: ...
    def to_datetime_date(self) -> _A: ...
    if sys.version_info >= (3, 7):
        @classmethod
        def fromisoformat(cls: Type[_S], date_string: str) -> _S: ...
    if sys.version_info >= (3, 8):
        @classmethod
        def fromisocalendar(cls: Type[_S], year: int, week: int, day: int) -> _S: ...

    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...

    def ctime(self) -> str: ...
    def strftime(self, fmt: _Text) -> str: ...
    def __format__(self, fmt: str) -> str: ...
    def isoformat(self) -> str: ...
    def timetuple(self) -> struct_time: ...
    def toordinal(self) -> int: ...
    def replace(self, year: int = ..., month: int = ..., day: int = ...) -> date: ...
    def __le__(self, other: date) -> bool: ...
    def __lt__(self, other: date) -> bool: ...
    def __ge__(self, other: date) -> bool: ...
    def __gt__(self, other: date) -> bool: ...
    if sys.version_info >= (3, 8):
        def __add__(self: _S, other: _actual_datetime.timedelta) -> _S: ...
        def __radd__(self: _S, other: _actual_datetime.timedelta) -> _S: ...
    else:
        def __add__(self, other: _actual_datetime.timedelta) -> date: ...
        def __radd__(self, other: _actual_datetime.timedelta) -> date: ...
    @overload
    def __sub__(self, other: _actual_datetime.timedelta) -> date: ...
    @overload
    def __sub__(self, other: date) -> _actual_datetime.timedelta: ...
    def __hash__(self) -> int: ...
    def weekday(self) -> int: ...
    def isoweekday(self) -> int: ...
    def isocalendar(self) -> Tuple[int, int, int]: ...

class time:
    min: ClassVar[time]
    max: ClassVar[time]
    resolution: ClassVar[_actual_datetime.timedelta]

    if sys.version_info >= (3, 6):
        def __init__(self, hour: int = ..., minute: int = ..., second: int = ..., microsecond: int = ...,
                     tzinfo: Optional[_tzinfo] = ..., *, fold: int = ...) -> None: ...
    else:
        def __init__(self, hour: int = ..., minute: int = ..., second: int = ..., microsecond: int = ...,
                     tzinfo: Optional[_tzinfo] = ...) -> None: ...

    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def tzinfo(self) -> Optional[_tzinfo]: ...
    if sys.version_info >= (3, 6):
        @property
        def fold(self) -> int: ...

    def __le__(self, other: time) -> bool: ...
    def __lt__(self, other: time) -> bool: ...
    def __ge__(self, other: time) -> bool: ...
    def __gt__(self, other: time) -> bool: ...
    def __hash__(self) -> int: ...
    if sys.version_info >= (3, 6):
        def isoformat(self, timespec: str = ...) -> str: ...
    else:
        def isoformat(self) -> str: ...
    if sys.version_info >= (3, 7):
        @classmethod
        def fromisoformat(cls: Type[_S], time_string: str) -> _S: ...
    def strftime(self, fmt: _Text) -> str: ...
    def __format__(self, fmt: str) -> str: ...
    def utcoffset(self) -> Optional[_actual_datetime.timedelta]: ...
    def tzname(self) -> Optional[str]: ...
    def dst(self) -> Optional[int]: ...
    if sys.version_info >= (3, 6):
        def replace(self, hour: int = ..., minute: int = ..., second: int = ...,
                    microsecond: int = ..., tzinfo: Optional[_tzinfo] = ...,
                    *, fold: int = ...) -> time: ...
    else:
        def replace(self, hour: int = ..., minute: int = ..., second: int = ...,
                    microsecond: int = ..., tzinfo: Optional[_tzinfo] = ...) -> time: ...


_date = date
_time = time


class datetime(date):
    min: ClassVar[datetime]
    max: ClassVar[datetime]
    resolution: ClassVar[_actual_datetime.timedelta]

    if sys.version_info >= (3, 6):
        def __new__(
            cls: Type[_S],
            year: int,
            month: int,
            day: int,
            hour: int = ...,
            minute: int = ...,
            second: int = ...,
            microsecond: int = ...,
            tzinfo: Optional[_tzinfo] = ...,
            *,
            fold: int = ...,
        ) -> _S: ...
    else:
        def __new__(
            cls: Type[_S],
            year: int,
            month: int,
            day: int,
            hour: int = ...,
            minute: int = ...,
            second: int = ...,
            microsecond: int = ...,
            tzinfo: Optional[_tzinfo] = ...,
        ) -> _S: ...

    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def tzinfo(self) -> Optional[_tzinfo]: ...
    if sys.version_info >= (3, 6):
        @property
        def fold(self) -> int: ...

    @classmethod
    def fromtimestamp(cls: Type[_S], t: float, tz: Optional[_tzinfo] = ...) -> _S: ...
    @classmethod
    def utcfromtimestamp(cls: Type[_S], t: float) -> _S: ...
    @classmethod
    def today(cls: Type[_S]) -> _S: ...
    @classmethod
    def fromordinal(cls: Type[_S], n: int) -> _S: ...
    if sys.version_info >= (3, 8):
        @classmethod
        def now(cls: Type[_S], tz: Optional[_tzinfo] = ...) -> _S: ...
    else:
        @overload
        @classmethod
        def now(cls: Type[_S], tz: None = ...) -> _S: ...
        @overload
        @classmethod
        def now(cls, tz: _tzinfo) -> datetime: ...
    @classmethod
    def utcnow(cls: Type[_S]) -> _S: ...
    if sys.version_info >= (3, 6):
        @classmethod
        def combine(cls, date: _date, time: _time, tzinfo: Optional[_tzinfo] = ...) -> datetime: ...
    else:
        @classmethod
        def combine(cls, date: _date, time: _time) -> datetime: ...
    if sys.version_info >= (3, 7):
        @classmethod
        def fromisoformat(cls: Type[_S], date_string: str) -> _S: ...
    def strftime(self, fmt: _Text) -> str: ...
    def __format__(self, fmt: str) -> str: ...
    def toordinal(self) -> int: ...
    def timetuple(self) -> struct_time: ...
    def timestamp(self) -> float: ...
    def utctimetuple(self) -> struct_time: ...
    def date(self) -> _date: ...
    def time(self) -> _time: ...
    def timetz(self) -> _time: ...
    if sys.version_info >= (3, 6):
        def replace(self, year: int = ..., month: int = ..., day: int = ..., hour: int = ...,
                    minute: int = ..., second: int = ..., microsecond: int = ..., tzinfo:
                    Optional[_tzinfo] = ..., *, fold: int = ...) -> datetime: ...
    else:
        def replace(self, year: int = ..., month: int = ..., day: int = ..., hour: int = ...,
                    minute: int = ..., second: int = ..., microsecond: int = ..., tzinfo:
                    Optional[_tzinfo] = ...) -> datetime: ...
    if sys.version_info >= (3, 8):
        def astimezone(self: _S, tz: Optional[_tzinfo] = ...) -> _S: ...
    elif sys.version_info >= (3, 3):
        def astimezone(self, tz: Optional[_tzinfo] = ...) -> datetime: ...
    else:
        def astimezone(self, tz: _tzinfo) -> datetime: ...
    def ctime(self) -> str: ...
    if sys.version_info >= (3, 6):
        def isoformat(self, sep: str = ..., timespec: str = ...) -> str: ...
    else:
        def isoformat(self, sep: str = ...) -> str: ...
    @classmethod
    def strptime(cls, date_string: _Text, format: _Text) -> datetime: ...
    def utcoffset(self) -> Optional[_actual_datetime.timedelta]: ...
    def tzname(self) -> Optional[str]: ...
    def dst(self) -> Optional[_actual_datetime.timedelta]: ...
    def __le__(self, other: datetime) -> bool: ...  # type: ignore
    def __lt__(self, other: datetime) -> bool: ...  # type: ignore
    def __ge__(self, other: datetime) -> bool: ...  # type: ignore
    def __gt__(self, other: datetime) -> bool: ...  # type: ignore
    if sys.version_info >= (3, 8):
        def __add__(self: _S, other: _actual_datetime.timedelta) -> _S: ...
        def __radd__(self: _S, other: _actual_datetime.timedelta) -> _S: ...
    else:
        def __add__(self, other: _actual_datetime.timedelta) -> datetime: ...
        def __radd__(self, other: _actual_datetime.timedelta) -> datetime: ...
    @overload  # type: ignore
    def __sub__(self, other: datetime) -> _actual_datetime.timedelta: ...
    @overload
    def __sub__(self, other: _actual_datetime.timedelta) -> datetime: ...
    def __hash__(self) -> int: ...
    def weekday(self) -> int: ...
    def isoweekday(self) -> int: ...
    def isocalendar(self) -> Tuple[int, int, int]: ...


class UTC0545(_actual_datetime.tzinfo):
    def utcoffset(self, dt: datetime) -> _actual_datetime.timedelta: ...
    def dst(self, dt: datetime) -> _actual_datetime.timedelta: ...
    def tzname(self, dt: datetime) -> str: ...
    def fromutc(self, dt: datetime) -> datetime: ...
