Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

agriconnect / pandas   python

Repository URL to install this package:

/ core / arrays / datetimes.py

# -*- coding: utf-8 -*-
from datetime import datetime, time, timedelta
import textwrap
import warnings

import numpy as np
from pytz import utc

from pandas._libs import lib, tslib
from pandas._libs.tslibs import (
    NaT, Timestamp, ccalendar, conversion, fields, iNaT, normalize_date,
    resolution as libresolution, timezones)
import pandas.compat as compat
from pandas.errors import PerformanceWarning
from pandas.util._decorators import Appender

from pandas.core.dtypes.common import (
    _INT64_DTYPE, _NS_DTYPE, is_categorical_dtype, is_datetime64_dtype,
    is_datetime64_ns_dtype, is_datetime64tz_dtype, is_dtype_equal,
    is_extension_type, is_float_dtype, is_object_dtype, is_period_dtype,
    is_string_dtype, is_timedelta64_dtype, pandas_dtype)
from pandas.core.dtypes.dtypes import DatetimeTZDtype
from pandas.core.dtypes.generic import (
    ABCDataFrame, ABCIndexClass, ABCPandasArray, ABCSeries)
from pandas.core.dtypes.missing import isna

from pandas.core import ops
from pandas.core.algorithms import checked_add_with_arr
from pandas.core.arrays import datetimelike as dtl
from pandas.core.arrays._ranges import generate_regular_range
import pandas.core.common as com

from pandas.tseries.frequencies import get_period_alias, to_offset
from pandas.tseries.offsets import Day, Tick

_midnight = time(0, 0)
# TODO(GH-24559): Remove warning, int_as_wall_time parameter.
_i8_message = """
    Passing integer-dtype data and a timezone to DatetimeIndex. Integer values
    will be interpreted differently in a future version of pandas. Previously,
    these were viewed as datetime64[ns] values representing the wall time
    *in the specified timezone*. In the future, these will be viewed as
    datetime64[ns] values representing the wall time *in UTC*. This is similar
    to a nanosecond-precision UNIX epoch. To accept the future behavior, use

        pd.to_datetime(integer_data, utc=True).tz_convert(tz)

    To keep the previous behavior, use

        pd.to_datetime(integer_data).tz_localize(tz)
"""


def tz_to_dtype(tz):
    """
    Return a datetime64[ns] dtype appropriate for the given timezone.

    Parameters
    ----------
    tz : tzinfo or None

    Returns
    -------
    np.dtype or Datetime64TZDType
    """
    if tz is None:
        return _NS_DTYPE
    else:
        return DatetimeTZDtype(tz=tz)


def _to_M8(key, tz=None):
    """
    Timestamp-like => dt64
    """
    if not isinstance(key, Timestamp):
        # this also converts strings
        key = Timestamp(key)
        if key.tzinfo is not None and tz is not None:
            # Don't tz_localize(None) if key is already tz-aware
            key = key.tz_convert(tz)
        else:
            key = key.tz_localize(tz)

    return np.int64(conversion.pydt_to_i8(key)).view(_NS_DTYPE)


def _field_accessor(name, field, docstring=None):
    def f(self):
        values = self.asi8
        if self.tz is not None and not timezones.is_utc(self.tz):
            values = self._local_timestamps()

        if field in self._bool_ops:
            if field.endswith(('start', 'end')):
                freq = self.freq
                month_kw = 12
                if freq:
                    kwds = freq.kwds
                    month_kw = kwds.get('startingMonth', kwds.get('month', 12))

                result = fields.get_start_end_field(values, field,
                                                    self.freqstr, month_kw)
            else:
                result = fields.get_date_field(values, field)

            # these return a boolean by-definition
            return result

        if field in self._object_ops:
            result = fields.get_date_name_field(values, field)
            result = self._maybe_mask_results(result, fill_value=None)

        else:
            result = fields.get_date_field(values, field)
            result = self._maybe_mask_results(result, fill_value=None,
                                              convert='float64')

        return result

    f.__name__ = name
    f.__doc__ = "\n{}\n".format(docstring)
    return property(f)


