Skip to content

Latest commit

 

History

History
168 lines (139 loc) · 4.34 KB

File metadata and controls

168 lines (139 loc) · 4.34 KB
id schema-date-validation
title Date Validation and Parsing
category primitives
skillLevel beginner
tags
schema
date
validation
parsing
timestamp
lessonOrder 15
rule
description
Date Validation and Parsing using Schema.
summary Dates arrive in many formats: ISO strings, Unix timestamps, Date objects. JavaScript's Date constructor silently accepts invalid input ("Invalid Date"). You need to parse dates safely and validate...

Problem

Dates arrive in many formats: ISO strings, Unix timestamps, Date objects. JavaScript's Date constructor silently accepts invalid input ("Invalid Date"). You need to parse dates safely and validate they make sense (not in the past, not too far in the future).

Solution

import { Schema } from "effect"

// ============================================
// BUILT-IN DATE SCHEMAS
// ============================================

// Date object validation
const DateSchema = Schema.Date
// ✅ new Date() → Date
// ❌ "not a date" → ParseError

// Parse date from ISO string
const DateFromString = Schema.DateFromString
// ✅ "2024-01-15T10:30:00Z" → Date
// ❌ "invalid" → ParseError

// ============================================
// CUSTOM DATE PARSING
// ============================================

// Unix timestamp (seconds) to Date
const DateFromUnix = Schema.transform(
  Schema.Number,
  Schema.DateFromSelf,
  {
    decode: (timestamp) => new Date(timestamp * 1000),
    encode: (date) => Math.floor(date.getTime() / 1000),
  }
)

// Unix timestamp (milliseconds) to Date
const DateFromMillis = Schema.transform(
  Schema.Number,
  Schema.DateFromSelf,
  {
    decode: (ms) => new Date(ms),
    encode: (date) => date.getTime(),
  }
)

// ============================================
// DATE REFINEMENTS
// ============================================

// Valid date (not "Invalid Date")
const ValidDate = Schema.Date.pipe(
  Schema.filter(
    (d) => !isNaN(d.getTime()),
    { message: () => "Invalid date" }
  )
)

// Date must be in the future
const FutureDate = Schema.Date.pipe(
  Schema.filter(
    (d) => d.getTime() > Date.now(),
    { message: () => "Date must be in the future" }
  )
)

// Date must be in the past
const PastDate = Schema.Date.pipe(
  Schema.filter(
    (d) => d.getTime() < Date.now(),
    { message: () => "Date must be in the past" }
  )
)

// Date within range
const RecentDate = Schema.Date.pipe(
  Schema.filter(
    (d) => {
      const oneYearAgo = Date.now() - 365 * 24 * 60 * 60 * 1000
      return d.getTime() >= oneYearAgo && d.getTime() <= Date.now()
    },
    { message: () => "Date must be within the last year" }
  )
)

// ============================================
// USING IN STRUCTS
// ============================================

const Event = Schema.Struct({
  title: Schema.String,
  startDate: FutureDate,
  endDate: FutureDate,
})

const APIPayload = Schema.Struct({
  userId: Schema.String,
  createdAt: DateFromString,    // ISO string from JSON
  timestamp: DateFromUnix,       // Unix seconds
})

// Decode from different formats
const decodeEvent = Schema.decodeUnknownSync(Event)
const decodePayload = Schema.decodeUnknownSync(APIPayload)

// Future date validation
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000)
const nextWeek = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)

const event = decodeEvent({
  title: "Conference",
  startDate: tomorrow,
  endDate: nextWeek,
})
console.log(`✅ Event: ${event.title} starts ${event.startDate.toDateString()}`)

// Parse from API payload
const payload = decodePayload({
  userId: "user_123",
  createdAt: "2024-01-15T10:30:00Z",
  timestamp: 1705318200,
})
console.log(`✅ Created: ${payload.createdAt.toISOString()}`)

Why This Works

Schema Purpose
Schema.Date Validates Date objects
Schema.DateFromString Parses ISO strings to Date
Schema.DateFromSelf Date-to-Date (for transforms)
transform Convert timestamps to Date
filter Custom date constraints

When to Use

  • Parsing API responses with date strings
  • Converting Unix timestamps from databases
  • Validating event dates (future/past)
  • Ensuring date ranges make sense

Related Patterns