Tutoriales

Guía Completa de Timestamps en JavaScript

Esta página está disponible temporalmente en inglés. La traducción al español está en preparación.

Introduction

JavaScript provides the Date object for working with dates and timestamps. Understanding how to properly use timestamps in JavaScript is essential for web development, data processing, and time-based applications. This guide covers timestamp fundamentals, conversions, timezone handling, and best practices.

Understanding JavaScript Timestamps

Unix Timestamp in JavaScript

JavaScript uses Unix timestamps in milliseconds since January 1, 1970, 00:00:00 UTC (the Unix epoch):

JavaScript Timestamp = Milliseconds since 1970-01-01 00:00:00 UTC

Example: 1704624000000
  = 1704624000 seconds since epoch
  = January 8, 2024, 12:00:00 PM UTC

Important: JavaScript uses milliseconds while many other systems use seconds. Always verify units when converting.

Current Timestamp

// Current timestamp in milliseconds
const nowMs = Date.now();
console.log(nowMs);  // e.g., 1704624000000

// Alternative method
const nowMs2 = new Date().getTime();
console.log(nowMs2);  // Same as Date.now()

// Convert to seconds
const nowSec = Math.floor(Date.now() / 1000);
console.log(nowSec);  // e.g., 1704624000

Creating Dates

Creating Date Objects

From Timestamp

// Create from milliseconds timestamp
const dateFromMs = new Date(1704624000000);
console.log(dateFromMs.toISOString());  // "2024-01-08T12:00:00.000Z"

// Create from seconds timestamp (multiply by 1000)
const dateFromSec = new Date(1704624000 * 1000);
console.log(dateFromSec.toISOString());  // "2024-01-08T12:00:00.000Z"

From Date Components

// Create from year, month, day (months are 0-indexed!)
const date1 = new Date(2024, 0, 8);  // January 8, 2024
console.log(date1.toISOString());  // "2024-01-08T00:00:00.000Z"

// Create with time
const date2 = new Date(2024, 0, 8, 14, 30, 0);
console.log(date2.toISOString());  // "2024-01-08T14:30:00.000Z"

// Create from string (ISO 8601 recommended)
const date3 = new Date('2024-01-08T14:30:00.000Z');
console.log(date3.toISOString());  // "2024-01-08T14:30:00.000Z"

Common Mistake: JavaScript months are 0-indexed (0 = January, 11 = December)!

Current Date and Time

const now = new Date();

console.log(now.toISOString());        // "2024-01-08T12:34:56.789Z"
console.log(now.toString());           // "Mon Jan 08 2024 07:34:56 GMT-0500"
console.log(now.toDateString());      // "Mon Jan 08 2024"
console.log(now.toTimeString());      // "07:34:56 GMT-0500"
console.log(now.toLocaleString());     // "1/8/2024, 7:34:56 AM"

Getting Date Components

Extracting Date Parts

const date = new Date(2024, 0, 8, 14, 30, 45, 123);

// Get components
console.log(date.getFullYear());      // 2024
console.log(date.getMonth());        // 0 (January - 0-indexed!)
console.log(date.getDate());         // 8 (day of month)
console.log(date.getHours());        // 14 (hour 0-23)
console.log(date.getMinutes());      // 30 (minutes 0-59)
console.log(date.getSeconds());      // 45 (seconds 0-59)
console.log(date.getMilliseconds()); // 123 (milliseconds 0-999)

// Get day of week (0 = Sunday, 6 = Saturday)
console.log(date.getDay());          // 1 (Monday)

// Get UTC components
console.log(date.getUTCFullYear()); // 2024
console.log(date.getUTCHours());   // 19 (if local is 14:30)

Relative Time Components

const date = new Date(2024, 0, 8);

// Get timezone offset (in minutes)
const offset = date.getTimezoneOffset();
console.log(offset);  // e.g., -300 (UTC-5 = -5 * 60)

// Get timestamp
const timestamp = date.getTime();
console.log(timestamp);  // e.g., 1704672000000 (milliseconds)

// Get ISO 8601 string
const isoString = date.toISOString();
console.log(isoString);  // "2024-01-08T00:00:00.000Z"

Setting Date Components

Modifying Dates

const date = new Date(2024, 0, 8);

