Time Analysis Patterns
Learn advanced patterns for analyzing and processing time periods using split, merge, and other operations.
Flexible Period Splitting
The split operation provides three powerful approaches for dividing periods:
Split by Count
Divide any period into equal parts:
typescript
import { createTemporal, split, period } from '@allystudio/usetemporal'
const temporal = createTemporal({ date: new Date() })
// Split a quarter into 3 equal parts
const quarter = period(
temporal,
{
start: new Date('2024-01-01'),
end: new Date('2024-03-31')
}
)
const thirds = split(temporal, quarter, { count: 3 })
// Result: 3 custom periods of ~30 days each
// Split a day into 4 parts (6-hour chunks)
const day = temporal.period( new Date(), 'day')
const quarters = split(temporal, day, { count: 4 })
// Result: 4 custom periods of 6 hours eachSplit by Duration
Create chunks of specific duration:
typescript
// Split a year into 2-month chunks
const year = temporal.period( new Date(), 'year')
const bimonthly = split(temporal, year, {
duration: { months: 2 }
})
// Result: 6 periods of 2 months each
// Split a month into weekly chunks
const month = temporal.period( new Date(), 'month')
const weeks = split(temporal, month, {
duration: { weeks: 1 }
})
// Result: 4-5 week periods
// Split a day into 90-minute intervals
const day = temporal.period( new Date(), 'day')
const intervals = split(temporal, day, {
duration: { hours: 1, minutes: 30 }
})
// Result: 16 periods of 90 minutes eachProject Planning
Split project timelines into manageable phases:
typescript
// Split a project timeline into phases
const project = period(
temporal,
{
start: new Date('2024-01-01'),
end: new Date('2024-12-31')
}
)
// Equal phases
const phases = split(temporal, project, { count: 5 })
// Result: 5 equal project phases
// Sprint-based
const sprints = split(temporal, project, {
duration: { weeks: 2 }
})
// Result: ~26 two-week sprints
// Quarterly milestones
const quarters = split(temporal, project, { by: 'quarter' })Data Aggregation
Process large date ranges in batches:
typescript
// Split data range for batch processing
const dataRange = period(
temporal,
{
start: new Date('2023-01-01'),
end: new Date('2023-12-31')
}
)
// Process in monthly batches
const batches = split(temporal, dataRange, { by: 'month' })
for (const batch of batches) {
await processDataForPeriod(batch)
}
// Or process in 10 equal chunks for parallel processing
const chunks = split(temporal, dataRange, { count: 10 })
await Promise.all(
chunks.map(chunk => processDataForPeriod(chunk))
)Time Series Analysis
Analyze trends over different time windows:
typescript
const yearData = period(
temporal,
{
start: new Date('2023-01-01'),
end: new Date('2023-12-31')
}
)
// Weekly analysis
const weeks = split(temporal, yearData, { duration: { weeks: 1 } })
const weeklyAverages = weeks.map(week => ({
period: week,
average: calculateAverage(week)
}))
// Monthly comparison
const months = split(temporal, yearData, { by: 'month' })
const monthlyGrowth = months.map((month, i) => ({
month: month,
growth: i > 0 ? calculateGrowth(months[i-1], month) : 0
}))
// Quarterly reports
const quarters = split(temporal, yearData, { count: 4 })
quarters.forEach((quarter, i) => {
generateQuarterlyReport(quarter, i + 1)
})Handling Edge Cases
Uneven Splits
When splitting by count, the last period accounts for rounding:
typescript
const timePeriod = period(
temporal,
{
start: new Date('2024-01-01'),
end: new Date('2024-01-10') // 10 days
}
)
const parts = split(temporal, timePeriod, { count: 3 })
// parts[0]: ~3.33 days
// parts[1]: ~3.33 days
// parts[2]: ~3.34 days (includes remainder)Duration Overflow
When splitting by duration, the last period may be shorter:
typescript
const month = temporal.period( new Date('2024-02-01'), 'month')
const weeks = split(temporal, month, {
duration: { weeks: 1 }
})
// Last week may be partial (1-3 days in February)Complex Durations
Multiple duration units are added together:
typescript
const period = split(temporal, year, {
duration: {
months: 1,
weeks: 2
}
})
// Each chunk is 1 month + 2 weeks (~6 weeks)Comparison: split vs divide
| Feature | divide | split |
|---|---|---|
| Split by unit | ✓ | ✓ (with by option) |
| Split by count | ✗ | ✓ |
| Split by duration | ✗ | ✓ |
| Returns | Standard periods | Custom periods (except with by) |
| Use case | Calendar units | Flexible divisions |
typescript
// These are equivalent:
divide(temporal.adapter, year, 'month')
split(temporal, year, { by: 'month' })
// But split offers more:
split(temporal, year, { count: 10 }) // 10 equal parts
split(temporal, year, { duration: { days: 30 } }) // 30-day chunksMerging Periods
Combine multiple periods into larger units:
typescript
// Merge weeks into a month
const weeks = divide(temporal.adapter, month, 'week')
const mergedMonth = merge(temporal.adapter, weeks)
// Combine business days
const workDays = days.filter(day => !isWeekend(day))
const workPeriod = merge(temporal.adapter, workDays)Advanced Analysis Patterns
Rolling Windows
typescript
function rollingAverage(data: Period[], windowSize: number) {
const results = []
for (let i = windowSize - 1; i < data.length; i++) {
const window = data.slice(i - windowSize + 1, i + 1)
const merged = merge(temporal.adapter, window)
results.push({
period: merged,
average: calculateAverage(merged)
})
}
return results
}
// 7-day rolling average
const days = divide(temporal.adapter, month, 'day')
const rolling7Day = rollingAverage(days, 7)Period Overlap Detection
typescript
function findOverlaps(periods: Period[]): Array<[Period, Period]> {
const overlaps = []
for (let i = 0; i < periods.length - 1; i++) {
for (let j = i + 1; j < periods.length; j++) {
if (contains(temporal.adapter, periods[i], periods[j].start) ||
contains(temporal.adapter, periods[j], periods[i].start)) {
overlaps.push([periods[i], periods[j]])
}
}
}
return overlaps
}
// Check meeting conflicts
const meetings = [/* array of meeting periods */]
const conflicts = findOverlaps(meetings)Gap Analysis
typescript
function findGaps(periods: Period[], container: Period): Period[] {
const sorted = periods.sort((a, b) =>
a.start.getTime() - b.start.getTime()
)
const gaps = []
let lastEnd = container.start
for (const period of sorted) {
if (period.start > lastEnd) {
gaps.push(temporal.period({ start: lastEnd, end: period.start }))
}
lastEnd = period.end > lastEnd ? period.end : lastEnd
}
if (lastEnd < container.end) {
gaps.push(temporal.period({ start: lastEnd, end: container.end }))
}
return gaps
}
// Find free time slots
const meetings = [/* array of meeting periods */]
const workDay = period(
temporal,
{
start: new Date('2024-01-15T09:00:00'),
end: new Date('2024-01-15T17:00:00')
}
)
const freeSlots = findGaps(meetings, workDay)See Also
- divide() Pattern - Core division concepts
- Business Logic Patterns - Practical applications
- split - API reference
- merge - API reference