Skip to content

Migration Guide

This guide helps you migrate from popular date libraries to useTemporal. Each section provides direct comparisons and migration strategies.

Breaking Changes in v2.0.0

Removal of toPeriod Function

The toPeriod function has been removed in v2.0.0 as part of our API simplification efforts. toPeriod was just a wrapper around period with the same functionality.

Before (v1.x)

typescript
import { toPeriod } from '@allystudio/usetemporal';

const dayPeriod = toPeriod(temporal, new Date(), 'day');
const monthPeriod = toPeriod(temporal, date, 'month');

After (v2.0.0)

Level 1 (Pure Functions):

typescript
import { period } from '@allystudio/usetemporal/operations';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const adapter = createNativeAdapter();
const dayPeriod = period(adapter, new Date(), 'day');
const monthPeriod = period(adapter, date, 'month');

Level 2 (Builder):

typescript
import { createTemporal } from '@allystudio/usetemporal';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const temporal = createTemporal({
  adapter: createNativeAdapter(),
  date: new Date()
});

const dayPeriod = temporal.period(new Date(), 'day');
const monthPeriod = temporal.period(date, 'month');

This requires updating the function signature - toPeriod doesn't exist in v2.0.

Rename of createPeriod to period

The createPeriod function has been renamed to period in v2.0.0 to follow a cleaner, more mathematical API style. The function behaves identically - only the name has changed.

Before (v1.x)

typescript
import { createPeriod } from '@allystudio/usetemporal';

const dayPeriod = createPeriod(temporal, new Date(), 'day');
const monthPeriod = createPeriod(temporal, date, 'month');

After (v2.0.0)

Level 1 (Pure Functions):

typescript
import { period } from '@allystudio/usetemporal/operations';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const adapter = createNativeAdapter();
const dayPeriod = period(adapter, new Date(), 'day');
const monthPeriod = period(adapter, date, 'month');

Level 2 (Builder):

typescript
import { createTemporal } from '@allystudio/usetemporal';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const temporal = createTemporal({
  adapter: createNativeAdapter(),
  date: new Date()
});

const dayPeriod = temporal.period(new Date(), 'day');
const monthPeriod = temporal.period(date, 'month');

Note: The function signature has changed - adapter is now the first parameter for pure functions.

Merge of createCustomPeriod into period

The createCustomPeriod function has been merged into the period function in v2.0.0 through function overloading. This reduces the API surface while maintaining all functionality.

Before (v1.x)

typescript
import { createCustomPeriod } from '@allystudio/usetemporal';

const customPeriod = createCustomPeriod(startDate, endDate);

After (v2.0.0)

Level 1 (Pure Functions):

typescript
import { period } from '@allystudio/usetemporal/operations';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const adapter = createNativeAdapter();
const customPeriod = period(adapter, { start: startDate, end: endDate });

Level 2 (Builder):

typescript
import { createTemporal } from '@allystudio/usetemporal';
import { createNativeAdapter } from '@allystudio/usetemporal/native';

const temporal = createTemporal({
  adapter: createNativeAdapter(),
  date: new Date()
});

const customPeriod = temporal.period({ start: startDate, end: endDate });

The period function now accepts two signatures:

  • period(adapter, date, unit) - Creates a standard period (Level 1)
  • period(adapter, { start, end }) - Creates a custom period (Level 1)
  • temporal.period(date, unit) - Builder API (Level 2)
  • temporal.period({ start, end }) - Builder API (Level 2)

StableMonth Moved to Calendar Units Package

The stableMonth unit has been moved from the core library to the @allystudio/usetemporal/calendar package in v2.0.0. This keeps the core library focused on fundamental operations while providing calendar-specific features as an optional enhancement.

Before (v1.x)

typescript
import { period, STABLE_MONTH } from '@allystudio/usetemporal';

const stableMonth = period(temporal, 'stableMonth', date);
// or
const stableMonth = period(temporal, STABLE_MONTH, date);

After (v2.0.0)

Install the calendar units package:

bash
npm install @allystudio/usetemporal/calendar

Then use it:

typescript
import { period } from '@allystudio/usetemporal';
import '@allystudio/usetemporal/calendar'; // Registers stableMonth unit

