Beispiel #1
0
    def _build_datetime(parts):

        weekdate = parts.get("weekdate")

        if weekdate is not None:
            # we can use strptime (%G, %V, %u) in python 3.6 but these tokens aren't available before that
            year, week = int(weekdate[0]), int(weekdate[1])

            if weekdate[2] is not None:
                day = int(weekdate[2])
            else:
                # day not given, default to 1
                day = 1

            dt = iso_to_gregorian(year, week, day)
            parts["year"] = dt.year
            parts["month"] = dt.month
            parts["day"] = dt.day

        timestamp = parts.get("timestamp")

        if timestamp is not None:
            return datetime.fromtimestamp(timestamp, tz=tz.tzutc())

        expanded_timestamp = parts.get("expanded_timestamp")

        if expanded_timestamp is not None:
            return datetime.fromtimestamp(
                normalize_timestamp(expanded_timestamp),
                tz=tz.tzutc(),
            )

        day_of_year = parts.get("day_of_year")

        if day_of_year is not None:
            year = parts.get("year")
            month = parts.get("month")
            if year is None:
                raise ParserError(
                    "Year component is required with the DDD and DDDD tokens."
                )

            if month is not None:
                raise ParserError(
                    "Month component is not allowed with the DDD and DDDD tokens."
                )

            date_string = "{}-{}".format(year, day_of_year)
            try:
                dt = datetime.strptime(date_string, "%Y-%j")
            except ValueError:
                raise ParserError(
                    "The provided day of year '{}' is invalid.".format(day_of_year)
                )

            parts["year"] = dt.year
            parts["month"] = dt.month
            parts["day"] = dt.day

        day_of_week = parts.get("day_of_week")
        day = parts.get("day")

        # If day is passed, ignore day of week
        if day_of_week is not None and day is None:
            year = parts.get("year", 1970)
            month = parts.get("month", 1)
            day = 1

            # dddd => first day of week after epoch
            # dddd YYYY => first day of week in specified year
            # dddd MM YYYY => first day of week in specified year and month
            # dddd MM => first day after epoch in specified month
            next_weekday_dt = next_weekday(datetime(year, month, day), day_of_week)
            parts["year"] = next_weekday_dt.year
            parts["month"] = next_weekday_dt.month
            parts["day"] = next_weekday_dt.day

        am_pm = parts.get("am_pm")
        hour = parts.get("hour", 0)

        if am_pm == "pm" and hour < 12:
            hour += 12
        elif am_pm == "am" and hour == 12:
            hour = 0

        # Support for midnight at the end of day
        if hour == 24:
            if parts.get("minute", 0) != 0:
                raise ParserError("Midnight at the end of day must not contain minutes")
            if parts.get("second", 0) != 0:
                raise ParserError("Midnight at the end of day must not contain seconds")
            if parts.get("microsecond", 0) != 0:
                raise ParserError(
                    "Midnight at the end of day must not contain microseconds"
                )
            hour = 0
            day_increment = 1
        else:
            day_increment = 0

        # account for rounding up to 1000000
        microsecond = parts.get("microsecond", 0)
        if microsecond == 1000000:
            microsecond = 0
            second_increment = 1
        else:
            second_increment = 0

        increment = timedelta(days=day_increment, seconds=second_increment)

        return (
            datetime(
                year=parts.get("year", 1),
                month=parts.get("month", 1),
                day=parts.get("day", 1),
                hour=hour,
                minute=parts.get("minute", 0),
                second=parts.get("second", 0),
                microsecond=microsecond,
                tzinfo=parts.get("tzinfo"),
            )
            + increment
        )
Beispiel #2
0
    def test_iso_gregorian(self):
        with pytest.raises(ValueError):
            util.iso_to_gregorian(2013, 0, 5)

        with pytest.raises(ValueError):
            util.iso_to_gregorian(2013, 8, 0)
