2 Commits

Author SHA1 Message Date
Peter Smit
fca040a44d chore(deps): bump prisma to 6.18.0
All checks were successful
CI / checks (push) Successful in 1m3s
2025-11-03 20:19:05 +01:00
Derek
b2f9498142 Prevent date offset for expenses in local timezones (#433) 2025-11-03 19:46:24 +01:00
4 changed files with 857 additions and 53 deletions

874
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@
"@formatjs/intl-localematcher": "^0.5.4",
"@hookform/resolvers": "^3.3.2",
"@json2csv/plainjs": "^7.0.6",
"@prisma/client": "^5.6.0",
"@prisma/client": "^6.18.0",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.5",
@@ -56,7 +56,7 @@
"next13-progressbar": "^1.1.1",
"openai": "^4.25.0",
"pg": "^8.11.3",
"prisma": "^5.7.0",
"prisma": "^6.18.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.47.0",

View File

@@ -5,7 +5,7 @@ import { DocumentsCount } from '@/app/groups/[groupId]/expenses/documents-count'
import { Button } from '@/components/ui/button'
import { getGroupExpenses } from '@/lib/api'
import { Currency } from '@/lib/currency'
import { cn, formatCurrency, formatDate } from '@/lib/utils'
import { cn, formatCurrency, formatDateOnly } from '@/lib/utils'
import { ChevronRight } from 'lucide-react'
import { useLocale, useTranslations } from 'next-intl'
import Link from 'next/link'
@@ -99,7 +99,7 @@ export function ExpenseCard({
<DocumentsCount count={expense._count.documents} />
</div>
<div className="text-xs text-muted-foreground">
{formatDate(expense.expenseDate, locale, { dateStyle: 'medium' })}
{formatDateOnly(expense.expenseDate, locale, { dateStyle: 'medium' })}
</div>
</div>
<Button

View File

@@ -24,6 +24,34 @@ export function formatDate(
})
}
/**
* Formats a date-only field (without time) for display.
* Extracts UTC date components to avoid timezone shifts that can cause off-by-one day errors.
* Use this for dates stored as DATE type in the database (e.g., expenseDate).
*
* @param date - The date to format (typically from a database DATE field, e.g., 2025-10-17T00:00:00.000Z)
* @param locale - The locale string (e.g., 'en-US', 'fr-FR')
* @param options - Formatting options (dateStyle, timeStyle)
* @returns Formatted date string in the specified locale
*/
export function formatDateOnly(
date: Date,
locale: string,
options: { dateStyle?: DateTimeStyle; timeStyle?: DateTimeStyle } = {},
) {
// Extract UTC date components to avoid timezone shifts
const year = date.getUTCFullYear()
const month = date.getUTCMonth()
const day = date.getUTCDate()
// Create a new date in the user's local timezone with these components
const localDate = new Date(year, month, day)
return localDate.toLocaleString(locale, {
...options,
})
}
export function formatCategoryForAIPrompt(category: Category) {
return `"${category.grouping}/${category.name}" (ID: ${category.id})`
}