const stableMonth = period(temporal, 'stableMonth', temporal.browsing.value);
const days = divide(temporal.adapter, stableMonth, 'day'); // Always 42 days

Manual Implementation (if not using calendar-units)

typescript
// Generate 6-week calendar grid manually
const month = period(temporal, 'month', date);
const weeks = divide(temporal.adapter, month, 'week');

// Get all weeks that touch this month
const firstWeek = weeks[0];
const prevWeek = previous(temporal.adapter, firstWeek);
const allWeeks = [prevWeek, ...weeks];

// Ensure 6 weeks total
while (allWeeks.length < 6) {
  const lastWeek = allWeeks[allWeeks.length - 1];
  allWeeks.push(next(temporal.adapter, lastWeek));
}

// Get all days
const days = allWeeks.flatMap(week => divide(temporal.adapter, week, 'day'));

See Calendar Units for more details.

Migration from Moment.js

Basic Date Operations

Moment.js

javascript
import moment from "moment";

// Current time
const now = moment();

// Specific date
const date = moment("2024-03-14");

// Format
const formatted = moment().format("YYYY-MM-DD");

// Add/subtract
const tomorrow = moment().add(1, "day");
const yesterday = moment().subtract(1, "day");

useTemporal

javascript
import { createTemporal } from "@allystudio/usetemporal";
import { createNativeAdapter } from "@allystudio/usetemporal/native";

const temporal = createTemporal({ adapter: createNativeAdapter() });

// Current time
const now = temporal.now;

// Specific date
const date = new Date("2024-03-14");
const day = temporal.periods.day(temporal, { date });

// Format (through adapter or native)
const formatted = day.start.toISOString().split("T")[0];

// Add/subtract
const tomorrow = day.future();
const yesterday = day.past();

Start/End of Period

Moment.js

javascript
// Start of month
const startOfMonth = moment().startOf("month");

// End of month
const endOfMonth = moment().endOf("month");

// Start of week
const startOfWeek = moment().startOf("week");

useTemporal

javascript
// Start/end of month
const month = temporal.periods.month(temporal);
const startOfMonth = month.start;
const endOfMonth = month.end;

// Start/end of week
const week = temporal.periods.week(temporal);
const startOfWeek = week.start;
const endOfWeek = week.end;

Working with Weeks

Moment.js

javascript
// Get week number
const weekNumber = moment().week();

// Get all days in week
const days = [];
const startOfWeek = moment().startOf("week");
for (let i = 0; i < 7; i++) {
  days.push(startOfWeek.clone().add(i, "days"));
}

useTemporal

javascript
// Get week number
const week = temporal.periods.week(temporal);
const weekNumber = week.number;

// Get all days in week - much simpler!
const days = temporal.divide(week, "day");

Relative Time

Moment.js

javascript
// Check if date is in the past
const isPast = moment("2023-01-01").isBefore(moment());

// Check if date is today
const isToday = moment().isSame(date, "day");

// Get days in month
const daysInMonth = moment().daysInMonth();

useTemporal

javascript
// Check if date is in the past
const day = temporal.periods.day(temporal, { date: new Date("2023-01-01") });
const isPast = day.isPast;

// Check if date is today
const isToday = day.isNow;

// Get days in month
const month = temporal.periods.month(temporal);
const daysInMonth = month.days;

Migration from date-fns

Basic Operations

date-fns

javascript
import {
  format,
  addDays,
  startOfMonth,
  endOfMonth,
  getWeek,
  eachDayOfInterval,
} from "date-fns";

const now = new Date();

// Format date
const formatted = format(now, "yyyy-MM-dd");

// Add days
const tomorrow = addDays(now, 1);

// Get start/end of month
const monthStart = startOfMonth(now);
const monthEnd = endOfMonth(now);

// Get week number
const weekNum = getWeek(now);

// Get all days in a range
const days = eachDayOfInterval({
  start: monthStart,
  end: monthEnd,
});

useTemporal

javascript
const temporal = createTemporal({ adapter: createNativeAdapter() });

// Current date
const now = temporal.now;

// Format date (use adapter or native)
const formatted = now.toISOString().split("T")[0];

// Add days
const today = temporal.periods.day(temporal);
const tomorrow = today.future();

// Get start/end of month
const month = temporal.periods.month(temporal);
const monthStart = month.start;
const monthEnd = month.end;

