Agent SkillsAgent Skills
git-tao

timezone-safety

@git-tao/timezone-safety
git-tao
0
0 forks
Updated 4/7/2026
View on GitHub

Prevents timezone-related bugs. Apply when working with dates, times, or timestamps.

Installation

$npx agent-skills-cli install @git-tao/timezone-safety
Claude Code
Cursor
Copilot
Codex
Antigravity

Details

Path.claude/skills/timezone-safety/SKILL.md
Branchmain
Scoped Name@git-tao/timezone-safety

Usage

After installing, this skill will be available to your AI coding assistant.

Verify installation:

npx agent-skills-cli list

Skill Instructions


name: timezone-safety description: "Prevents timezone-related bugs. Apply when working with dates, times, or timestamps."

Timezone Safety Skill

Prevents timezone bugs from mixing naive and aware datetimes.

When to Apply

  • Any Date/datetime usage
  • Timestamp fields in database
  • API responses with dates
  • Date comparisons
  • Storing/retrieving timestamps

Core Rules

1. Always Use UTC Internally

JavaScript/TypeScript:

// Get UTC timestamp
const now = new Date();
const utcString = now.toISOString();  // "2025-01-07T12:00:00.000Z"

// Parse ISO string (preserves UTC)
const parsed = new Date("2025-01-07T12:00:00.000Z");

Python:

from datetime import datetime, UTC

# CORRECT
now = datetime.now(UTC)

# WRONG - naive datetime
now = datetime.now()      # No timezone!
now = datetime.utcnow()   # Deprecated, still naive!

2. Database: Use TIMESTAMPTZ

-- CORRECT
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()

-- WRONG - ambiguous timezone
created_at TIMESTAMP

3. API Responses: ISO Format

// CORRECT - ISO 8601 with timezone
return { created_at: order.createdAt.toISOString() };
// Returns: "2025-01-15T10:30:00.000Z"

// WRONG - loses timezone
return { created_at: order.createdAt.toLocaleDateString() };

4. Display: Convert at UI Layer

// Backend sends UTC, frontend converts for display
const utcDate = new Date(response.created_at);
const localDisplay = utcDate.toLocaleString();

// Better formatting
const formatted = utcDate.toLocaleString('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit'
});

Common Bugs

Stripe Timestamps

// Stripe returns Unix seconds
const stripeTimestamp = event.created;  // 1705312200

// WRONG - missing * 1000
const date = new Date(stripeTimestamp);

// CORRECT - convert to milliseconds
const date = new Date(stripeTimestamp * 1000);

Date Comparison

// WRONG - may compare different timezones
if (expiresAt < new Date()) { ... }

// CORRECT - compare timestamps
if (new Date(expiresAt).getTime() < Date.now()) { ... }

Token Expiration

// Store as UTC timestamp
const expiresAt = new Date(Date.now() + 3600000).toISOString();

// Compare correctly
const isExpired = new Date(token.expiresAt).getTime() < Date.now();

Best Practices

WhatHow
StoreAlways TIMESTAMPTZ
Createnew Date().toISOString()
API responseISO 8601 with Z suffix
DisplayConvert to local at UI layer
CompareUse .getTime() timestamps
StripeMultiply by 1000

Detection

# Find potential issues
grep -rn "new Date()" src/
grep -rn "datetime.now()" backend/
grep -rn "TIMESTAMP[^T]" --include="*.sql"