Dates in Javascript

new Date(...)

let today = new Date()

console.log('today', today) // This will automatically represent today

console.log('today - valueOf', today.valueOf()) // Returns a number MS since the UNIX epoch (midnight Jan 1 1970 UTC)

console.log('today - toString', today.toString()) // Returns the date in local timezone 

Copy paste from java.util.date

  • 1995 duplication
  • All dates are UTC based internally
  • Most methods return local time values
  • Limited timezone support

Parsing Inconsistencies

// Same date, different string formats
let day1 = new Date('2023-01-09');       // 2023-01-09T00:00:00Z (UTC)
let day2 = new Date('2023-1-9');         // 2023-01-09T00:00:00 (local time) 😭
let day3 = new Date('01/09/2023');       // 2023-01-09T00:00:00 (local time) 😭
let day4 = new Date('2023-01-9');        // 2023-01-09T00:00:00 (local time) 😭

// Let's compare the dates 

console.log('day1 & day2', day1.getTime() === day2.getTime())
console.log('day2 & day3', day2.getTime() === day3.getTime())
console.log('day3 & day4', day3.getTime() === day4.getTime())

// Let's look at their epoch time values

console.log('day1', day1.getTime())
console.log('day2', day2.getTime())
console.log('day3', day3.getTime())
console.log('day4', day4.getTime())

API naming conventions

// SetYear() vs setFullYear()
const setYearExample = new Date();

setYearExample.setYear(98);

console.log('setYearExample', setYearExample.toString());

setYearExample.setFullYear(98)

console.log('setYearExample', setYearExample.toString());

Server -> Client -> Server

// The server sends the time

// '2024-02-28' to represent midnight on Feb 28 2024
// and we parse it.

let serverTime = new Date('2024-02-28')

// The user does some operations of some sort and we patch the changes.
// we create the date to send it back and the server only keeps the difference

let time = `${serverTime.getYear()}-${serverTime.getMonth()}-${serverTime.getDate()}`

/*

 {
   clientName: 'Justin',
   ....
   date: time
 }
*/


// What is the problem here?

Server -> Client -> Server

// The server sends the time

// '2024-02-28' to represent midnight on Feb 28 2024
// and we parse it.

let serverTime = new Date('2024-02-28')

// 1. GetMonth is 0 based but getDate is not... 

console.log('serverTime.getMonth()', serverTime.getMonth())

let time = `${serverTime.getYear()}-${serverTime.getMonth() + 1}-${serverTime.getDate()}`

Problem 1

Server -> Client -> Server

// The server sends the time

// '2024-02-28' to represent midnight on Feb 28 2024
// and we parse it.

let serverTime = new Date('2024-02-28')

// 1. GetMonth is 0 based but getDate is not...
// 2. GetYear is not at all what we need

console.log('serverTime.getYear()', serverTime.getYear(), 'serverTime.getFullYear()', serverTime.getFullYear())

let time = `${serverTime.getFullYear()}-${serverTime.getMonth() + 1}-${serverTime.getDate()}`

Problem 2

Server -> Client -> Server

// The server sends the time

// '2024-02-28' to represent midnight on Feb 28 2024
// and we parse it.

// 1. GetMonth is 0 based but getDate is not...
// 2. GetYear is not at all what we need...
// 3. The parsing issue strikes again...

let sad = '😭';
let jsDateObject = 'inconsistent, immutable, and _bad_'

Problem 3

MomentJS

2011 - 2023

Consistent Parsing

let m1 = moment('2023-03-01');      // Always parses as local time by default
let m2 = moment('2023/03/01');      // Also parses as local time


console.log('m1', m1.toString());
console.log('m2', m2.toString());

Easy Formatting

let m = moment('2025-01-01T00:00:00-05:00');

console.log('m formatted', m.tz('Asia/Tokyo').format('YYYY-MM-DD HH:mm:ss')); // "2025-01-01 14:00:00"

