diff --git a/frontend/src/format.ts b/frontend/src/format.ts index 5c23420d3..e6e464db3 100644 --- a/frontend/src/format.ts +++ b/frontend/src/format.ts @@ -51,7 +51,7 @@ export const dateFormat: Record = { quarter: (date) => `${date.getUTCFullYear().toString()}Q${(Math.floor(date.getUTCMonth() / 3) + 1).toString()}`, month: utcFormat("%b %Y"), - week: utcFormat("%YW%W"), + week: utcFormat("%GW%V"), day, }; @@ -61,7 +61,7 @@ export const timeFilterDateFormat: Record = { quarter: (date) => `${date.getUTCFullYear().toString()}-Q${(Math.floor(date.getUTCMonth() / 3) + 1).toString()}`, month: utcFormat("%Y-%m"), - week: utcFormat("%Y-W%W"), + week: utcFormat("%G-W%V"), day, }; diff --git a/frontend/test/format.test.ts b/frontend/test/format.test.ts index 65e034c49..2a78829b2 100644 --- a/frontend/test/format.test.ts +++ b/frontend/test/format.test.ts @@ -37,8 +37,8 @@ test("time filter date formatting", () => { assert.is(day(date), "2020-03-20"); assert.is(month(janfirst), "2020-01"); assert.is(month(date), "2020-03"); - assert.is(week(janfirst), "2020-W00"); - assert.is(week(date), "2020-W11"); + assert.is(week(janfirst), "2020-W01"); + assert.is(week(date), "2020-W12"); assert.is(quarter(janfirst), "2020-Q1"); assert.is(quarter(date), "2020-Q1"); assert.is(year(janfirst), "2020"); @@ -54,8 +54,8 @@ test("human-readable date formatting", () => { assert.is(day(date), "2020-03-20"); assert.is(month(janfirst), "Jan 2020"); assert.is(month(date), "Mar 2020"); - assert.is(week(janfirst), "2020W00"); - assert.is(week(date), "2020W11"); + assert.is(week(janfirst), "2020W01"); + assert.is(week(date), "2020W12"); assert.is(quarter(janfirst), "2020Q1"); assert.is(quarter(date), "2020Q1"); assert.is(year(janfirst), "2020"); diff --git a/src/fava/help/filters.md b/src/fava/help/filters.md index 3ad718ad7..15ccacf4d 100644 --- a/src/fava/help/filters.md +++ b/src/fava/help/filters.md @@ -4,7 +4,7 @@ With the text inputs at the top right of the page, you can filter the entries that are displayed in Fava's reports. If you use multiple filters, the entries matching all of them will be selected. -### Time +## Time Filter entries by their date. You can specify dates and intervals like years, quarters, months, weeks, and days (for example `2015`, `2012-Q1`, `2010-10`, @@ -20,18 +20,35 @@ current year up to today, or `year-1 - year` for all entries of the last and current year. To prevent subtraction, use parentheses: `(month)-10` refers to the 10th of this month, whereas `month-10` would be 10 months ago. -**Week number** Week number of the year (Monday as the first day of the week) as -a decimal number. All days in a new year preceding the first Monday are -considered to be in week 0. +### ISO 8601 Week dates -### Account +The week-based calendar follows +[ISO 8601 week-numbering system](https://en.wikipedia.org/wiki/ISO_week_date) +with each week starting on Mondays and the first week of the ISO week-based year +being the first week that has the majority of its days in January. Equivalently, +it is also the week to containing January 4th. + +Some examples where the ISO week-based calendar differs from the Gregorian +calendar: + +- Week 1 of 2025 starts on Monday 30 December 2024 and ends on Sunday 5 January + 2025\. As a result, 30 December 2024 belongs to the year 2025 of the ISO + week-based calendar, despite being in the year 2024 of the Gregorian calendar. +- Week 53 of 2020 ends on Sunday 3 January 2021. As a result, 3 January 2021 + belongs to the year 2020 of the ISO week-based calendar, despite being in the + year 2021 of the Gregorian calendar. + +Most years of ISO week-based calendars have 52 weeks, but as there are slightly +more than 52 weeks in a year, some years contain a 53rd week. + +## Account Filter entries by account, matching any entry this account is part of. The filter can be an account name, either the full account name or a component of the account name, or a regular expression matching the account name, e.g. `.*Company.*` to filter for all that contain `Company`. -### Filter by tag, link, payee and other metadata +## Filter by tag, link, payee and other metadata This final filter allows you to filter entries by various attributes. diff --git a/src/fava/util/date.py b/src/fava/util/date.py index 3aa26deae..604c492ad 100644 --- a/src/fava/util/date.py +++ b/src/fava/util/date.py @@ -125,7 +125,7 @@ def format_date(self, date: datetime.date) -> str: if self is Interval.MONTH: return date.strftime("%b %Y") if self is Interval.WEEK: - return date.strftime("%YW%W") + return date.strftime("%GW%V") return date.strftime("%Y-%m-%d") def format_date_filter(self, date: datetime.date) -> str: @@ -137,7 +137,7 @@ def format_date_filter(self, date: datetime.date) -> str: if self is Interval.MONTH: return date.strftime("%Y-%m") if self is Interval.WEEK: - return date.strftime("%Y-W%W") + return date.strftime("%G-W%V") return date.strftime("%Y-%m-%d") @@ -313,7 +313,7 @@ def substitute( if interval == "week": string = string.replace( complete_match, - (today + timedelta(offset * 7)).strftime("%Y-W%W"), + (today + timedelta(offset * 7)).strftime("%G-W%V"), ) if interval == "day": string = string.replace( @@ -384,7 +384,7 @@ def parse_date( # noqa: PLR0911 if match: year, week = map(int, match.group(1, 2)) start = ( - datetime.datetime.strptime(f"{year}-W{week}-1", "%Y-W%W-%w") + datetime.datetime.strptime(f"{year}-W{week}-1", "%G-W%V-%w") .replace(tzinfo=datetime.timezone.utc) .date() ) diff --git a/tests/test_util_date.py b/tests/test_util_date.py index ddb7caaba..4005ae575 100644 --- a/tests/test_util_date.py +++ b/tests/test_util_date.py @@ -149,7 +149,7 @@ def test_interval_tuples() -> None: ("(month+24)", "2018-06"), ("week", "2016-W25"), ("week+20", "2016-W45"), - ("week+2000", "2054-W42"), + ("week+2000", "2054-W43"), ("day", "2016-06-24"), ("day+20", "2016-07-14"), ], @@ -219,8 +219,8 @@ def test_fiscal_substitute( ("2000-01-01", "2001-01-01", " 2000 "), ("2010-10-01", "2010-11-01", "2010-10"), ("2000-01-03", "2000-01-04", "2000-01-03"), - ("2015-01-05", "2015-01-12", "2015-W01"), - ("2025-01-06", "2025-01-13", "2025-W01"), + ("2014-12-29", "2015-01-05", "2015-W01"), + ("2024-12-30", "2025-01-06", "2025-W01"), ("2015-04-01", "2015-07-01", "2015-Q2"), ("2014-01-01", "2016-01-01", "2014 to 2015"), ("2014-01-01", "2016-01-01", "2014-2015"),