Troubleshooting Guide
This guide helps you resolve common issues when working with useTemporal. Each section includes symptoms, causes, and solutions.
Installation Issues
Module Resolution Errors
Symptom:
Cannot find module '@usetemporal/core' or its corresponding type declarations.Cause: Package not installed or incorrect import path.
Solution:
# Ensure packages are installed
npm install @usetemporal/core @usetemporal/adapter-native
# For TypeScript projects
npm install -D @types/nodeVerify installation:
// Correct import
import { createTemporal } from "@usetemporal/core";
import { nativeAdapter } from "@usetemporal/adapter-native";
// NOT this (common mistake)
import { createTemporal } from "usetemporal"; // Wrong!ESM/CommonJS Conflicts
Symptom:
SyntaxError: Cannot use import statement outside a moduleCause: useTemporal is ESM-only, but your project is using CommonJS.
Solution:
- Update package.json:
{
"type": "module"
}- Or use dynamic imports:
// For CommonJS environments
async function setupTemporal() {
const { createTemporal } = await import("@usetemporal/core");
const { nativeAdapter } = await import("@usetemporal/adapter-native");
return createTemporal({ dateAdapter: nativeAdapter });
}- For Vite/webpack projects, configure build tool:
// vite.config.js
export default {
optimizeDeps: {
include: ["@usetemporal/core", "@vue/reactivity"],
},
};Runtime Errors
Missing Date Adapter
Symptom:
Error: A date adapter is required. Please install and provide an adapter from @usetemporal/adapter-* packages.Cause: No date adapter provided to createTemporal.
Solution:
// ❌ Wrong
const temporal = createTemporal(); // No adapter!
// ✅ Correct
import { nativeAdapter } from "@usetemporal/adapter-native";
const temporal = createTemporal({
dateAdapter: nativeAdapter,
});Invalid Date Errors
Symptom:
TypeError: Cannot read properties of undefined (reading 'getFullYear')
Invalid DateCause: Passing invalid date to temporal.
Solution:
// Check dates before using
function safePeriod(temporal, date) {
if (!date || isNaN(date.getTime())) {
console.warn("Invalid date provided:", date);
date = new Date(); // Fallback to current date
}
return temporal.periods.day(temporal, { date });
}
// Validate user input
const userDate = new Date(userInput);
if (isNaN(userDate.getTime())) {
throw new Error("Invalid date format");
}Timezone Offset Issues
Symptom:
Day shows as previous/next day
Hour is off by timezone offsetCause: JavaScript Date uses local timezone.
Solution:
// Be explicit about timezone handling
const date = new Date("2024-03-14T00:00:00.000Z"); // UTC
const localDate = new Date(2024, 2, 14); // Local timezone
// Use adapter that handles timezones
import { luxonAdapter } from "@allystudio/usetemporal/luxon";
const temporal = createTemporal({
dateAdapter: luxonAdapter,
timeZone: "America/New_York", // Future feature
});Reactivity Issues
Changes Not Updating
Symptom:
- UI doesn't update when navigating dates
- Reactive properties seem frozen
Cause: Not using reactive references correctly.
Solution:
// ❌ Wrong - breaks reactivity
let month = temporal.periods.month(temporal);
month = month.future(); // Creates new object, loses reactivity
// ✅ Correct - maintain reactivity
import { ref } from "@vue/reactivity";
const currentDate = ref(new Date());
const temporal = createTemporal({
dateAdapter: nativeAdapter,
date: currentDate, // Pass reactive ref
});
// Update the ref to trigger reactivity
currentDate.value = new Date(2024, 3, 1);Memory Leaks with Watchers
Symptom:
- Memory usage increases over time
- Performance degrades
Cause: Not cleaning up watchers.
Solution:
// Vue 3
import { watch, onUnmounted } from "vue";
const stopWatcher = watch(
() => month.number,
(newMonth) => {
console.log("Month changed:", newMonth);
}
);
// Clean up
onUnmounted(() => {
stopWatcher();
});
// React
import { useEffect } from "react";
useEffect(() => {
const unwatch = watch(
() => month.number,
(newMonth) => {
console.log("Month changed:", newMonth);
}
);
return () => unwatch();
}, []);Divide Pattern Issues
Unexpected Number of Units
Symptom:
const days = temporal.divide(month, "day");
console.log(days.length); // Expected 31, got 35Cause: Month period might include partial weeks.
Solution:
// For calendar displays, generate a 6-week grid
const month = temporal.periods.month(temporal);
const weeks = temporal.divide(month, "week");
// Get all weeks that touch this month
const firstWeek = weeks[0];
const prevWeek = firstWeek.past();
const allWeeks = [prevWeek, ...weeks];
// Ensure 6 weeks total
while (allWeeks.length < 6) {
const lastWeek = allWeeks[allWeeks.length - 1];
allWeeks.push(lastWeek.future());
}
const calendarDays = allWeeks.flatMap(week => temporal.divide(week, "day"));
console.log(calendarDays.length); // Always 42
// For exact month days
const monthDays = temporal
.divide(month, "day")
.filter((day) => day.month === month.number);Performance Issues with Large Divides
Symptom:
- Browser freezes
- "Maximum call stack exceeded"
Cause: Dividing large time periods into small units.
Solution:
// ❌ Avoid
const year = temporal.periods.year(temporal);
const minutes = temporal.divide(year, "minute"); // 525,600 objects!
// ✅ Better approach
function* generateMinutes(year) {
const months = temporal.divide(year, "month");
for (const month of months) {
const days = temporal.divide(month, "day");
for (const day of days) {
const hours = temporal.divide(day, "hour");
for (const hour of hours) {
const minutes = temporal.divide(hour, "minute");
yield* minutes;
}
}
}
}
// Use generator for large datasets
for (const minute of generateMinutes(year)) {
if (shouldProcess(minute)) {
processMinute(minute);
}
}Browser Compatibility
Proxy Not Supported
Symptom:
TypeError: Proxy is not definedCause: Old browser without Proxy support.
Solution:
// Check browser support
if (typeof Proxy === "undefined") {
console.error("Your browser does not support Proxy. Please upgrade.");
// Load polyfill or show upgrade message
}
// Or use feature detection
const isProxySupported = typeof Proxy !== "undefined";
if (!isProxySupported) {
// Fallback to non-reactive date handling
}Intl API Issues
Symptom:
- Month/day names showing as numbers
- Incorrect locale formatting
Cause: Limited Intl support in browser.
Solution:
// Check Intl support
const intlSupported = typeof Intl !== "undefined" && Intl.DateTimeFormat;
// Provide fallbacks
const monthNames = intlSupported
? undefined
: ["January", "February" /* ... */];
// Use polyfill if needed
import "@formatjs/intl-datetimeformat/polyfill";Configuration Issues
Week Start Day Not Working
Symptom:
- Weeks still start on wrong day
- Calendar layout incorrect
Cause: Configuration not applied to adapter.
Solution:
// Ensure configuration is passed to adapter
const temporal = createTemporal({
dateAdapter: nativeAdapter,
weekStartsOn: 1, // Monday
});
// Verify in divide operations
const week = temporal.periods.week(temporal);
const days = temporal.divide(week, "day");
console.log(days[0].dayOfWeek); // Should be 1 (Monday)Locale Not Applying
Symptom:
- Month names in English despite locale setting
- Date formats not localized
Cause: Adapter doesn't support locale or incorrect configuration.
Solution:
// Use adapter that supports locales
import { luxonAdapter } from "@allystudio/usetemporal/luxon";
const temporal = createTemporal({
dateAdapter: luxonAdapter,
locale: "fr-FR", // French
});
// Or format manually
const formatter = new Intl.DateTimeFormat("fr-FR", {
month: "long",
});
const monthName = formatter.format(month.start);Common Mistakes
1. Mutating Date Objects
Problem:
const date = temporal.now;
date.setMonth(date.getMonth() + 1); // Mutates!Solution:
// Create new dates
const nextMonth = new Date(date);
nextMonth.setMonth(date.getMonth() + 1);
// Or use temporal navigation
const currentMonth = temporal.periods.month(temporal);
const nextMonth = currentMonth.future();2. Comparing Time Units Incorrectly
Problem:
const day1 = temporal.periods.day(temporal);
const day2 = temporal.periods.day(temporal);
console.log(day1 === day2); // false!Solution:
// Compare by value
const isSameDay = day1.start.getTime() === day2.start.getTime();
// Or use adapter comparison
const isSame = adapter.isSame(day1.start, day2.start, "day");3. Assuming Month Numbers
Problem:
// Expecting JavaScript's 0-indexed months
if (month.number === 0) {
// Never true!
console.log("January");
}Solution:
// useTemporal uses 1-12 for months
if (month.number === 1) {
console.log("January");
}Debugging Tips
1. Enable Verbose Logging
// Debug temporal instance
function debugTemporal(temporal) {
console.log("Current date:", temporal.now);
console.log("Configuration:", {
adapter: temporal.adapter?.name,
weekStartsOn: temporal.weekStartsOn,
});
}
// Debug time unit
function debugTimeUnit(unit) {
console.log("Time Unit Debug:", {
type: unit._type,
start: unit.start,
end: unit.end,
isNow: unit.isNow,
number: unit.number,
});
}2. Validate Divide Results
function validateDivide(parent, children, expectedCount) {
console.assert(
children.length === expectedCount,
`Expected ${expectedCount} units, got ${children.length}`
);
// Check continuity
for (let i = 1; i < children.length; i++) {
const prevEnd = children[i - 1].end.getTime();
const currentStart = children[i].start.getTime();
console.assert(
Math.abs(prevEnd - currentStart) < 1000,
`Gap between units at index ${i}`
);
}
}3. Use Browser DevTools
// Add temporal to window for debugging
if (process.env.NODE_ENV === "development") {
window.__temporal = temporal;
window.__debugTimeUnit = (unit) => {
console.table({
start: unit.start.toISOString(),
end: unit.end.toISOString(),
isNow: unit.isNow,
isPast: unit.isPast,
isFuture: unit.isFuture,
});
};
}Getting Help
If you're still experiencing issues:
- Check the Examples: Review the examples for working code
- API Reference: Consult the API documentation
- GitHub Issues: Search or create an issue on GitHub
- Community: Join our Discord/Slack for community support
When reporting issues, please include:
- useTemporal version
- Date adapter being used
- Browser/Node version
- Minimal reproduction code
- Error messages and stack traces
Remember: Most issues are related to timezone handling, incorrect imports, or misunderstanding the 1-indexed months. Check these first!