// Get week number
const week = temporal.periods.week(temporal);
const weekNum = week.number;

// Get all days in month - much simpler!
const days = temporal.divide(month, "day");

Advanced date-fns with useTemporal Adapter

For a smoother migration, use the date-fns adapter:

javascript
import { createTemporal } from "@allystudio/usetemporal";
import { createDateFnsAdapter } from "@allystudio/usetemporal/date-fns";
import { format } from "date-fns";

const temporal = createTemporal({
  adapter: createDateFnsAdapter(),
});

// Now you can use date-fns functions on useTemporal dates
const month = temporal.periods.month(temporal);
const formatted = format(month.start, "MMMM yyyy"); // "March 2024"

// But also get useTemporal's powerful features
const weeks = temporal.divide(month, "week");
const days = temporal.divide(month, "day");

Migration from Day.js

Basic Operations

Day.js

javascript
import dayjs from "dayjs";

// Current time
const now = dayjs();

// Parse date
const date = dayjs("2024-03-14");

// Format
const formatted = dayjs().format("YYYY-MM-DD");

// Chain operations
const result = dayjs().startOf("month").add(1, "week").endOf("day");

// Get/set
const year = dayjs().year();
const month = dayjs().month(); // 0-11

useTemporal

javascript
const temporal = createTemporal({ adapter: createNativeAdapter() });

// Current time
const now = temporal.now;

// Work with specific date
const date = new Date("2024-03-14");
const day = temporal.periods.day(temporal, { date });

// Format
const formatted = day.start.toISOString().split("T")[0];

// Equivalent operations
const month = temporal.periods.month(temporal);
const firstWeek = temporal.divide(month, "week")[0];
const endOfFirstWeek = firstWeek.end;

// Get values - note month is 1-12!
const year = temporal.periods.year(temporal);
const monthUnit = temporal.periods.month(temporal);
console.log(year.number); // 2024
console.log(monthUnit.number); // 3 (March, not 2!)

Migration from Luxon

Basic Operations

Luxon

javascript
import { DateTime } from "luxon";

// Current time
const now = DateTime.now();

// Create date
const date = DateTime.fromISO("2024-03-14");

// With timezone
const ny = DateTime.now().setZone("America/New_York");

// Format
const formatted = now.toFormat("yyyy-MM-dd");

// Start of period
const startOfMonth = now.startOf("month");

// Add duration
const tomorrow = now.plus({ days: 1 });

useTemporal with Luxon Adapter

javascript
import { createTemporal } from "@allystudio/usetemporal";
import { createLuxonAdapter } from "@allystudio/usetemporal/luxon";

const temporal = createTemporal({
  adapter: createLuxonAdapter(),
  timeZone: "America/New_York", // planned feature
});

// Current time
const now = temporal.now;

// Work with specific date
const date = new Date("2024-03-14");
const day = temporal.periods.day(temporal, { date });

// Format using Luxon through the adapter
const formatted = temporal.adapter.format(day.start, "yyyy-MM-dd");

// Start of period
const month = temporal.periods.month(temporal);
const startOfMonth = month.start;

// Navigation
const tomorrow = day.future();

Migration from Native Date

Basic Operations

Native JavaScript Date

javascript
// Current time
const now = new Date();

// Create date
const date = new Date(2024, 2, 14); // March 14 (month is 0-indexed!)

// Get components
const year = date.getFullYear();
const month = date.getMonth(); // 0-11
const day = date.getDate();

// Add days (manual calculation)
const tomorrow = new Date(now);
tomorrow.setDate(tomorrow.getDate() + 1);

// Get first day of month (manual)
const firstDay = new Date(date.getFullYear(), date.getMonth(), 1);

// Get last day of month (manual)
const lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);

useTemporal

javascript
const temporal = createTemporal({ adapter: createNativeAdapter() });

// Current time
const now = temporal.now;

// Work with specific date
const date = new Date(2024, 2, 14); // Still March 14
const day = temporal.periods.day(temporal, { date });

// Get components - month is 1-12!
const year = temporal.periods.year(temporal);
const month = temporal.periods.month(temporal);
console.log(year.number); // 2024
console.log(month.number); // 3 (not 2!)
console.log(day.number); // 14

// Add days - much simpler
const tomorrow = day.future();