// Set components (returns timestamp)
date.setFullYear(2025);
date.setMonth(11);      // December
date.setDate(25);
date.setHours(18);
date.setMinutes(30);
date.setSeconds(45);
date.setMilliseconds(0);

console.log(date.toISOString());  // "2025-12-25T18:30:45.000Z"

// Set UTC components
date.setUTCFullYear(2025);
date.setUTCHours(12);

Important: Set methods return the timestamp, not the Date object. Chain carefully:

// Correct: Use same date object
const date = new Date(2024, 0, 8);
date.setDate(15);
date.setMonth(5);  // June 15, 2024

// WRONG: Creates new date, loses changes
const date = new Date(2024, 0, 8);
new Date(date).setDate(15);  // Original date unchanged!

Date Arithmetic

Adding and Subtracting Time

const date = new Date(2024, 0, 8);

// Add 7 days
date.setDate(date.getDate() + 7);
console.log(date.toISOString());  // "2024-01-15T00:00:00.000Z"

// Add 3 hours (3600 * 1000 ms)
date.setTime(date.getTime() + (3 * 3600 * 1000));
console.log(date.toISOString());  // "2024-01-15T03:00:00.000Z"

// Subtract 1 month
date.setMonth(date.getMonth() - 1);
console.log(date.toISOString());  // "2023-12-15T03:00:00.000Z"

// Add 1 year
date.setFullYear(date.getFullYear() + 1);
console.log(date.toISOString());  // "2024-12-15T03:00:00.000Z"

Best Practice: Use timestamp arithmetic for precision:

> // Add 1 hour in milliseconds (60 * 60 * 1000)
> const oneHour = 60 * 60 * 1000;
> const newDate = new Date(date.getTime() + oneHour);
>

Time Differences

const date1 = new Date(2024, 0, 8);
const date2 = new Date(2024, 0, 15);

// Difference in milliseconds
const diffMs = date2 - date1;
console.log(diffMs);  // 604800000 (7 days in ms)

// Convert to seconds, minutes, hours, days
const diffSec = Math.floor(diffMs / 1000);
const diffMin = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));

console.log(`${diffDays} days`);  // "7 days"
console.log(`${diffHours} hours`);  // "168 hours"

Formatting Dates

Built-in Formatting

toLocaleString Family

const date = new Date(2024, 0, 8, 14, 30, 45);

// Locale-specific formats
console.log(date.toLocaleDateString());      // "1/8/2024"
console.log(date.toLocaleTimeString());      // "2:30:45 PM"
console.log(date.toLocaleString());         // "1/8/2024, 2:30:45 PM"

// With locale options
console.log(date.toLocaleDateString('en-US', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}));
// "Monday, January 8, 2024"

console.log(date.toLocaleDateString('zh-CN', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}));
// "2024年1月8日"

International Formats

const date = new Date(2024, 0, 8);

// ISO 8601 (always UTC)
console.log(date.toISOString());  // "2024-01-08T00:00:00.000Z"

// UTC string
console.log(date.toUTCString());  // "Sun, 07 Jan 2024 00:00:00 GMT"

// Date string (local time)
console.log(date.toString());  // "Mon Jan 08 2024 00:00:00 GMT-0500"

Best Practice: Always use toISOString() for API calls and database storage to avoid timezone issues.

Custom Formatting

// Manual formatting (use Intl.DateTimeFormat for i18n)
function formatDate(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

console.log(formatDate(new Date(2024, 0, 8, 14, 30, 45)));
// "2024-01-08 14:30:45"

Recommendation: Use libraries like date-fns, luxon, or day.js for complex formatting instead of manual formatting.

Timezone Handling

Working with Timezones

Getting Timezone Info

const date = new Date();

// Get timezone offset (in minutes)
const offset = date.getTimezoneOffset();
console.log(offset);  // e.g., -300 (UTC-5) or 300 (UTC+5)

// Convert offset to hours
const offsetHours = offset / 60;
console.log(offsetHours);  // -5 or 5

// Get timezone name (browser-specific)
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(timezone);  // e.g., "America/New_York"

Converting Between Timezones

const date = new Date(2024, 0, 8, 14, 30, 0);

// Convert to different timezone using toLocaleString
const nyTime = date.toLocaleString('en-US', {
  timeZone: 'America/New_York',
  timeZoneName: 'short'
});
console.log(nyTime);  // "1/8/2024, 9:30:00 AM EST"

const tokyoTime = date.toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo'
});
console.log(tokyoTime);  // "1/8/2024, 11:30:00 PM"