def _dt_array_cmp(cls, op):
    """
    Wrap comparison operations to convert datetime-like to datetime64
    """
    opname = '__{name}__'.format(name=op.__name__)
    nat_result = True if opname == '__ne__' else False

    def wrapper(self, other):
        if isinstance(other, (ABCDataFrame, ABCSeries, ABCIndexClass)):
            return NotImplemented

        other = lib.item_from_zerodim(other)

        if isinstance(other, (datetime, np.datetime64, compat.string_types)):
            if isinstance(other, (datetime, np.datetime64)):
                # GH#18435 strings get a pass from tzawareness compat
                self._assert_tzawareness_compat(other)

            try:
                other = _to_M8(other, tz=self.tz)
            except ValueError:
                # string that cannot be parsed to Timestamp
                return ops.invalid_comparison(self, other, op)

            result = op(self.asi8, other.view('i8'))
            if isna(other):
                result.fill(nat_result)
        elif lib.is_scalar(other) or np.ndim(other) == 0:
            return ops.invalid_comparison(self, other, op)
        elif len(other) != len(self):
            raise ValueError("Lengths must match")
        else:
            if isinstance(other, list):
                try:
                    other = type(self)._from_sequence(other)
                except ValueError:
                    other = np.array(other, dtype=np.object_)
            elif not isinstance(other, (np.ndarray, ABCIndexClass, ABCSeries,
                                        DatetimeArray)):
                # Following Timestamp convention, __eq__ is all-False
                # and __ne__ is all True, others raise TypeError.
                return ops.invalid_comparison(self, other, op)

            if is_object_dtype(other):
                # We have to use _comp_method_OBJECT_ARRAY instead of numpy
                #  comparison otherwise it would fail to raise when
                #  comparing tz-aware and tz-naive
                with np.errstate(all='ignore'):
                    result = ops._comp_method_OBJECT_ARRAY(op,
                                                           self.astype(object),
                                                           other)
                o_mask = isna(other)
            elif not (is_datetime64_dtype(other) or
                      is_datetime64tz_dtype(other)):
                # e.g. is_timedelta64_dtype(other)
                return ops.invalid_comparison(self, other, op)
            else:
                self._assert_tzawareness_compat(other)
                if isinstance(other, (ABCIndexClass, ABCSeries)):
                    other = other.array

                if (is_datetime64_dtype(other) and
                        not is_datetime64_ns_dtype(other) or
                        not hasattr(other, 'asi8')):
                    # e.g. other.dtype == 'datetime64[s]'
                    # or an object-dtype ndarray
                    other = type(self)._from_sequence(other)

                result = op(self.view('i8'), other.view('i8'))
                o_mask = other._isnan

            result = com.values_from_object(result)

            # Make sure to pass an array to result[...]; indexing with
            # Series breaks with older version of numpy
            o_mask = np.array(o_mask)
            if o_mask.any():
                result[o_mask] = nat_result

        if self._hasnans:
            result[self._isnan] = nat_result

        return result

    return compat.set_function_name(wrapper, opname, cls)


