Skip to content

Commit

Permalink
Merge branch 'master' into fix-fa-locale
Browse files Browse the repository at this point in the history
  • Loading branch information
krisfremen authored Oct 21, 2024
2 parents b3c8a66 + d5bd7db commit 8261e38
Show file tree
Hide file tree
Showing 18 changed files with 109 additions and 85 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
16 changes: 8 additions & 8 deletions .github/workflows/continuous_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ jobs:
- os: windows-latest
path: ~\AppData\Local\pip\Cache
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Cache pip
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -47,27 +47,27 @@ jobs:
- name: Test with tox
run: tox
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
file: coverage.xml

linting:
name: Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
restore-keys: ${{ runner.os }}-pre-commit-
- name: Set up Python ${{ runner.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ jobs:
release-to-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
Expand Down
39 changes: 22 additions & 17 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
from datetime import date
from datetime import datetime as dt_datetime
from datetime import time as dt_time
from datetime import timedelta
from datetime import timedelta, timezone
from datetime import tzinfo as dt_tzinfo
from math import trunc
from time import struct_time
from typing import (
Any,
ClassVar,
Final,
Generator,
Iterable,
List,
Literal,
Mapping,
Optional,
Tuple,
Expand All @@ -36,12 +38,6 @@
from arrow.constants import DEFAULT_LOCALE, DEHUMANIZE_LOCALES
from arrow.locales import TimeFrameLiteral

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final, Literal
else:
from typing import Final, Literal # pragma: no cover


TZ_EXPR = Union[dt_tzinfo, str]

_T_FRAMES = Literal[
Expand Down Expand Up @@ -496,7 +492,7 @@ def range(

values = [getattr(current, f) for f in cls._ATTRS]
current = cls(*values, tzinfo=tzinfo).shift( # type: ignore[misc]
**{frame_relative: relative_steps}
check_imaginary=True, **{frame_relative: relative_steps}
)

if frame in ["month", "quarter", "year"] and current.day < original_day:
Expand Down Expand Up @@ -587,7 +583,9 @@ def span(
elif frame_absolute == "quarter":
floor = floor.shift(months=-((self.month - 1) % 3))

ceil = floor.shift(**{frame_relative: count * relative_steps})
ceil = floor.shift(
check_imaginary=True, **{frame_relative: count * relative_steps}
)

if bounds[0] == "(":
floor = floor.shift(microseconds=+1)
Expand Down Expand Up @@ -802,15 +800,15 @@ def __hash__(self) -> int:

# attributes and properties

def __getattr__(self, name: str) -> int:
def __getattr__(self, name: str) -> Any:
if name == "week":
return self.isocalendar()[1]

if name == "quarter":
return int((self.month - 1) / self._MONTHS_PER_QUARTER) + 1

if not name.startswith("_"):
value: Optional[int] = getattr(self._datetime, name, None)
value: Optional[Any] = getattr(self._datetime, name, None)

if value is not None:
return value
Expand Down Expand Up @@ -985,10 +983,15 @@ def replace(self, **kwargs: Any) -> "Arrow":

return self.fromdatetime(current)

def shift(self, **kwargs: Any) -> "Arrow":
def shift(self, check_imaginary: bool = True, **kwargs: Any) -> "Arrow":
"""Returns a new :class:`Arrow <arrow.arrow.Arrow>` object with attributes updated
according to inputs.
Parameters:
check_imaginary (bool): If True (default), will check for and resolve
imaginary times (like during DST transitions). If False, skips this check.
Use pluralized property names to relatively shift their current value:
>>> import arrow
Expand Down Expand Up @@ -1035,7 +1038,8 @@ def shift(self, **kwargs: Any) -> "Arrow":

current = self._datetime + relativedelta(**relative_kwargs)

if not dateutil_tz.datetime_exists(current):
# If check_imaginary is True, perform the check for imaginary times (DST transitions)
if check_imaginary and not dateutil_tz.datetime_exists(current):
current = dateutil_tz.resolve_imaginary(current)

return self.fromdatetime(current)
Expand Down Expand Up @@ -1092,7 +1096,8 @@ def format(
self, fmt: str = "YYYY-MM-DD HH:mm:ssZZ", locale: str = DEFAULT_LOCALE
) -> str:
"""Returns a string representation of the :class:`Arrow <arrow.arrow.Arrow>` object,
formatted according to the provided format string.
formatted according to the provided format string. For a list of formatting values,
see :ref:`supported-tokens`
:param fmt: the format string.
:param locale: the locale to format.
Expand Down Expand Up @@ -1147,7 +1152,7 @@ def humanize(
locale = locales.get_locale(locale)

if other is None:
utc = dt_datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc())
utc = dt_datetime.now(timezone.utc).replace(tzinfo=dateutil_tz.tzutc())
dt = utc.astimezone(self._datetime.tzinfo)

elif isinstance(other, Arrow):
Expand Down Expand Up @@ -1444,7 +1449,7 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":

time_changes = {k: sign_val * v for k, v in time_object_info.items()}

return current_time.shift(**time_changes)
return current_time.shift(check_imaginary=True, **time_changes)

# query functions

Expand Down Expand Up @@ -1862,7 +1867,7 @@ def _get_iteration_params(cls, end: Any, limit: Optional[int]) -> Tuple[Any, int
@staticmethod
def _is_last_day_of_month(date: "Arrow") -> bool:
"""Returns a boolean indicating whether the datetime is the last day of the month."""
return date.day == calendar.monthrange(date.year, date.month)[1]
return cast(int, date.day) == calendar.monthrange(date.year, date.month)[1]


Arrow.min = Arrow.fromdatetime(dt_datetime.min)
Expand Down
6 changes: 1 addition & 5 deletions arrow/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

import sys
from datetime import datetime

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final
else:
from typing import Final # pragma: no cover
from typing import Final

# datetime.max.timestamp() errors on Windows, so we must hardcode
# the highest possible datetime value that can output a timestamp.
Expand Down
9 changes: 1 addition & 8 deletions arrow/formatter.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
"""Provides the :class:`Arrow <arrow.formatter.DateTimeFormatter>` class, an improved formatter for datetimes."""

import re
import sys
from datetime import datetime, timedelta
from typing import Optional, Pattern, cast
from typing import Final, Optional, Pattern, cast

from dateutil import tz as dateutil_tz

from arrow import locales
from arrow.constants import DEFAULT_LOCALE

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final
else:
from typing import Final # pragma: no cover


FORMAT_ATOM: Final[str] = "YYYY-MM-DD HH:mm:ssZZ"
FORMAT_COOKIE: Final[str] = "dddd, DD-MMM-YYYY HH:mm:ss ZZZ"
FORMAT_RFC822: Final[str] = "ddd, DD MMM YY HH:mm:ss Z"
Expand Down
20 changes: 7 additions & 13 deletions arrow/locales.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Provides internationalization for arrow in over 60 languages and dialects."""

import sys
from math import trunc
from typing import (
Any,
ClassVar,
Dict,
List,
Literal,
Mapping,
Optional,
Sequence,
Expand All @@ -16,11 +16,6 @@
cast,
)

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Literal
else:
from typing import Literal # pragma: no cover

TimeFrameLiteral = Literal[
"now",
"second",
Expand Down Expand Up @@ -659,20 +654,20 @@ class FrenchCanadianLocale(FrenchBaseLocale, Locale):
class GreekLocale(Locale):
names = ["el", "el-gr"]

past = "{0} πριν"
past = "πριν από {0}"
future = "σε {0}"
and_word = "και"

timeframes = {
"now": "τώρα",
"second": "ένα δεύτερο",
"second": "ένα δευτερόλεπτο",
"seconds": "{0} δευτερόλεπτα",
"minute": "ένα λεπτό",
"minutes": "{0} λεπτά",
"hour": "μία ώρα",
"hours": "{0} ώρες",
"day": "μία μέρα",
"days": "{0} μέρες",
"day": "μία ημέρα",
"days": "{0} ημέρες",
"week": "μία εβδομάδα",
"weeks": "{0} εβδομάδες",
"month": "ένα μήνα",
Expand Down Expand Up @@ -702,7 +697,7 @@ class GreekLocale(Locale):
"Φεβ",
"Μαρ",
"Απρ",
"Μαϊ",
"Μαΐ",
"Ιον",
"Ιολ",
"Αυγ",
Expand Down Expand Up @@ -1172,7 +1167,6 @@ class KoreanLocale(Locale):
}

special_dayframes = {
-3: "그끄제",
-2: "그제",
-1: "어제",
1: "내일",
Expand All @@ -1181,7 +1175,7 @@ class KoreanLocale(Locale):
4: "그글피",
}

special_yearframes = {-2: "제작년", -1: "작년", 1: "내년", 2: "내후년"}
special_yearframes = {-2: "재작년", -1: "작년", 1: "내년", 2: "내후년"}

month_names = [
"",
Expand Down
8 changes: 2 additions & 6 deletions arrow/parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Provides the :class:`Arrow <arrow.parser.DateTimeParser>` class, a better way to parse datetime strings."""

import re
import sys
from datetime import datetime, timedelta
from datetime import tzinfo as dt_tzinfo
from functools import lru_cache
Expand All @@ -11,12 +10,14 @@
Dict,
Iterable,
List,
Literal,
Match,
Optional,
Pattern,
SupportsFloat,
SupportsInt,
Tuple,
TypedDict,
Union,
cast,
overload,
Expand All @@ -28,11 +29,6 @@
from arrow.constants import DEFAULT_LOCALE
from arrow.util import next_weekday, normalize_timestamp

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Literal, TypedDict
else:
from typing import Literal, TypedDict # pragma: no cover


class ParserError(ValueError):
pass
Expand Down
4 changes: 4 additions & 0 deletions docs/guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ Move between the earlier and later moments of an ambiguous time:
Format
~~~~~~

For a list of formatting values, see :ref:`supported-tokens`

.. code-block:: python
>>> arrow.utcnow().format('YYYY-MM-DD HH:mm:ss ZZ')
Expand Down Expand Up @@ -365,6 +367,8 @@ Then get and use a factory for it:
>>> custom.days_till_xmas()
>>> 211
.. _supported-tokens:

Supported Tokens
~~~~~~~~~~~~~~~~

Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ classifiers = [
]
dependencies = [
"python-dateutil>=2.7.0",
"types-python-dateutil>=2.8.10",
]
requires-python = ">=3.8"
description = "Better dates & times for Python"
Expand Down
1 change: 1 addition & 0 deletions requirements/requirements-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pytest-cov
pytest-mock
pytz==2021.1
simplejson==3.*
types-python-dateutil>=2.8.10
1 change: 0 additions & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
python-dateutil>=2.7.0
types-python-dateutil>=2.8.10
Loading

0 comments on commit 8261e38

Please sign in to comment.