// Extract time components in specific timezone
const tokyoDate = new Date(date.toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo'
}));
console.log(tokyoDate.getHours());  // 23 (11 PM)

Best Practice: Always work with UTC internally and convert to local timezone only for display.

UTC vs Local Time

const date = new Date(2024, 0, 8, 14, 30, 0);

// Local time methods
console.log(date.getHours());     // Local hour (e.g., 14 for EST)
console.log(date.getTime());    // Timestamp (same regardless of timezone)

// UTC methods
console.log(date.getUTCHours()); // UTC hour (e.g., 19 for EST)
console.log(date.getUTCDate());  // UTC day of month

Parsing Dates

Parsing Date Strings

Using Date Constructor

// ISO 8601 (recommended)
const isoDate = new Date('2024-01-08T14:30:00.000Z');
console.log(isoDate.toISOString());  // "2024-01-08T14:30:00.000Z"

// Short date format (browser-dependent, avoid!)
const shortDate = new Date('01/08/2024');
console.log(shortDate);  // May be Jan 8 or Aug 8 depending on locale

// RFC 2822 format
const rfcDate = new Date('Mon, 08 Jan 2024 14:30:00 GMT');
console.log(rfcDate.toISOString());  // "2024-01-08T14:30:00.000Z"

Problem: Date parsing is inconsistent across browsers and locales.

Manual Parsing

// Parse ISO 8601 string manually
function parseISOString(isoString) {
  const date = new Date(isoString);
  if (isNaN(date.getTime())) {
    throw new Error('Invalid date string');
  }
  return date;
}

// Parse custom format (YYYY-MM-DD)
function parseCustomDate(dateString) {
  const [year, month, day] = dateString.split('-').map(Number);
  return new Date(year, month - 1, day);  // months are 0-indexed
}

console.log(parseCustomDate('2024-01-08').toISOString());
// "2024-01-08T00:00:00.000Z"

Recommendation: Use libraries like date-fns/parse or luxon/DateTime.fromISO for reliable parsing.

Validating Dates

// Check if date is valid
function isValidDate(date) {
  return date instanceof Date && !isNaN(date.getTime());
}

// Examples
const validDate = new Date(2024, 0, 8);
const invalidDate = new Date('invalid');

console.log(isValidDate(validDate));    // true
console.log(isValidDate(invalidDate));  // false
console.log(isNaN(invalidDate.getTime()));  // true (NaN)

Common Pitfalls

Month Indexing

// Common mistake: Using 1-12 for months
const date = new Date(2024, 12, 8);  // January 2025!
console.log(date.toISOString());  // "2025-01-08T00:00:00.000Z"

// Correct: Use 0-11 for months
const date = new Date(2024, 11, 8);  // December 2024
console.log(date.toISOString());  // "2024-12-08T00:00:00.000Z"

Timezone Confusion

const date = new Date(2024, 0, 8, 0, 0, 0);

// These produce different values!
console.log(date.getTime());     // 1704672000000 (same)
console.log(date.toString());     // "Mon Jan 08 2024 00:00:00 GMT-0500"
console.log(date.toISOString()); // "2024-01-08T05:00:00.000Z"

// Midnight EST = 5:00 AM UTC

Problem: Creating dates without timezone info assumes local time.

String Parsing Inconsistencies

// Different browsers may parse differently
const date1 = new Date('2024-01-08');      // Might be Jan 8 or Jan 1
const date2 = new Date('2024/01/08');      // Might be parsed differently
const date3 = new Date('01-08-2024');      // Very ambiguous!

// Always use ISO 8601
const date = new Date('2024-01-08T00:00:00Z');
console.log(date.toISOString());  // Consistent across all browsers

Math Overflow

const date = new Date(2024, 0, 31);

// Add 2 months to Jan 31
date.setMonth(date.getMonth() + 2);
console.log(date.toISOString());  // "2024-03-31T00:00:00.000Z" ✓

// Add 1 month to Jan 31 (February doesn't have 31!)
date.setMonth(date.getMonth() + 1);
console.log(date.toISOString());  // "2024-03-02T00:00:00.000Z" ✓

