Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from datetime import time as dt_time
from datetime import timedelta, timezone
from datetime import tzinfo as dt_tzinfo
from decimal import Decimal
from math import trunc
from time import struct_time
from typing import (
Expand Down Expand Up @@ -238,17 +239,21 @@ def utcnow(cls) -> "Arrow":
@classmethod
def fromtimestamp(
cls,
timestamp: Union[int, float, str],
timestamp: Union[int, float, str, Decimal],
tzinfo: Optional[TZ_EXPR] = None,
) -> "Arrow":
"""Constructs an :class:`Arrow <arrow.arrow.Arrow>` object from a timestamp, converted to
the given timezone.

:param timestamp: an ``int`` or ``float`` timestamp, or a ``str`` that converts to either.
:param timestamp: an ``int``, ``float`` or ``Decimal`` timestamp, or a ``str`` that
converts to one of those.
:param tzinfo: (optional) a ``tzinfo`` object. Defaults to local time.

"""

if isinstance(timestamp, Decimal):
timestamp = float(timestamp)

if tzinfo is None:
tzinfo = dt_datetime.now().astimezone().tzinfo
elif isinstance(tzinfo, str):
Expand All @@ -273,13 +278,17 @@ def fromtimestamp(
)

@classmethod
def utcfromtimestamp(cls, timestamp: Union[int, float, str]) -> "Arrow":
def utcfromtimestamp(cls, timestamp: Union[int, float, str, Decimal]) -> "Arrow":
"""Constructs an :class:`Arrow <arrow.arrow.Arrow>` object from a timestamp, in UTC time.

:param timestamp: an ``int`` or ``float`` timestamp, or a ``str`` that converts to either.
:param timestamp: an ``int``, ``float`` or ``Decimal`` timestamp, or a ``str`` that
converts to one of those.

"""

if isinstance(timestamp, Decimal):
timestamp = float(timestamp)

if not util.is_timestamp(timestamp):
raise ValueError(f"The provided timestamp {timestamp!r} is invalid.")

Expand Down
22 changes: 22 additions & 0 deletions tests/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import sys
import time
from datetime import date, datetime, timedelta, timezone
from decimal import Decimal
from typing import List

import dateutil
Expand Down Expand Up @@ -140,6 +141,18 @@ def test_fromtimestamp(self):
with pytest.raises(ValueError):
arrow.Arrow.fromtimestamp("invalid timestamp")

def test_fromtimestamp_decimal(self):
# arrow.get() accepts a Decimal timestamp, so the constructor it stands
# in for has to accept one too.
timestamp = Decimal("1591328104.308505")

result = arrow.Arrow.fromtimestamp(timestamp, tzinfo="Europe/Paris")

assert_datetime_equality(
result._datetime,
datetime.fromtimestamp(float(timestamp), ZoneInfo("Europe/Paris")),
)

def test_utcfromtimestamp(self):
timestamp = time.time()

Expand All @@ -151,6 +164,15 @@ def test_utcfromtimestamp(self):
with pytest.raises(ValueError):
arrow.Arrow.utcfromtimestamp("invalid timestamp")

def test_utcfromtimestamp_decimal(self):
timestamp = Decimal("1591328104.308505")

result = arrow.Arrow.utcfromtimestamp(timestamp)

assert result._datetime == datetime(
2020, 6, 5, 3, 35, 4, 308505, tzinfo=timezone.utc
)

def test_fromdatetime(self):
dt = datetime(2013, 2, 3, 12, 30, 45, 1)

Expand Down
Loading