JS Quiz: 14 Date Time Questions in JavaScript

Gotchas every developer will encounter ✨

updated 4 months ago

quiz (2)
date (1)
gotchas (1)

How well do you know the Date class?

  • Prove your JavaScript skillz! 🚀
  • No login or signup required. ✨
  • Multiple choice. 🤖 … How difficult can it be, eh?

Outline

The Date class in JavaScript has a notoriously difficult API. It was inherited from Java…

This situation leads many developers to use 3rd party libraries without question. While often a safe and reliable choice, these libraries are rarely needed for formatting dates or localization!

This quiz is designed to test (and deepen) your knowledge of the native Date API. Use the green buttons for hints & explanations! Hopefully by the end of the challenge you’ll have solidified your understanding of Date’s in JavaScript.

If you get stuck

  1. Read the Hints (Green button, lower right corner). Some include a few animated answers w/ detailed annotations, while others offer only a few clues. I can’t give away all the answers so easy!
    Seriously though, this is intentional, the answers are there. Skip ahead or try the code snippets out, then change it, and play some more.
  2. Try the code in your browser’s Console (try shortcut F12 on Windows, or Command + Option + J on Mac).
  3. Please feel free to Tweet at me @justsml. I’d love to hear your thoughts!

NOTE: Assume all examples run with GMT-7 timezone offset.

Loading...
A few more seconds...

Date Constructor Part 1

const d1 = new Date(2020, 1, 1)
console.log(d1)

What will the output include?

  • Jan 01 2020
  • Feb 01 2020
  • RangeError: Invalid argument.

The Month argument is zero-based. With a range of 0-11 (using western calendars.)

‘February’ has an index value of one. (Think of it like an array lookup.)

Date Constructor Part 2

const d2 = new Date(2020, 0, 1)
console.log(d2)

What will the output include?

  • Jan 01 2020
  • Feb 01 2020
  • RangeError: Invalid argument.

The Month argument is zero-based. With a range of 0-11 (using western calendars.)

‘January’ has an index value of zero. (Think of it like an array lookup.)

Date Constructor Part 3

const d3 = Date('Thu, 01 Jan 1970 00:00:00 GMT')
console.log(d3)

What will the output include?

  • 01 Jan 1970
  • Unix Epoch of 0
  • Current Date, in UTC/GMT
  • Current Date
  • NaN

This is a common gotcha that’s easy to overlook, even in code review.

A Date instance created with Date([args]) will always return today’s date. In other words, the arguments are ignored. Date('blah') is an alias for new Date().

The missing piece is the new keyword: new Date(dateString).

Date String Parsing

Assume all examples run with GMT-7 timezone offset.

const d1 = new Date('2020-01-01')
const d2 = new Date('2020-01-01T00:00')
console.log(d1.getFullYear(), d2.getFullYear())

What value will print to the console?

  • 2019 2020
  • 2020 2021
  • 2020 2020
  • 2020 2019

The Date constructor parses date strings using either UTC/GMT or local time.

The trick is knowing if your local timezone will be used… The T00:00 causes it to use UTC/GMT time.

Formatting

Given the following date…

const date = new Date('2020-01-01T00:00')

Select an incorrect formatting method:

  • date.toLocaleFormat('en-US', { timeZone: 'UTC', timeZoneName: 'short' })
  • date.toLocaleDateString('en-US', { timeZone: 'UTC', timeZoneName: 'short' })
  • date.toLocaleTimeString('en-GB', { timeZone: 'UTC' })
  • new Intl.DateTimeFormat('en-US').format(date)

The method Date.toLocaleFormat() is not standard, or well supported.

Before I reach for a 3rd party library, I prefer to use the native toLocaleDateString method. It’s behavior is documented under Intl.DateTimeFormat.

Formatting

const date = new Date(2020)
console.log(date.getFullYear())

What will the output include?

  • 1969
  • 1970
  • 2019
  • 2020
  • 2021

A Date instance cannot be created with a single integer as an argument. It is invalid, and will default to the start of ‘computer time’ (milliseconds since Jan 1st, 1970.)