// JavaScript auto-adjusts overflow

Benefit: JavaScript automatically handles date overflow (Feb 31 → Mar 2 or 3 depending on leap year).

Best Practices

Performance

Avoid Frequent Date Creation

// BAD: Create new Date in loop
for (let i = 0; i < 1000; i++) {
  const now = new Date();
  // ... operations
}

// GOOD: Create once, reuse
const now = new Date();
const timestamp = now.getTime();
for (let i = 0; i < 1000; i++) {
  // ... operations with timestamp
}

Use Timestamp for Comparisons

const date1 = new Date(2024, 0, 8);
const date2 = new Date(2024, 0, 15);

// BAD: Compare Date objects (slow)
if (date1 < date2) { }

// GOOD: Compare timestamps (fast)
if (date1.getTime() < date2.getTime()) { }

// Even better: Use timestamps directly
const ts1 = date1.getTime();
const ts2 = date2.getTime();
if (ts1 < ts2) { }

Cache Timezone Offset

// Cache timezone offset (doesn't change during runtime)
const TZ_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;

// Use in conversions
function toLocalTime(timestamp) {
  return new Date(timestamp + TZ_OFFSET);
}

console.log(toLocalTime(Date.now()));

Data Integrity

// Validate before operations
function safeDateOperation(callback) {
  try {
    const result = callback();
    if (isNaN(result.getTime())) {
      throw new Error('Invalid date result');
    }
    return result;
  } catch (error) {
    console.error('Date operation failed:', error);
    return new Date();  // Return current time as fallback
  }
}

// Usage
const result = safeDateOperation(() => {
  return new Date(invalidInput);
});

Storage Best Practices

// Store as ISO 8601 string
function serializeDate(date) {
  return date.toISOString();
}

// Deserialize from ISO 8601
function deserializeDate(isoString) {
  return new Date(isoString);
}

// Usage in JSON
const data = {
  timestamp: Date.now(),
  isoDate: new Date().toISOString(),
  userCreated: serializeDate(new Date())
};

// Parse from API
const createdDate = deserializeDate(apiResponse.userCreated);

Common Operations

Utility Functions

Start/End of Day

function startOfDay(date) {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  return d;
}

function endOfDay(date) {
  const d = new Date(date);
  d.setHours(23, 59, 59, 999);
  return d;
}

console.log(startOfDay(new Date()).toISOString());
// "2024-01-08T00:00:00.000Z"

Start/End of Week

function startOfWeek(date) {
  const d = new Date(date);
  const day = d.getDay();
  const diff = d.getDate() - day + (day === 0 ? -6 : 1);
  d.setDate(diff);
  return startOfDay(d);
}

function endOfWeek(date) {
  const d = startOfWeek(new Date(date));
  d.setDate(d.getDate() + 6);
  return endOfDay(d);
}

console.log(startOfWeek(new Date(2024, 0, 8)).toISOString());
// "2024-01-01T00:00:00.000Z" (Monday)

Start/End of Month

function startOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}

function endOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth() + 1, 0);
}

console.log(startOfMonth(new Date(2024, 0, 15)).toISOString());
// "2024-01-01T00:00:00.000Z"

console.log(endOfMonth(new Date(2024, 0, 15)).toISOString());
// "2024-01-31T00:00:00.000Z"

Age Calculation

function calculateAge(birthDate) {
  const today = new Date();
  const birth = new Date(birthDate);

  let years = today.getFullYear() - birth.getFullYear();
  const monthDiff = today.getMonth() - birth.getMonth();

  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
    years--;
  }

  return years;
}

console.log(calculateAge('1990-06-15'));
// 33 (assuming current date is 2024-01-08)

Business Days Calculation

function addBusinessDays(startDate, days) {
  const result = new Date(startDate);
  let addedDays = 0;

  while (addedDays < days) {
    result.setDate(result.getDate() + 1);
    const dayOfWeek = result.getDay();

    if (dayOfWeek !== 0 && dayOfWeek !== 6) {  // Not weekend
      addedDays++;
    }
  }

  return result;
}

console.log(addBusinessDays(new Date(2024, 0, 8), 5).toISOString());
// "2024-01-15T00:00:00.000Z" (skips weekend)

Examples and Use Cases

Countdown Timer

