Skip to content

Commit 4bb6f44

Browse files
committed
edited notes: handle timezone differences between client and server
1 parent 8520373 commit 4bb6f44

File tree

2 files changed

+40
-39
lines changed

2 files changed

+40
-39
lines changed
Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,75 @@
1+
import cls from '../../services/cls.js';
12
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
2-
import dayjs from "dayjs";
33
import { resolveDateParams } from "./edited-notes.js";
44

5-
function resolveAsDate(dateStr: string) {
6-
return resolveDateParams(dateStr).date;
5+
// test date setup
6+
// client: UTC+1
7+
// server: UTC
8+
// day/month/year is changed when server converts a client date to to UTC
9+
const clientDate = "2025-01-01 00:11:11.000+0100";
10+
const serverDate = "2024-12-31 23:11:11.000Z";
11+
12+
// expected values - from client's point of view
13+
const expectedToday = "2025-01-01";
14+
const expectedTodayMinus1 = "2024-12-31";
15+
const expectedMonth = "2025-01";
16+
const expectedMonthMinus2 = "2024-11";
17+
const expectedYear = "2025";
18+
const expectedYearMinus1 = "2024";
19+
20+
function runTest(dateStrToResolve: string, expectedDate: string) {
21+
cls.init(() => {
22+
cls.set("localNowDateTime", clientDate);
23+
const resolvedDate = resolveDateParams(dateStrToResolve).date;
24+
expect(resolvedDate).toBe(expectedDate);
25+
});
726
}
827

9-
describe("edited-notes::resolveAsDate", () => {
28+
describe("edited-notes::resolveDateParams", () => {
1029
beforeEach(() => {
11-
// Set a fixed date and time before each test
1230
vi.useFakeTimers();
13-
vi.setSystemTime(new Date('2012-11-10T23:22:21Z')); // NOTE!!: Date wrap in my timezone
31+
vi.setSystemTime(new Date(serverDate));
1432
});
1533

1634
afterEach(() => {
1735
// Restore real timers after each test
1836
vi.useRealTimers();
1937
});
2038

21-
2239
it("resolves 'TODAY' to today's date", () => {
23-
const expectedDate = dayjs().format("YYYY-MM-DD");
24-
const resolvedDate = resolveAsDate("TODAY");
25-
expect(resolvedDate).toBe(expectedDate);
40+
runTest("TODAY", expectedToday);
2641
});
2742

2843
it("resolves 'MONTH' to current month", () => {
29-
const expectedMonth = dayjs().format("YYYY-MM");
30-
const resolvedMonth = resolveAsDate("MONTH");
31-
expect(resolvedMonth).toBe(expectedMonth);
44+
runTest("MONTH", expectedMonth);
3245
});
3346

3447
it("resolves 'YEAR' to current year", () => {
35-
const expectedYear = dayjs().format("YYYY");
36-
const resolvedYear = resolveAsDate("YEAR");
37-
expect(resolvedYear).toBe(expectedYear);
48+
runTest("YEAR", expectedYear);
3849
});
3950

4051
it("resolves 'TODAY-1' to yesterday's date", () => {
41-
const expectedDate = dayjs().subtract(1, "day").format("YYYY-MM-DD");
42-
const resolvedDate = resolveAsDate("TODAY-1");
43-
expect(resolvedDate).toBe(expectedDate);
52+
runTest("TODAY-1", expectedTodayMinus1);
4453
});
4554

4655
it("resolves 'MONTH-2' to 2 months ago", () => {
47-
const expectedMonth = dayjs().subtract(2, "month").format("YYYY-MM");
48-
const resolvedMonth = resolveAsDate("MONTH-2");
49-
expect(resolvedMonth).toBe(expectedMonth);
56+
runTest("MONTH-2", expectedMonthMinus2);
5057
});
5158

52-
it("resolves 'YEAR+1' to next year", () => {
53-
const expectedYear = dayjs().add(1, "year").format("YYYY");
54-
const resolvedYear = resolveAsDate("YEAR+1");
55-
expect(resolvedYear).toBe(expectedYear);
59+
it("resolves 'YEAR-1' to last year", () => {
60+
runTest("YEAR-1", expectedYearMinus1);
5661
});
5762

5863
it("returns original string for unrecognized keyword", () => {
59-
const unrecognizedString = "NOT_A_DYNAMIC_DATE";
60-
const resolvedString = resolveAsDate(unrecognizedString);
61-
expect(resolvedString).toBe(unrecognizedString);
64+
runTest("FOO", "FOO");
6265
});
6366

6467
it("returns original string for partially recognized keyword", () => {
65-
const partialString = "TODAY-";
66-
const resolvedString = resolveAsDate(partialString);
67-
expect(resolvedString).toBe(partialString);
68+
runTest("TODAY-", "TODAY-");
6869
});
6970

7071
it("resolves 'today' (lowercase) to today's date", () => {
71-
const expectedDate = dayjs().format("YYYY-MM-DD");
72-
const resolvedDate = resolveAsDate("today");
73-
expect(resolvedDate).toBe(expectedDate);
72+
runTest("today", expectedToday);
7473
});
7574

7675
});

apps/server/src/routes/api/edited-notes.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dayjs from "dayjs";
12
import beccaService from "../../becca/becca_service.js";
23
import sql from "../../services/sql.js";
34
import cls from "../../services/cls.js";
@@ -6,7 +7,7 @@ import type { Request } from "express";
67
import { NotePojo } from "../../becca/becca-interface.js";
78
import type BNote from "../../becca/entities/bnote.js";
89
import { EditedNotesResponse } from "@triliumnext/commons";
9-
import dayjs from "dayjs";
10+
import dateUtils from "../../services/date_utils.js";
1011

1112
interface NotePath {
1213
noteId: string;
@@ -85,7 +86,7 @@ function getNotePathData(note: BNote): NotePath | undefined {
8586
}
8687
}
8788

88-
function formatDateFromKeywordAndDelta(keyword: string, delta: number): string {
89+
function formatDateFromKeywordAndDelta(startingDate: dayjs.Dayjs, keyword: string, delta: number): string {
8990
const formatMap = new Map<string, { format: string, addUnit: dayjs.UnitType }>([
9091
["today", { format: "YYYY-MM-DD", addUnit: "day" }],
9192
["month", { format: "YYYY-MM", addUnit: "month" }],
@@ -98,7 +99,7 @@ function formatDateFromKeywordAndDelta(keyword: string, delta: number): string {
9899
throw new Error(`Unrecognized keyword: ${keyword}`);
99100
}
100101

101-
const date = dayjs().add(delta, handler.addUnit);
102+
const date = startingDate.add(delta, handler.addUnit);
102103
return date.format(handler.format);
103104
}
104105

@@ -126,7 +127,8 @@ export function resolveDateParams(dateStr: string): DateFilter {
126127
const keyword = match[1].toLowerCase();
127128
const delta = match[2] ? parseInt(match[2]) : 0;
128129

129-
const date = formatDateFromKeywordAndDelta(keyword, delta);
130+
const clientDate = dayjs(dateUtils.localNowDate());
131+
const date = formatDateFromKeywordAndDelta(clientDate, keyword, delta);
130132
return {
131133
date: `${date}`
132134
}

0 commit comments

Comments
 (0)