Fix event time save off-by-one using bundled tz data.
Use moment-timezone in parseEventDatetime so naive America/Asuncion wall-clock times convert correctly regardless of the host Node tz database. Also normalize user registration date filters with toDbDate for Postgres. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"hono": "^4.4.7",
|
||||
"ioredis": "^5.11.1",
|
||||
"jose": "^5.4.0",
|
||||
"moment-timezone": "^0.6.2",
|
||||
"nanoid": "^5.0.7",
|
||||
"nodemailer": "^7.0.13",
|
||||
"pdfkit": "^0.17.2",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
import { randomUUID } from 'crypto';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
/**
|
||||
* Get database type (reads env var each time to handle module loading order)
|
||||
@@ -59,17 +60,10 @@ export function parseEventDatetime(
|
||||
return new Date(datetime);
|
||||
}
|
||||
|
||||
// Treat the digits as UTC so we have a stable reference instant.
|
||||
const fakeUTC = new Date(datetime + 'Z');
|
||||
|
||||
// Ask Intl what that UTC instant looks like in both UTC and the target tz.
|
||||
const utcStr = fakeUTC.toLocaleString('en-US', { timeZone: 'UTC' });
|
||||
const tzStr = fakeUTC.toLocaleString('en-US', { timeZone: timezone });
|
||||
|
||||
// The gap between the two tells us the tz offset at this point in time.
|
||||
const offsetMs = new Date(utcStr).getTime() - new Date(tzStr).getTime();
|
||||
|
||||
return new Date(fakeUTC.getTime() + offsetMs);
|
||||
// Interpret the wall-clock digits as local time in `timezone` using
|
||||
// moment-timezone's bundled IANA data. This keeps the conversion correct
|
||||
// regardless of the host Node runtime's (possibly stale) tz database.
|
||||
return moment.tz(datetime, timezone).toDate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import { z } from 'zod';
|
||||
import { db, dbGet, dbAll, users, tickets, events, payments, magicLinkTokens, userSessions, invoices, auditLogs, emailLogs, paymentOptions, legalPages, siteSettings } from '../db/index.js';
|
||||
import { eq, desc, sql, and, gte, lte } from 'drizzle-orm';
|
||||
import { requireAuth } from '../lib/auth.js';
|
||||
import { getNow } from '../lib/utils.js';
|
||||
import { getNow, toDbDate } from '../lib/utils.js';
|
||||
|
||||
interface UserContext {
|
||||
id: string;
|
||||
@@ -39,8 +39,8 @@ usersRouter.get('/', requireAuth(['admin']), async (c) => {
|
||||
const conditions: any[] = [];
|
||||
if (role) conditions.push(eq((users as any).role, role));
|
||||
if (accountStatus) conditions.push(eq((users as any).accountStatus, accountStatus));
|
||||
if (registeredAfter) conditions.push(gte((users as any).createdAt, registeredAfter));
|
||||
if (registeredBefore) conditions.push(lte((users as any).createdAt, registeredBefore));
|
||||
if (registeredAfter) conditions.push(gte((users as any).createdAt, toDbDate(registeredAfter)));
|
||||
if (registeredBefore) conditions.push(lte((users as any).createdAt, toDbDate(registeredBefore)));
|
||||
if (search) {
|
||||
const like = `%${search.toLowerCase()}%`;
|
||||
conditions.push(sql`(
|
||||
|
||||
Reference in New Issue
Block a user