The reason the answer is not 1970 is because you’d need to use .getUTCFullYear() to get the year without timezone offset (for these questions, GMT-7 is assumed.)

You won’t observe this effect if you live at GMT-0 (or greater than GMT+1.)

UTC Dates Part 1

var date = new Date(Date.UTC(2020, 0, 1))
console.log(date.getUTCFullYear(), date.getFullYear())

What will the output include?

  • 2020 2020
  • 2020 2019
  • 2019 2020
  • 2019 2019

The getFullYear() method is based off a local offset of GMT-07:00. Which means it will give the previous year, as the date is represented locally is Dec 31 2019 17:00:00.

UTC Dates Part 2

const d = Date.UTC(2020, 0, 1)
console.log(d)

What will the output include?

  • A UTC-based date instance
  • A date instance adjusted for local time-zone
  • Milliseconds since Jan 1st, 1970
  • An error

The helper method Date.UTC doesn’t return a date instance. It returns an integer in milliseconds.

UTC Dates Part 3

// Assume local TZ is -07:00
const d = new Date(Date.UTC(2020, 0, 1))
console.log(d.getTimezoneOffset())

What will the output include?

  • 0
  • 420
  • 700
  • 1400
  • null

Date’s will be implicitly presented in local time, with an unchanging .getTimezoneOffset().

Date instances do not store ‘original’ timezone data. Date instances essentially store only the # of milliseconds since the Unix Epoch (Jan 1, 1970). The timezone is accounted for when Date String parsing. And the default display behavior is automatically determined based on the system or browser’s locale settings.

screenshots/timezones-ex1.jpg

Date Setters Part 1

const d = new Date(2020, 0, 1)
d.setDate(1)
console.log(d)

What will the output include?

  • Jan 01 2020
  • Feb 01 2020
  • RangeError: Invalid argument.

The .setDate() method sets the day of the month, based on the given instance’s current month.

If a value is provided outside of the number of days available, the date instance month value will be adjusted (e.g. A setDate(32) in January will calculate as February 1st.)

Date Setters Part 2

const d = new Date(2020, 0, 1)
d.setDate(0)
console.log(d)

What will the output include?

  • Jan 01 2020
  • Jan 00 2020
  • Feb 01 2020
  • Dec 31 2019
  • RangeError: Invalid argument.

The setDate method sets the day of the month, based on the given instance’s current month.

If you invoke setDate(0) the date instance will adjust to the last day of the previous month.

Date Setters Part 3

const d = new Date(2020, 0, 1)
d.setDate(32)
console.log(d)

What will the output include?

  • Jan 01 2020
  • Jan 32 2020
  • Feb 01 2020
  • RangeError: Invalid argument.

If a positive integer is provided to setDate outside of the number of days available, the date instance’s month and day will be adjusted as necessary. (e.g. A setDate(32) in January will calculate as February 1st.)

Date Setters Part 4

const d = new Date(2020, 1, 1)
d.setDate(100)
console.log(d)
  • Jan 01 2020
  • Feb 01 2020
  • May 01 2020
  • May 10 2020
  • RangeError: Invalid argument.

Hint: Setting the date with setDate(X) isn’t the same as adding X days.

Date Setters Part 5

const d = new Date(2020, 1, 1)
d.setDate(100)
d.setDate(-100)
console.log(d)
  • Feb 01 2020
  • Feb -100 2020
  • Jan 21 2020
  • Jan 01 2020
  • RangeError: Invalid argument.

This is perhaps one of the stranger questions here.

The reason this even comes up is the likely scenario: You know setDate(1) goes to the first day of the month. And that setDate(-1) will select the last day of the previous month, “wow, that’s handy” you say. Then, a requirement comes down: we need be able to extend (and cancel) subscriptions by 120-day increments. This question simulates this scenario.

Hopefully you don’t find yourself with code attempting tricks like this with setDate. Use a 3rd party library, check out date_fns, dayjs, or momentjs. They feature a vastly more practical interface.

Here’s a screenshot of what the values are after each change:

screenshots/date-setters.ex1.jpg

Unless otherwise noted, all content is copyright Dan Levy 2014-1019.