From f728b2b0e77ae0692f535d1dc31ff8abce2c5b5c Mon Sep 17 00:00:00 2001 From: contributor Date: Fri, 3 Oct 2025 12:16:34 +0300 Subject: [PATCH 1/4] fix enex import saves local dates in wrong format (with Z, like UTC fields) the proper format for dateCreated, dateModified is: +0000 --- apps/server/src/services/date_utils.ts | 14 ++++++++++++++ apps/server/src/services/import/enex.ts | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/server/src/services/date_utils.ts b/apps/server/src/services/date_utils.ts index 33f0ff197..7a1a9020a 100644 --- a/apps/server/src/services/date_utils.ts +++ b/apps/server/src/services/date_utils.ts @@ -27,6 +27,19 @@ function localNowDate() { } } +function formatDateTimeToLocalISO(date: Date | string | null | undefined) { + if (!date) { + return undefined; + } + + const d = dayjs(date); + if (!d.isValid()) { + return undefined; + } + + return d.format(LOCAL_DATETIME_FORMAT); +} + function pad(num: number) { return num <= 9 ? `0${num}` : `${num}`; } @@ -94,6 +107,7 @@ export default { utcNowDateTime, localNowDateTime, localNowDate, + formatDateTimeToLocalISO, utcDateStr, utcDateTimeStr, parseDateTime, diff --git a/apps/server/src/services/import/enex.ts b/apps/server/src/services/import/enex.ts index 5a13e0960..49950109f 100644 --- a/apps/server/src/services/import/enex.ts +++ b/apps/server/src/services/import/enex.ts @@ -3,6 +3,7 @@ import stream from "stream"; import { Throttle } from "stream-throttle"; import log from "../log.js"; import { md5, escapeHtml, fromBase64 } from "../utils.js"; +import date_utils from "../date_utils.js"; import sql from "../sql.js"; import noteService from "../notes.js"; import imageService from "../image.js"; @@ -235,6 +236,8 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN function updateDates(note: BNote, utcDateCreated?: string, utcDateModified?: string) { // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL + const dateCreated = date_utils.formatDateTimeToLocalISO(utcDateCreated); + const dateModified = date_utils.formatDateTimeToLocalISO(utcDateModified); sql.execute( ` UPDATE notes @@ -243,7 +246,7 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN dateModified = ?, utcDateModified = ? WHERE noteId = ?`, - [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, note.noteId] + [dateCreated, utcDateCreated, dateModified, utcDateModified, note.noteId] ); sql.execute( From a3bd15e10295122ea2dcf459846c835ca2cff1f5 Mon Sep 17 00:00:00 2001 From: contributor Date: Thu, 13 Nov 2025 18:30:38 +0200 Subject: [PATCH 2/4] move date conversion function to enex directly to protect from future potential refactoring --- apps/server/src/services/date_utils.ts | 17 +++-------------- apps/server/src/services/import/enex.ts | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/server/src/services/date_utils.ts b/apps/server/src/services/date_utils.ts index 7a1a9020a..89b39f456 100644 --- a/apps/server/src/services/date_utils.ts +++ b/apps/server/src/services/date_utils.ts @@ -27,19 +27,6 @@ function localNowDate() { } } -function formatDateTimeToLocalISO(date: Date | string | null | undefined) { - if (!date) { - return undefined; - } - - const d = dayjs(date); - if (!d.isValid()) { - return undefined; - } - - return d.format(LOCAL_DATETIME_FORMAT); -} - function pad(num: number) { return num <= 9 ? `0${num}` : `${num}`; } @@ -104,10 +91,12 @@ function validateUtcDateTime(str: string | undefined) { } export default { + LOCAL_DATETIME_FORMAT, + UTC_DATETIME_FORMAT, utcNowDateTime, localNowDateTime, localNowDate, - formatDateTimeToLocalISO, + utcDateStr, utcDateTimeStr, parseDateTime, diff --git a/apps/server/src/services/import/enex.ts b/apps/server/src/services/import/enex.ts index 49950109f..5fe70fa47 100644 --- a/apps/server/src/services/import/enex.ts +++ b/apps/server/src/services/import/enex.ts @@ -1,3 +1,4 @@ +import dayjs from "dayjs"; import sax from "sax"; import stream from "stream"; import { Throttle } from "stream-throttle"; @@ -236,8 +237,8 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN function updateDates(note: BNote, utcDateCreated?: string, utcDateModified?: string) { // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL - const dateCreated = date_utils.formatDateTimeToLocalISO(utcDateCreated); - const dateModified = date_utils.formatDateTimeToLocalISO(utcDateModified); + const dateCreated = formatDateTimeToLocalDbFormat(utcDateCreated); + const dateModified = formatDateTimeToLocalDbFormat(utcDateModified); sql.execute( ` UPDATE notes @@ -410,4 +411,17 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN }); } +function formatDateTimeToLocalDbFormat(date: Date | string | null | undefined) { + if (!date) { + return undefined; + } + + const d = dayjs(date); + if (!d.isValid()) { + return undefined; + } + + return d.format(date_utils.LOCAL_DATETIME_FORMAT); +} + export default { importEnex }; From 48a20500f8cbe8ed4093256ec68cd753b75ead9e Mon Sep 17 00:00:00 2001 From: contributor Date: Thu, 13 Nov 2025 19:54:32 +0200 Subject: [PATCH 3/4] explicit param to keep or convert local date for enex import --- apps/server/src/services/import/enex.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/server/src/services/import/enex.ts b/apps/server/src/services/import/enex.ts index 5fe70fa47..711723516 100644 --- a/apps/server/src/services/import/enex.ts +++ b/apps/server/src/services/import/enex.ts @@ -237,8 +237,8 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN function updateDates(note: BNote, utcDateCreated?: string, utcDateModified?: string) { // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL - const dateCreated = formatDateTimeToLocalDbFormat(utcDateCreated); - const dateModified = formatDateTimeToLocalDbFormat(utcDateModified); + const dateCreated = formatDateTimeToLocalDbFormat(utcDateCreated, false); + const dateModified = formatDateTimeToLocalDbFormat(utcDateModified, false); sql.execute( ` UPDATE notes @@ -411,17 +411,23 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN }); } -function formatDateTimeToLocalDbFormat(date: Date | string | null | undefined) { - if (!date) { +function formatDateTimeToLocalDbFormat( + utcDateFromEnex: Date | string | null | undefined, + keepUtc: boolean) { + + if (!utcDateFromEnex) { return undefined; } - const d = dayjs(date); - if (!d.isValid()) { + let date = dayjs(utcDateFromEnex); + if (keepUtc) { + date = date.utc(); + } + if (!date.isValid()) { return undefined; } - return d.format(date_utils.LOCAL_DATETIME_FORMAT); + return date.format(date_utils.LOCAL_DATETIME_FORMAT); } export default { importEnex }; From 98b5b81d7d5b339980f3d0682d42085ac6ac7159 Mon Sep 17 00:00:00 2001 From: contributor Date: Thu, 13 Nov 2025 20:33:03 +0200 Subject: [PATCH 4/4] add typing and improve readability --- apps/server/src/services/import/enex.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/server/src/services/import/enex.ts b/apps/server/src/services/import/enex.ts index 711723516..94104104a 100644 --- a/apps/server/src/services/import/enex.ts +++ b/apps/server/src/services/import/enex.ts @@ -413,21 +413,19 @@ function importEnex(taskContext: TaskContext<"importNotes">, file: File, parentN function formatDateTimeToLocalDbFormat( utcDateFromEnex: Date | string | null | undefined, - keepUtc: boolean) { - + keepUtc: boolean +): string | undefined { if (!utcDateFromEnex) { return undefined; } - let date = dayjs(utcDateFromEnex); - if (keepUtc) { - date = date.utc(); - } - if (!date.isValid()) { + const parsedDate = dayjs(utcDateFromEnex); + + if (!parsedDate.isValid()) { return undefined; } - return date.format(date_utils.LOCAL_DATETIME_FORMAT); + return (keepUtc ? parsedDate.utc() : parsedDate).format(date_utils.LOCAL_DATETIME_FORMAT); } export default { importEnex };