Beispiel #3
0
    def get(self, *args: Any, **kwargs: Any) -> Arrow:
        """Returns an :class:`Arrow <arrow.arrow.Arrow>` object based on flexible inputs.

        :param locale: (optional) a ``str`` specifying a locale for the parser. Defaults to 'en-us'.
        :param tzinfo: (optional) a :ref:`timezone expression <tz-expr>` or tzinfo object.
            Replaces the timezone unless using an input form that is explicitly UTC or specifies
            the timezone in a positional argument. Defaults to UTC.
        :param normalize_whitespace: (optional) a ``bool`` specifying whether or not to normalize
            redundant whitespace (spaces, tabs, and newlines) in a datetime string before parsing.
            Defaults to false.

        Usage::

            >>> import arrow

        **No inputs** to get current UTC time::

            >>> arrow.get()
            <Arrow [2013-05-08T05:51:43.316458+00:00]>

        **One** :class:`Arrow <arrow.arrow.Arrow>` object, to get a copy.

            >>> arw = arrow.utcnow()
            >>> arrow.get(arw)
            <Arrow [2013-10-23T15:21:54.354846+00:00]>

        **One** ``float`` or ``int``, convertible to a floating-point timestamp, to get
        that timestamp in UTC::

            >>> arrow.get(1367992474.293378)
            <Arrow [2013-05-08T05:54:34.293378+00:00]>

            >>> arrow.get(1367992474)
            <Arrow [2013-05-08T05:54:34+00:00]>

        **One** ISO 8601-formatted ``str``, to parse it::

            >>> arrow.get('2013-09-29T01:26:43.830580')
            <Arrow [2013-09-29T01:26:43.830580+00:00]>

        **One** ISO 8601-formatted ``str``, in basic format, to parse it::

            >>> arrow.get('20160413T133656.456289')
            <Arrow [2016-04-13T13:36:56.456289+00:00]>

        **One** ``tzinfo``, to get the current time **converted** to that timezone::

            >>> arrow.get(tz.tzlocal())
            <Arrow [2013-05-07T22:57:28.484717-07:00]>

        **One** naive ``datetime``, to get that datetime in UTC::

            >>> arrow.get(datetime(2013, 5, 5))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **One** aware ``datetime``, to get that datetime::

            >>> arrow.get(datetime(2013, 5, 5, tzinfo=tz.tzlocal()))
            <Arrow [2013-05-05T00:00:00-07:00]>

        **One** naive ``date``, to get that date in UTC::

            >>> arrow.get(date(2013, 5, 5))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **One** time.struct time::

            >>> arrow.get(gmtime(0))
            <Arrow [1970-01-01T00:00:00+00:00]>

        **One** iso calendar ``tuple``, to get that week date in UTC::

            >>> arrow.get((2013, 18, 7))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **Two** arguments, a naive or aware ``datetime``, and a replacement
        :ref:`timezone expression <tz-expr>`::

            >>> arrow.get(datetime(2013, 5, 5), 'US/Pacific')
            <Arrow [2013-05-05T00:00:00-07:00]>

        **Two** arguments, a naive ``date``, and a replacement
        :ref:`timezone expression <tz-expr>`::

            >>> arrow.get(date(2013, 5, 5), 'US/Pacific')
            <Arrow [2013-05-05T00:00:00-07:00]>

        **Two** arguments, both ``str``, to parse the first according to the format of the second::

            >>> arrow.get('2013-05-05 12:30:45 America/Chicago', 'YYYY-MM-DD HH:mm:ss ZZZ')
            <Arrow [2013-05-05T12:30:45-05:00]>

        **Two** arguments, first a ``str`` to parse and second a ``list`` of formats to try::

            >>> arrow.get('2013-05-05 12:30:45', ['MM/DD/YYYY', 'YYYY-MM-DD HH:mm:ss'])
            <Arrow [2013-05-05T12:30:45+00:00]>

        **Three or more** arguments, as for the direct constructor of an ``Arrow`` object::

            >>> arrow.get(2013, 5, 5, 12, 30, 45)
            <Arrow [2013-05-05T12:30:45+00:00]>

        """

        arg_count = len(args)
        locale = kwargs.pop("locale", DEFAULT_LOCALE)
        tz = kwargs.get("tzinfo", None)
        normalize_whitespace = kwargs.pop("normalize_whitespace", False)

        # if kwargs given, send to constructor unless only tzinfo provided
        if len(kwargs) > 1:
            arg_count = 3

        # tzinfo kwarg is not provided
        if len(kwargs) == 1 and tz is None:
            arg_count = 3

        # () -> now, @ tzinfo or utc
        if arg_count == 0:
            if isinstance(tz, str):
                tz = parser.TzinfoParser.parse(tz)
                return self.type.now(tzinfo=tz)

            if isinstance(tz, dt_tzinfo):
                return self.type.now(tzinfo=tz)

            return self.type.utcnow()

        if arg_count == 1:
            arg = args[0]
            if isinstance(arg, Decimal):
                arg = float(arg)

            # (None) -> raises an exception
            if arg is None:
                raise TypeError("Cannot parse argument of type None.")

            # try (int, float) -> from timestamp @ tzinfo
            elif not isinstance(arg, str) and is_timestamp(arg):
                if tz is None:
                    # set to UTC by default
                    tz = dateutil_tz.tzutc()
                return self.type.fromtimestamp(arg, tzinfo=tz)

            # (Arrow) -> from the object's datetime @ tzinfo
            elif isinstance(arg, Arrow):
                return self.type.fromdatetime(arg.datetime, tzinfo=tz)

            # (datetime) -> from datetime @ tzinfo
            elif isinstance(arg, datetime):
                return self.type.fromdatetime(arg, tzinfo=tz)

            # (date) -> from date @ tzinfo
            elif isinstance(arg, date):
                return self.type.fromdate(arg, tzinfo=tz)

            # (tzinfo) -> now @ tzinfo
            elif isinstance(arg, dt_tzinfo):
                return self.type.now(tzinfo=arg)

            # (str) -> parse @ tzinfo
            elif isinstance(arg, str):
                dt = parser.DateTimeParser(locale).parse_iso(arg, normalize_whitespace)
                return self.type.fromdatetime(dt, tzinfo=tz)

            # (struct_time) -> from struct_time
            elif isinstance(arg, struct_time):
                return self.type.utcfromtimestamp(calendar.timegm(arg))

            # (iso calendar) -> convert then from date @ tzinfo
            elif isinstance(arg, tuple) and len(arg) == 3:
                d = iso_to_gregorian(*arg)
                return self.type.fromdate(d, tzinfo=tz)

            else:
                raise TypeError(f"Cannot parse single argument of type {type(arg)!r}.")

        elif arg_count == 2:

            arg_1, arg_2 = args[0], args[1]

            if isinstance(arg_1, datetime):

                # (datetime, tzinfo/str) -> fromdatetime @ tzinfo
                if isinstance(arg_2, (dt_tzinfo, str)):
                    return self.type.fromdatetime(arg_1, tzinfo=arg_2)
                else:
                    raise TypeError(
                        f"Cannot parse two arguments of types 'datetime', {type(arg_2)!r}."
                    )

            elif isinstance(arg_1, date):

                # (date, tzinfo/str) -> fromdate @ tzinfo
                if isinstance(arg_2, (dt_tzinfo, str)):
                    return self.type.fromdate(arg_1, tzinfo=arg_2)
                else:
                    raise TypeError(
                        f"Cannot parse two arguments of types 'date', {type(arg_2)!r}."
                    )

            # (str, format) -> parse @ tzinfo
            elif isinstance(arg_1, str) and isinstance(arg_2, (str, list)):
                dt = parser.DateTimeParser(locale).parse(
                    args[0], args[1], normalize_whitespace
                )
                return self.type.fromdatetime(dt, tzinfo=tz)

            else:
                raise TypeError(
                    f"Cannot parse two arguments of types {type(arg_1)!r} and {type(arg_2)!r}."
                )

        # 3+ args -> datetime-like via constructor
        else:
            return self.type(*args, **kwargs)