function countdown(targetDate) {
  const now = Date.now();
  const target = new Date(targetDate).getTime();
  const diff = target - now;

  if (diff <= 0) {
    return { expired: true };
  }

  const days = Math.floor(diff / (1000 * 60 * 60 * 24));
  const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
  const seconds = Math.floor((diff % (1000 * 60)) / 1000);

  return {
    expired: false,
    days,
    hours,
    minutes,
    seconds,
    totalMs: diff
  };
}

console.log(countdown('2024-12-31'));
// { expired: false, days: 357, hours: 11, minutes: 29, seconds: 12, totalMs: ... }

Relative Time (e.g., "2 hours ago")

function timeAgo(timestamp) {
  const now = Date.now();
  const diff = now - timestamp;
  const seconds = Math.floor(diff / 1000);

  if (seconds < 60) return 'just now';
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours} hour${hours !== 1 ? 's' : ''} ago`;
  const days = Math.floor(hours / 24);
  if (days < 30) return `${days} day${days !== 1 ? 's' : ''} ago`;
  const months = Math.floor(days / 30);
  if (months < 12) return `${months} month${months !== 1 ? 's' : ''} ago`;
  const years = Math.floor(days / 365);
  return `${years} year${years !== 1 ? 's' : ''} ago`;
}

const oneHourAgo = Date.now() - (60 * 60 * 1000);
console.log(timeAgo(oneHourAgo));  // "1 hour ago"

Date Range Validation

function isDateInRange(date, startDate, endDate) {
  const timestamp = date.getTime();
  return timestamp >= startDate.getTime() && timestamp <= endDate.getTime();
}

// Example: Check if date is in Q1 2024
const q1Start = new Date(2024, 0, 1);
const q1End = new Date(2024, 2, 31);
const testDate = new Date(2024, 1, 15);

console.log(isDateInRange(testDate, q1Start, q1End));  // true
console.log(isDateInRange(new Date(2024, 3, 1), q1Start, q1End));  // false

Best Practices Summary

JavaScript Date Checklist

✅ Always use ISO 8601 format ('2024-01-08T14:30:00.000Z') for strings
✅ Work with timestamps internally, convert to Date only for display
✅ Use toISOString() for API calls and database storage
✅ Remember months are 0-indexed (0 = January, 11 = December)
✅ Cache timezone offset and Date.now() to avoid repeated calls
✅ Validate dates with isNaN(date.getTime())
✅ Use Intl.DateTimeFormat for i18n-aware formatting
✅ Consider libraries (date-fns, luxon, day.js) for complex operations
✅ Use timestamp arithmetic for precision (add/subtract milliseconds)
✅ Handle date overflow gracefully (JavaScript auto-adjusts)
❌ Don't use locale-specific strings for parsing (inconsistent across browsers)
❌ Don't mix UTC and local methods in same calculation
❌ Don't create Date objects in loops (reuse or use timestamps)
❌ Don't assume browser timezones (always validate with getTimezoneOffset)
❌ Don't rely on automatic string parsing (use ISO 8601)
❌ Don't forget about DST transitions when calculating business days

Performance Tips

✅ Cache Date.now() instead of calling repeatedly
✅ Use timestamps for comparisons (faster than Date objects)
✅ Minimize Date object creation in loops
✅ Use Math.floor() instead of bitwise operators for readability
✅ Store timezone offset as constant for repeated calculations
❌ Don't use Date.parse() on non-ISO strings (unreliable)
❌ Don't create Date objects in hot code paths
❌ Don't use toLocaleString() in performance-critical sections

Related Tools

Additional Resources

For production applications with complex date/time requirements, consider using libraries like:

  • date-fns: Modular, immutable date utilities
  • luxon: Modern API with timezone support (from Moment.js creators)
  • day.js: Lightweight alternative to Moment.js (2KB)
  • temporal-polyfill: Future TC39 Temporal API proposal

Native Date is sufficient for basic operations, but libraries provide better ergonomics and timezone handling for complex use cases.

Actualizacion

No confundas formato de presentacion con instante. toISOString() siempre usa UTC y toLocaleString() solo cambia la vista; compara y almacena milisegundos, y localiza al mostrar.

Pruébalo

Prueba la conversión de timestamps

Resultado de fecha

¿Necesitas más opciones? Asistente de timestamps JavaScript