Adapter
Date adapter interface for integrating different date libraries.
Type Definition
typescript
interface Adapter {
startOf(date: Date, unit: AdapterUnit, weekStartsOn?: WeekDay): Date
endOf(date: Date, unit: AdapterUnit, weekStartsOn?: WeekDay): Date
add(date: Date, value: number, unit: AdapterUnit): Date
diff(start: Date, end: Date, unit: AdapterUnit): number
}
type AdapterUnit =
| 'year'
| 'quarter'
| 'month'
| 'week'
| 'day'
| 'hour'
| 'minute'
| 'second'
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6Methods
startOf
Get the start of a time unit.
typescript
startOf(date: Date, unit: AdapterUnit, weekStartsOn?: WeekDay): Date- Parameters:
date- Reference dateunit- Time unit to get start ofweekStartsOn- First day of week (0-6, for week unit only)
- Returns: Date at the start of the specified unit
endOf
Get the end of a time unit.
typescript
endOf(date: Date, unit: AdapterUnit, weekStartsOn?: WeekDay): Date- Parameters:
date- Reference dateunit- Time unit to get end ofweekStartsOn- First day of week (0-6, for week unit only)
- Returns: Date at the end of the specified unit
add
Add time to a date.
typescript
add(date: Date, value: number, unit: AdapterUnit): Date- Parameters:
date- Starting datevalue- Amount to add (can be negative)unit- Unit of time to add
- Returns: New date with time added
diff
Calculate difference between dates.
typescript
diff(start: Date, end: Date, unit: AdapterUnit): number- Parameters:
start- Start dateend- End dateunit- Unit to measure difference in
- Returns: Difference as a number in the specified unit
Available Adapters
Native Adapter
Uses JavaScript's built-in Date methods.
typescript
import { createTemporal } from '@allystudio/usetemporal'
import { createNativeAdapter } from '@allystudio/usetemporal/native'
const temporal = createTemporal({
adapter: createNativeAdapter(),
date: new Date()
})Luxon Adapter
Integration with the Luxon library.
typescript
import { createTemporal } from '@allystudio/usetemporal'
import { createLuxonAdapter } from '@allystudio/usetemporal/luxon'
const temporal = createTemporal({
adapter: createLuxonAdapter(),
date: new Date()
})date-fns Adapter
Integration with date-fns library.
typescript
import { createTemporal } from '@allystudio/usetemporal'
import { createDateFnsAdapter } from '@allystudio/usetemporal/date-fns'
const temporal = createTemporal({
adapter: createDateFnsAdapter(),
date: new Date()
})Temporal API Adapter
Future-proof adapter for the TC39 Temporal proposal.
typescript
import { createTemporal } from '@allystudio/usetemporal'
import { createTemporalAdapter } from '@allystudio/usetemporal/temporal'
const temporal = createTemporal({
adapter: createTemporalAdapter(),
date: new Date()
})Implementation Example
Here's how to implement a custom adapter:
typescript
const customAdapter: Adapter = {
startOf(date: Date, unit: AdapterUnit, weekStartsOn = 0): Date {
const d = new Date(date)
switch (unit) {
case 'year':
d.setMonth(0, 1)
d.setHours(0, 0, 0, 0)
break
case 'month':
d.setDate(1)
d.setHours(0, 0, 0, 0)
break
case 'day':
d.setHours(0, 0, 0, 0)
break
// ... other units
}
return d
},
endOf(date: Date, unit: AdapterUnit, weekStartsOn = 0): Date {
// Implementation
},
add(date: Date, value: number, unit: AdapterUnit): Date {
const d = new Date(date)
switch (unit) {
case 'year':
d.setFullYear(d.getFullYear() + value)
break
case 'month':
d.setMonth(d.getMonth() + value)
break
// ... other units
}
return d
},
diff(start: Date, end: Date, unit: AdapterUnit): number {
// Implementation
}
}Usage in Operations
Adapters are used internally by all temporal operations:
typescript
import { period, next } from '@allystudio/usetemporal/operations'
// These operations use the adapter internally
const monthPeriod = period(adapter, new Date(), 'month')
// Uses adapter.startOf() and adapter.endOf()
const nextMonth = next(adapter, monthPeriod)
// Uses adapter.add()Adapter Requirements
Immutability
Adapters must never mutate input dates:
typescript
// ✓ Good - creates new date
add(date: Date, value: number, unit: AdapterUnit): Date {
const result = new Date(date)
// modify result
return result
}
// ✗ Bad - mutates input
add(date: Date, value: number, unit: AdapterUnit): Date {
date.setMonth(date.getMonth() + value) // Don't do this!
return date
}Consistency
All methods must handle edge cases consistently:
typescript
// Month boundaries
startOf(new Date('2024-01-31'), 'month') // 2024-01-01
endOf(new Date('2024-02-15'), 'month') // 2024-02-29 (leap year)
// Week boundaries respect weekStartsOn
startOf(date, 'week', 0) // Sunday start
startOf(date, 'week', 1) // Monday startPrecision
Methods should maintain appropriate precision:
typescript
// startOf should zero out smaller units
startOf(new Date('2024-03-15T14:30:45.123'), 'day')
// Returns: 2024-03-15T00:00:00.000
// endOf should maximize smaller units
endOf(new Date('2024-03-15T14:30:45.123'), 'day')
// Returns: 2024-03-15T23:59:59.999Performance Considerations
- Caching: Adapters can cache frequently used calculations
- Lazy Loading: Heavy date libraries can be lazy loaded
- Native Performance: Native adapter is fastest for simple operations
Testing Adapters
typescript
// Test adapter implementation
function testAdapter(adapter: Adapter) {
const date = new Date('2024-03-15T10:30:00')
// Test startOf
expect(adapter.startOf(date, 'day')).toEqual(
new Date('2024-03-15T00:00:00')
)
// Test endOf
expect(adapter.endOf(date, 'day')).toEqual(
new Date('2024-03-15T23:59:59.999')
)
// Test add
expect(adapter.add(date, 1, 'month')).toEqual(
new Date('2024-04-15T10:30:00')
)
// Test diff
const later = new Date('2024-04-15T10:30:00')
expect(adapter.diff(date, later, 'day')).toBe(31)
}