Atemporal is designed to be fully immutable. Every operation that modifies a date returns a new instance, leaving the original unchanged. This design prevents an entire class of bugs common in date manipulation.
// JavaScript's native Date is mutableconst date = new Date('2024-07-16');const modified = date;modified.setMonth(11); // Modifies BOTH date and modifiedconsole.log(date.getMonth()); // 11 (December) - unexpected!console.log(modified.getMonth()); // 11 (December)
This behavior leads to subtle bugs:
Shared references - Passing dates to functions can unexpectedly modify them
Temporal coupling - Order of operations affects results
Race conditions - Concurrent modifications cause unpredictable behavior
Testing difficulties - Hard to reason about state changes
import atemporal from 'atemporal';function addBusinessDays(date: TemporalWrapper, days: number): TemporalWrapper { // This creates a NEW instance return date.add(days, 'day');}const original = atemporal('2024-07-16');const result = addBusinessDays(original, 5);// Original is unchangedconsole.log(original.format('YYYY-MM-DD')); // 2024-07-16console.log(result.format('YYYY-MM-DD')); // 2024-07-21
Multiple operations can safely work with the same date:
import atemporal from 'atemporal';const date = atemporal('2024-07-16');// These operations are completely independentconst future = date.add(1, 'month');const past = date.subtract(1, 'month');const modified = date.set('hour', 12);const converted = date.timeZone('Asia/Tokyo');// All results are different, date is unchangedconsole.log(date.format('YYYY-MM-DD HH:mm z'));// Output: 2024-07-16 00:00 UTC
/** * Creates a deep copy of the Atemporal instance. * @returns A new, identical TemporalWrapper instance. */clone(): TemporalWrapper { if (!this.isValid()) return this; return this._cloneWith(this.datetime);}
Use .clone() when you want to be explicit about creating a copy:
const date = atemporal('2024-07-16');const copy = date.clone();// Both are separate instancesconsole.log(date === copy); // false
In practice, you rarely need .clone() since all modification methods already return new instances.
import atemporal from 'atemporal';const iterations = 100000;const date = atemporal('2024-07-16');console.time('Immutable operations');for (let i = 0; i < iterations; i++) { const result = date.add(i, 'day');}console.timeEnd('Immutable operations');// Fast even with many operations
import atemporal from 'atemporal';const date = atemporal('2024-07-16');const modified = date.add(1, 'month');// Original unchangedconsole.log(date.month); // 7console.log(modified.month); // 8
const date = new Date('2024-07-16');const modified = date;modified.setMonth(7); // Modifies both!// Both changedconsole.log(date.getMonth()); // 7console.log(modified.getMonth()); // 7
import dayjs from 'dayjs';const date = dayjs('2024-07-16');const modified = date.add(1, 'month');// Original unchangedconsole.log(date.month()); // 6console.log(modified.month()); // 7
import moment from 'moment';const date = moment('2024-07-16');const modified = date.add(1, 'month');// Both changed (unless you clone)console.log(date.month()); // 7console.log(modified.month()); // 7