| 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... |
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).
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()}`)
| 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 |
- Parsing API responses with date strings
- Converting Unix timestamps from databases
- Validating event dates (future/past)
- Ensuring date ranges make sense