class DatetimeArray(dtl.DatetimeLikeArrayMixin,
                    dtl.TimelikeOps,
                    dtl.DatelikeOps):
    """
    Pandas ExtensionArray for tz-naive or tz-aware datetime data.

    .. versionadded:: 0.24.0

    .. warning::

       DatetimeArray is currently experimental, and its API may change
       without warning. In particular, :attr:`DatetimeArray.dtype` is
       expected to change to always be an instance of an ``ExtensionDtype``
       subclass.

    Parameters
    ----------
    values : Series, Index, DatetimeArray, ndarray
        The datetime data.

        For DatetimeArray `values` (or a Series or Index boxing one),
        `dtype` and `freq` will be extracted from `values`, with
        precedence given to

    dtype : numpy.dtype or DatetimeTZDtype
        Note that the only NumPy dtype allowed is 'datetime64[ns]'.
    freq : str or Offset, optional
    copy : bool, default False
        Whether to copy the underlying array of values.
    """
    _typ = "datetimearray"
    _scalar_type = Timestamp

    # define my properties & methods for delegation
    _bool_ops = ['is_month_start', 'is_month_end',
                 'is_quarter_start', 'is_quarter_end', 'is_year_start',
                 'is_year_end', 'is_leap_year']
    _object_ops = ['weekday_name', 'freq', 'tz']
    _field_ops = ['year', 'month', 'day', 'hour', 'minute', 'second',
                  'weekofyear', 'week', 'weekday', 'dayofweek',
                  'dayofyear', 'quarter', 'days_in_month',
                  'daysinmonth', 'microsecond',
                  'nanosecond']
    _other_ops = ['date', 'time', 'timetz']
    _datetimelike_ops = _field_ops + _object_ops + _bool_ops + _other_ops
    _datetimelike_methods = ['to_period', 'tz_localize',
                             'tz_convert',
                             'normalize', 'strftime', 'round', 'floor',
                             'ceil', 'month_name', 'day_name']

    # dummy attribute so that datetime.__eq__(DatetimeArray) defers
    # by returning NotImplemented
    timetuple = None

    # Needed so that Timestamp.__richcmp__(DateTimeArray) operates pointwise
    ndim = 1

    # ensure that operations with numpy arrays defer to our implementation
    __array_priority__ = 1000

    # -----------------------------------------------------------------
    # Constructors

    _attributes = ["freq", "tz"]
    _dtype = None  # type: Union[np.dtype, DatetimeTZDtype]
    _freq = None

    def __init__(self, values, dtype=_NS_DTYPE, freq=None, copy=False):
        if isinstance(values, (ABCSeries, ABCIndexClass)):
            values = values._values

        inferred_freq = getattr(values, "_freq", None)

        if isinstance(values, type(self)):
            # validation
            dtz = getattr(dtype, 'tz', None)
            if dtz and values.tz is None:
                dtype = DatetimeTZDtype(tz=dtype.tz)
            elif dtz and values.tz:
                if not timezones.tz_compare(dtz, values.tz):
                    msg = (
                        "Timezone of the array and 'dtype' do not match. "
                        "'{}' != '{}'"
                    )
                    raise TypeError(msg.format(dtz, values.tz))
            elif values.tz:
                dtype = values.dtype
            # freq = validate_values_freq(values, freq)
            if freq is None:
                freq = values.freq
            values = values._data

        if not isinstance(values, np.ndarray):
            msg = (
                "Unexpected type '{}'. 'values' must be a DatetimeArray "
                "ndarray, or Series or Index containing one of those."
            )
            raise ValueError(msg.format(type(values).__name__))

        if values.dtype == 'i8':
            # for compat with datetime/timedelta/period shared methods,
            #  we can sometimes get here with int64 values.  These represent
            #  nanosecond UTC (or tz-naive) unix timestamps
            values = values.view(_NS_DTYPE)

        if values.dtype != _NS_DTYPE:
            msg = (
                "The dtype of 'values' is incorrect. Must be 'datetime64[ns]'."
                " Got {} instead."
            )
            raise ValueError(msg.format(values.dtype))

        dtype = _validate_dt64_dtype(dtype)

        if freq == "infer":
            msg = (
                "Frequency inference not allowed in DatetimeArray.__init__. "
                "Use 'pd.array()' instead."
            )
            raise ValueError(msg)

        if copy:
            values = values.copy()
        if freq:
            freq = to_offset(freq)
        if getattr(dtype, 'tz', None):
            # https://github.com/pandas-dev/pandas/issues/18595
            # Ensure that we have a standard timezone for pytz objects.
            # Without this, things like adding an array of timedeltas and
            # a  tz-aware Timestamp (with a tz specific to its datetime) will
            # be incorrect(ish?) for the array as a whole
            dtype = DatetimeTZDtype(tz=timezones.tz_standardize(dtype.tz))
Loading ...