Beispiel #4
0
    def get(self, *args, **kwargs):
        """ Returns an :class:`Arrow <arrow.arrow.Arrow>` object based on flexible inputs.

        :param locale: (optional) a ``str`` specifying a locale for the parser. Defaults to
            'en_us'.
        :param tzinfo: (optional) a :ref:`timezone expression <tz-expr>` or tzinfo object.
            Replaces the timezone unless using an input form that is explicitly UTC or specifies
            the timezone in a positional argument. Defaults to UTC.

        Usage::

            >>> import arrow

        **No inputs** to get current UTC time::

            >>> arrow.get()
            <Arrow [2013-05-08T05:51:43.316458+00:00]>

        **None** to also get current UTC time::

            >>> arrow.get(None)
            <Arrow [2013-05-08T05:51:49.016458+00:00]>

        **One** :class:`Arrow <arrow.arrow.Arrow>` object, to get a copy.

            >>> arw = arrow.utcnow()
            >>> arrow.get(arw)
            <Arrow [2013-10-23T15:21:54.354846+00:00]>

        **One** ``float`` or ``int``, convertible to a floating-point timestamp, to get
        that timestamp in UTC::

            >>> arrow.get(1367992474.293378)
            <Arrow [2013-05-08T05:54:34.293378+00:00]>

            >>> arrow.get(1367992474)
            <Arrow [2013-05-08T05:54:34+00:00]>

        **One** ISO-8601-formatted ``str``, to parse it::

            >>> arrow.get('2013-09-29T01:26:43.830580')
            <Arrow [2013-09-29T01:26:43.830580+00:00]>

        **One** ISO-8601-formatted ``str``, in basic format, to parse it::

            >>> arrow.get('20160413T133656.456289')
            <Arrow [2016-04-13T13:36:56.456289+00:00]>

        **One** ``tzinfo``, to get the current time **converted** to that timezone::

            >>> arrow.get(tz.tzlocal())
            <Arrow [2013-05-07T22:57:28.484717-07:00]>

        **One** naive ``datetime``, to get that datetime in UTC::

            >>> arrow.get(datetime(2013, 5, 5))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **One** aware ``datetime``, to get that datetime::

            >>> arrow.get(datetime(2013, 5, 5, tzinfo=tz.tzlocal()))
            <Arrow [2013-05-05T00:00:00-07:00]>

        **One** naive ``date``, to get that date in UTC::

            >>> arrow.get(date(2013, 5, 5))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **One** time.struct time::

            >>> arrow.get(gmtime(0))
            <Arrow [1970-01-01T00:00:00+00:00]>

        **One** iso calendar ``tuple``, to get that week date in UTC::

            >>> arrow.get((2013, 18, 7))
            <Arrow [2013-05-05T00:00:00+00:00]>

        **Two** arguments, a naive or aware ``datetime``, and a replacement
        :ref:`timezone expression <tz-expr>`::

            >>> arrow.get(datetime(2013, 5, 5), 'US/Pacific')
            <Arrow [2013-05-05T00:00:00-07:00]>

        **Two** arguments, a naive ``date``, and a replacement
        :ref:`timezone expression <tz-expr>`::

            >>> arrow.get(date(2013, 5, 5), 'US/Pacific')
            <Arrow [2013-05-05T00:00:00-07:00]>

        **Two** arguments, both ``str``, to parse the first according to the format of the second::

            >>> arrow.get('2013-05-05 12:30:45 America/Chicago', 'YYYY-MM-DD HH:mm:ss ZZZ')
            <Arrow [2013-05-05T12:30:45-05:00]>

        **Two** arguments, first a ``str`` to parse and second a ``list`` of formats to try::

            >>> arrow.get('2013-05-05 12:30:45', ['MM/DD/YYYY', 'YYYY-MM-DD HH:mm:ss'])
            <Arrow [2013-05-05T12:30:45+00:00]>

        **Three or more** arguments, as for the constructor of a ``datetime``::

            >>> arrow.get(2013, 5, 5, 12, 30, 45)
            <Arrow [2013-05-05T12:30:45+00:00]>

        """

        arg_count = len(args)
        locale = kwargs.pop("locale", "en_us")
        tz = kwargs.get("tzinfo", None)

        # if kwargs given, send to constructor unless only tzinfo provided
        if len(kwargs) > 1:
            arg_count = 3

        # tzinfo kwarg is not provided
        if len(kwargs) == 1 and tz is None:
            arg_count = 3

        # () -> now, @ utc.
        if arg_count == 0:
            if isstr(tz):
                tz = parser.TzinfoParser.parse(tz)
                return self.type.now(tz)

            if isinstance(tz, dt_tzinfo):
                return self.type.now(tz)

            return self.type.utcnow()

        if arg_count == 1:
            arg = args[0]

            # (None) -> now, @ utc.
            if arg is None:
                return self.type.utcnow()

            # try (int, float) -> utc, from timestamp.
            elif not isstr(arg) and is_timestamp(arg):
                return self.type.utcfromtimestamp(arg)

            # (Arrow) -> from the object's datetime.
            elif isinstance(arg, Arrow):
                return self.type.fromdatetime(arg.datetime)

            # (datetime) -> from datetime.
            elif isinstance(arg, datetime):
                return self.type.fromdatetime(arg)

            # (date) -> from date.
            elif isinstance(arg, date):
                return self.type.fromdate(arg)

            # (tzinfo) -> now, @ tzinfo.
            elif isinstance(arg, dt_tzinfo):
                return self.type.now(arg)

            # (str) -> parse.
            elif isstr(arg):
                dt = parser.DateTimeParser(locale).parse_iso(arg)
                return self.type.fromdatetime(dt, tz)

            # (struct_time) -> from struct_time
            elif isinstance(arg, struct_time):
                return self.type.utcfromtimestamp(calendar.timegm(arg))

            # (iso calendar) -> convert then from date
            elif isinstance(arg, tuple) and len(arg) == 3:
                dt = iso_to_gregorian(*arg)
                return self.type.fromdate(dt)

            else:
                raise TypeError(
                    "Can't parse single argument of type '{}'".format(
                        type(arg)))

        elif arg_count == 2:

            arg_1, arg_2 = args[0], args[1]

            if isinstance(arg_1, datetime):

                # (datetime, tzinfo/str) -> fromdatetime replace tzinfo.
                if isinstance(arg_2, dt_tzinfo) or isstr(arg_2):
                    return self.type.fromdatetime(arg_1, arg_2)
                else:
                    raise TypeError(
                        "Can't parse two arguments of types 'datetime', '{}'".
                        format(type(arg_2)))

            elif isinstance(arg_1, date):

                # (date, tzinfo/str) -> fromdate replace tzinfo.
                if isinstance(arg_2, dt_tzinfo) or isstr(arg_2):
                    return self.type.fromdate(arg_1, tzinfo=arg_2)
                else:
                    raise TypeError(
                        "Can't parse two arguments of types 'date', '{}'".
                        format(type(arg_2)))

            # (str, format) -> parse.
            elif isstr(arg_1) and (isstr(arg_2) or isinstance(arg_2, list)):
                dt = parser.DateTimeParser(locale).parse(args[0], args[1])
                return self.type.fromdatetime(dt, tzinfo=tz)

            else:
                raise TypeError(
                    "Can't parse two arguments of types '{}' and '{}'".format(
                        type(arg_1), type(arg_2)))

        # 3+ args -> datetime-like via constructor.
        else:
            return self.type(*args, **kwargs)
Beispiel #5
0
    def test_iso_gregorian(self):
        with self.assertRaises(ValueError):
            util.iso_to_gregorian(2013, 0, 5)

        with self.assertRaises(ValueError):
            util.iso_to_gregorian(2013, 8, 0)