Date Arithmetic

let m = moment();
let nextWeek = m.add(7, 'days');

console.log('m', m.toString());
console.log('nextWeek', nextWeek.toString())

The MomentJS Cons

  • Monolithic libary - 200 KB minimfied
  • No modularity
  • Mutability
  • Slower than modern alternatives
  • Deprecated
  • Timezones are less robust than modern alternatives

Luxon

2015 - ????

Pros

- Immutable API

- leverages browser intl api

- modular (tree shaking)

- faster than moment

Cons

- Smaller community than moment

- Browser dependency for intl features

- migration required

 

Temporal

2025 - ????

Reliable Parsing

let sd1 = new Date('2025-03-01'); // Interpreted as UTC in some browsers, local time in others  
let sd2 = new Date('March 1, 2025'); // May fail in non-US locales 

let d1 = Temporal.PlainDate.from('2025-03-01'); // Strict ISO 8601 parsing [1][4]  
let d2 = Temporal.PlainDateTime.from('2025-03-01T14:30:00'); // Explicit time handling 


// Error when you use a non ISO 8601 date
Temporal.PlainDate.from('2025/03/01') 

https://tc39.es/proposal-temporal/docs/#string-persistence-parsing-and-formatting

Immutable

let date = Temporal.PlainDate.from('2025-03-01');  
const newDate = date.add({ days: 7 }); // Returns new instance [1][6]  
console.log('date', date.toString()); // '2025-03-01' (unchanged)
console.log('newDate', newDate.toString())

Time zones

// Native conflates local/UTC time unexpected
// 
// 
// Moment requires a plugin
// 

// Conversion
let now1 = Temporal.Now.instant()
let now2 = now1.toZonedDateTimeISO('Asia/Tokyo'); // IANA Time Zone Identifiers
console.log('now1', now1.toString());
console.log('now2', now2.toString());

// direct creation
// 
let now3 = Temporal.Now.zonedDateTimeISO('Europe/Paris'); 
console.log('now3', now3.toString()); 

Time Arihmetic

// Original
// 
const oStart = new Date('2025-03-01');  
const oEnd = new Date('2025-03-08');  
const oDiff = oEnd - oStart; // Milliseconds, no direct day/month support

// Moment can use `.diff`
// 

const tStart = Temporal.PlainDate.from('2025-03-01');  
const tEnd = Temporal.PlainDate.from('2025-03-08');  
const tDiff = tStart.until(tEnd).days; // 7


console.log('original date diff', oDiff);
console.log('Temporal date diff', tDiff)

Gregorian

// Original only supports Gregorian calendars
// 
let hebrewDate = Temporal.PlainDate.from({  
  calendar: 'hebrew',  
  year: 5785,  
  month: 7,  
  day: 10  
});  
console.log(hebrewDate.toString()); // '2025-03-01[u-ca=hebrew]'

DST built in

// 1:30 AM on the day DST ends in Los Angeles (clocks go back from 2:00 to 1:00)
const beforeDST = Temporal.ZonedDateTime.from('2020-11-01T01:30-07:00[America/Los_Angeles]');
console.log('beforeDST', beforeDST.toString())
// Add 1 hour
const afterDST = beforeDST.add({ hours: 1 });
console.log('after', afterDST.toString());
// Output: 2020-11-01T01:30:00-08:00[America/Los_Angeles]
// Notice: The offset changes from -07:00 (PDT) to -08:00 (PST) automatically[4].

Presentation

let test = Temporal.Now.instant() 

console.log('en-us', test.toLocaleString('en-US'))
console.log('fr-FR', test.toLocaleString('fr-FR'))

I'm sold

But when can I actually use Temporal

Polyfill

- https://github.com/tc39/proposal-temporal/tree/main/#polyfills

- https://caniuse.com/temporal

DateFns

xxxx - xxxx

Made with Slides.com