// Get first/last day of month - automatic
const monthUnit = temporal.periods.month(temporal);
const firstDay = monthUnit.start;
const lastDay = monthUnit.end;

Common Migration Patterns

1. Calendar Generation

Traditional Approach

javascript
// Complex logic to generate calendar with any library
function generateCalendar(year, month) {
  const firstDay = new Date(year, month, 1);
  const lastDay = new Date(year, month + 1, 0);
  const days = [];

  // Add padding days from previous month
  const firstDayOfWeek = firstDay.getDay();
  for (let i = firstDayOfWeek - 1; i >= 0; i--) {
    days.push(new Date(year, month, -i));
  }

  // Add days of current month
  for (let i = 1; i <= lastDay.getDate(); i++) {
    days.push(new Date(year, month, i));
  }

  // Add padding days from next month
  // ... more complex logic

  return days;
}

useTemporal Approach

javascript
// Simple and clear with useTemporal
function generateCalendar(temporal) {
  const month = temporal.periods.month(temporal);
  const weeks = temporal.divide(month, "week");
  
  // Get all days from all weeks that touch this month
  const days = weeks.flatMap(week => temporal.divide(week, "day"));
  return days; // Includes padding days for complete weeks
}

2. Week-Based Calculations

Traditional Approach

javascript
// Get all weeks in a month (complex)
function getWeeksInMonth(date) {
  const startOfMonth = moment(date).startOf("month");
  const endOfMonth = moment(date).endOf("month");
  const weeks = [];

  let current = startOfMonth.clone().startOf("week");
  while (current.isSameOrBefore(endOfMonth)) {
    weeks.push(current.clone());
    current.add(1, "week");
  }

  return weeks;
}

useTemporal Approach

javascript
// Get all weeks in a month (simple)
function getWeeksInMonth(temporal) {
  const month = temporal.periods.month(temporal);
  const weeks = temporal.divide(month, "week");
  return weeks; // That's it!
}

3. Reactive Date Updates

Traditional Approach

javascript
// Manual tracking with other libraries
let currentDate = moment();
let subscribers = [];

function updateDate(newDate) {
  currentDate = newDate;
  subscribers.forEach((fn) => fn(currentDate));
}

function subscribe(fn) {
  subscribers.push(fn);
}

useTemporal Approach

javascript
// Automatic reactivity
import { watch } from "@vue/reactivity";

const temporal = createTemporal({ adapter: createNativeAdapter() });
const month = temporal.periods.month(temporal);

// Automatically updates when date changes
watch(
  () => month.number,
  (newMonth) => {
    console.log(`Month changed to ${newMonth}`);
  }
);

Migration Checklist

When migrating to useTemporal:

  1. Install useTemporal and choose an adapter

    bash
    npm install @allystudio/usetemporal
    # or with your preferred adapter (luxon or date-fns)
    npm install @allystudio/usetemporal luxon
    # or
    npm install @allystudio/usetemporal date-fns
  2. Update imports

    • Remove old date library imports
    • Import createTemporal and your chosen adapter
  3. Initialize temporal instance

    javascript
    const temporal = createTemporal({
      adapter: createNativeAdapter({ weekStartsOn: 1 }), // Configure as needed
    });
  4. Replace date operations

    • Use periods for accessing time units
    • Use divide() for getting collections
    • Use future()/past() for navigation
  5. Update month indexing

    • Remember: useTemporal months are 1-12, not 0-11
  6. Leverage reactive features

    • Use isNow, isPast, isFuture properties
    • Set up watchers for reactive updates
  7. Simplify complex date logic

    • Replace manual calculations with divide()
    • Use week-based calendar generation

Gradual Migration Strategy

You don't have to migrate everything at once:

javascript
// Phase 1: Use useTemporal for new features
const temporal = createTemporal({ adapter: createNativeAdapter() });

// Phase 2: Keep existing date library for formatting
import { format } from "date-fns";

// Phase 3: Combine both during transition
const month = temporal.periods.month(temporal);
const formatted = format(month.start, "MMMM yyyy");

// Phase 4: Gradually replace old patterns
const days = temporal.divide(month, "day"); // Instead of eachDayOfInterval

Need Help?

The useTemporal community is here to help make your migration smooth and successful!

Released under the MIT License.