# Date Timezone

> Handle date and timezone conversions correctly in forms and displays. Use when working with: Date inputs, new Date(), formatDate, toLocaleDateString, getDate(), getMonth(), getFullYear(), date parsing, UTC conversion, timezone issues, dates displaying wrong day, date-only fields in forms, YYYY-MM-DD parsing. Triggers: dates off by one day, timezone bugs, form date handling, competition dates, event dates, calendar dates.

- Skill: `majiayu000/date-timezone` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/date-timezone`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/date-timezone/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/date-timezone

---


# Date & Timezone Handling

## The Problem

HTML5 date inputs return strings like `"2024-01-15"`. When parsed with `new Date("2024-01-15")`, JavaScript treats this as **UTC midnight**, not local midnight. This causes dates to display incorrectly across timezones.

**Example bug:** User in Pacific timezone (-8) selects Jan 15 → stored as Jan 15 00:00 UTC → displayed using `getDate()` → shows Jan 14 (because UTC midnight is 4pm previous day in Pacific).

## Solution: Use UTC Consistently for Date-Only Fields

For fields that represent calendar dates (not specific moments in time):
1. **Parse** form strings as UTC midnight
2. **Display** using UTC methods

## Utilities in `src/utils/date-utils.ts`

### For Form Inputs

```typescript
import { parseDateInputAsUTC, formatDateInputFromUTC } from "@/utils/date-utils"

// Parsing: form string → Date for server
parseDateInputAsUTC("2024-01-15") // → Date at UTC midnight

// Formatting: Date from DB → form string
formatDateInputFromUTC(date) // → "2024-01-15"
```

### For Display

```typescript
import { formatUTCDateShort, formatUTCDateFull, formatUTCDateRange } from "@/utils/date-utils"

formatUTCDateShort(date)  // → "Jan 15"
formatUTCDateFull(date)   // → "Jan 15, 2024"
formatUTCDateRange(start, end) // → "January 15-17, 2024"
```

## When to Use What

| Scenario | Use |
|----------|-----|
| Date-only form field (start date, end date) | `parseDateInputAsUTC` on submit, `formatDateInputFromUTC` for default value |
| Displaying calendar dates | `formatUTCDateShort`, `formatUTCDateFull`, `formatUTCDateRange` |
| Timestamps (createdAt, updatedAt) | Local time methods are fine (these are actual moments) |

## Common Mistakes to Avoid

```typescript
// BAD - parses as UTC, displays as local
new Date("2024-01-15")
date.getDate()
date.toLocaleDateString()

// GOOD - consistent UTC handling
parseDateInputAsUTC("2024-01-15")
date.getUTCDate()
formatUTCDateFull(date)
```

## Form Pattern

```typescript
// In form component
import { parseDateInputAsUTC, formatDateInputFromUTC } from "@/utils/date-utils"

// Default values (for edit forms)
const form = useForm({
  defaultValues: {
    startDate: formatDateInputFromUTC(existingData.startDate),
  }
})

// On submit
function onSubmit(data) {
  saveToServer({
    startDate: parseDateInputAsUTC(data.startDate),
  })
}
```

