fix(campaigns/expiry): format dates in America/Montreal, not container UTC
The targo-hub container runs with TZ=UTC (no override set). Calls to
toLocaleDateString without an explicit timeZone option were rendering
dates in UTC, which meant a wrapper expiring at 23:59 EDT (= 03:59
UTC next day) showed "22 juin 2026" to the recipient instead of the
intended "21 juin".
All 4 date-formatting sites in lib/campaigns.js now pass
timeZone: 'America/Montreal' explicitly:
- worker (sendCampaignAsync) — main send path
- /campaigns/:id/recipients/:i/view — web fallback render
- POST /templates/:name/test-send sample defaults
- POST /templates/:name/preview sample defaults
Verified on prod: stored UTC "2026-06-22T03:59:59Z" now formats
"21 juin 2026" / "June 21, 2026" with the timeZone option, matching
the operator's intent ("expiration en fin de journée le 21 juin EDT").
Also re-patched the relance draft cmp-20260601-f857cd-rem from
2026-06-21T23:59:59Z (= 19:59 EDT, the early-evening cutoff) to
2026-06-22T03:59:59Z (= 23:59:59 EDT, true end of day). Bonus: this
aligns with the original campaign's recipients which expire around
~11:57-12:04 EDT on June 21, so the reminder always works at least
as long as the original — never the inverse confusion.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c55f75739f
commit
ddedd60320
|
|
@ -1132,7 +1132,7 @@ async function sendCampaignAsync (id) {
|
|||
let expiresInDays = ''
|
||||
if (r.gift_expires_at) {
|
||||
const exp = new Date(r.gift_expires_at)
|
||||
expiresAtDate = exp.toLocaleDateString(expiryLocale, { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
expiresAtDate = exp.toLocaleDateString(expiryLocale, { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'America/Montreal' })
|
||||
const days = Math.max(0, Math.ceil((exp - new Date()) / 86400000))
|
||||
expiresInDays = String(days)
|
||||
}
|
||||
|
|
@ -1830,7 +1830,7 @@ async function handle (req, res, method, path) {
|
|||
// as its main urgency line; without it the test email shows an
|
||||
// empty space where the date should be.
|
||||
const sampleExpAt = new Date(Date.now() + 30 * 86400 * 1000)
|
||||
.toLocaleDateString('fr-CA', { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
.toLocaleDateString('fr-CA', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'America/Montreal' })
|
||||
const vars = {
|
||||
firstname: 'Louis',
|
||||
lastname: 'Test',
|
||||
|
|
@ -1878,7 +1878,7 @@ async function handle (req, res, method, path) {
|
|||
const body = await parseBody(req)
|
||||
const html = body.html || fs.readFileSync(templatePath(tplPreview[1]), 'utf8')
|
||||
const sampleExpAt = new Date(Date.now() + 30 * 86400 * 1000)
|
||||
.toLocaleDateString('fr-CA', { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
.toLocaleDateString('fr-CA', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'America/Montreal' })
|
||||
const vars = {
|
||||
firstname: 'Louis', lastname: 'Paul', email: 'louis@targo.ca',
|
||||
description: '123 Rue de Test', gift_url: 'http://gtbt.co/PREVIEW',
|
||||
|
|
@ -1998,7 +1998,7 @@ async function handle (req, res, method, path) {
|
|||
let expiresInDays = ''
|
||||
if (r.gift_expires_at) {
|
||||
const exp = new Date(r.gift_expires_at)
|
||||
expiresAtDate = exp.toLocaleDateString(expiryLocale, { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
expiresAtDate = exp.toLocaleDateString(expiryLocale, { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'America/Montreal' })
|
||||
const days = Math.max(0, Math.ceil((exp - new Date()) / 86400000))
|
||||
expiresInDays = String(days)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user