Working with dates is an unavoidable part of most web applications. Thankfully JavaScript provides the built-in Date object for creating and manipulating dates. However, dealing with oddities like timezone shifts and daylight saving time can trip up even experienced developers.

In this comprehensive guide, you‘ll learn foolproof techniques for adding days to dates in JavaScript. By following best practices and avoiding common pitfalls, you can confidently write reliable date handling code.

Here‘s what we‘ll cover:

  • Date Concepts: Timestamps, Timezones & DST
  • Using setDate()/getDate()
  • Adding Days with Milliseconds
  • Building Reusable Date Utilities
  • Native JavaScript Dates vs Libraries
  • Visual Explanation of Dates & Offsets
  • Recap of Best Practices

Let‘s dive in and level up your date manipulation skills!

Date Concepts: Timestamps, Timezones & DST

To understand what‘s happening when adding days to dates, we first need to review some key date-related concepts.

Millisecond Timestamp

Computers store dates and times as a numeric timestamp – the number of milliseconds that have elapsed since the "Unix Epoch" (January 1st, 1970 at 00:00:00 GMT).

For example, the timestamp value 1674329625873 refers to this specific moment in time.

We can convert a timestamp to a human-readable date using new Date(milliseconds):

const now = 1674329625873;
const date = new Date(now); // Fri Jan 20 2023 18:20:25

Think of timestamps as raw serialized date data. The Date objects add display formatting.

Timezones

While timestamps are fixed points in time, human-readable dates must account for timezones.

For example, 5pm in San Francisco vs New York:

SF: Jan 20, 2023 17:00:00 // 5pm     
NY: Jan 20, 2023 20:00:00 // 5pm

The underlying timestamp is the same absolute point (1674329625873) – but the display time differs by timezone.

Browsers normally display dates in the local system timezone of the end user. However, dates from databases or APIs use a fixed reference timezone instead. We need to handle any mismatches to display the right time for the user.

Daylight Saving Time (DST)

Further confusing matters is Daylight Saving Time (DST). For part of the year, clocks shift forward or back by an hour.

These DST transitions mean adding 24 hours does not always equal 1 calendar day:

Daylight saving time illustration

During DST changes, 24 hours ≠ 1 day

If adding days across a DST boundary, we need special logic to handle the 1 hour offset.

Okay, with those concepts covered, let‘s look at techniques for incrementing dates…

Using setDate() and getDate()

The easiest approach is using the native setDate() and getDate() methods:

// Today
const date = new Date(); 

// Add 1 day
date.setDate(date.getDate() + 1); 

Here‘s what‘s happening:

  1. Create new Date object (date)
  2. Call getDate() to get the day of month
  3. Increment the day value
  4. Pass new day back into setDate()

This automatically handles overflow into the next month.

For example, January 31 + 1 day = February 1.

Let‘s look at some more examples:

// Birthday in current year  
const birthday = new Date(2023, 0, 19); 

// Next year
birthday.setDate(birthday.getDate() + 365); 

birthday; // Fri Jan 19 2024 00:00:00

We can use the same approach to subtract days:

// 2 weeks ago
const weeksAgo = new Date();
weeksAgo.setDate(weeksAgo.getDate() - 14);

Easy! Behind the scenes, the JavaScript engine handles all the messy month and year rollover logic for us.

Here are some pros of this technique:

✅ Simple and readable

✅ Built-in methods work consistently

✅ Auto handles month/year rollovers

The one minor drawback is that setDate() does not update the day of week. So you may end up with a "Tuesday" that is actually a Wednesday when incrementing days.

Overall, this setDate() approach strikes the best balance for readability and robustness when adding days.

Adding Days with Milliseconds

We can also add days by directly manipulating timestamps.

Every 24 hours = 86,400,000 milliseconds.

So to add 1 day:

// March 7 2025, 3:15pm
const start = new Date(2025, 2, 7, 15, 15); 

// 86,400,000 ms per day 
const oneDay = 1000 * 60 * 60 * 24;  

// New timestamp = +1 day
const end = start.getTime() + oneDay;

new Date(end); 
// Tue Mar 08 2025 15:15:00  

The .getTime() method converts Date objects to milliseconds since the Unix Epoch. By adding 86,400,000 ms, we offset forward 1 whole day.

Or in function form:

function addDays(date, days) {

  // 24 hrs 
  const oneDay = 1000 * 60 * 60 * 24;  

  const offset = days * oneDay;

  return new Date(date.getTime() + offset);

}

addDays(new Date(), 7); // 7 days later

This allows simple control of day increments and decrements by adjusting the millisecond offsets.

However, DST transitions throw off fixed offsets.

During spring forward, some hours don‘t exist:

                 1AM              
                  |               
     12AM  1AM  *2AM*  3AM        
                  |
     Actual:      1AM -> 3AM  

While in fall back, 1AM repeats twice:

                   1AM  
                 *  |   *   
                1AM  2AM
                  |
     Actual:   1AM -> 1AM again

So blindly by adding 24 hours during transitions fails:

// Spring forward night, 1:30am
const dstStart = new Date(2023, 2, 12, 1, 30);  

// Next day should be 3:30am...
const nextDay = addDays(dstStart, 1); 

// But is still 1:30am!
nextDay; // Sun Mar 12 2023 01:30:00

We skipped over the missing 2am hour and remained on the same day.

To fix this, we need to handle DST transitions by temporarily removing the timezone:

function addDays(date, days) {

  // 1. Remove timezone to avoid DST  
  date.setHours(date.getHours() - date.getTimezoneOffset()/60); 

  // 2. Now add days normally
  date.setTime(date.getTime() + days * oneDay);

  // 3. Restore timezone 
  date.setHours(date.getHours() + date.getTimezoneOffset()/60);

  return date;

}

By converting to UTC dates without DST, plain offsets work properly again through transitions.

In summary, millisecond offsets give us precision control when adding days. But we need to beware of DST changes tripping things up.

Okay, let‘s look at building reusable functions next…

Building Reusable Date Utilities

Rather than writing messy one-off date scripts, we can centralize common date manipulation operations into reusable utility modules.

Here is an example with functions to add days, weeks, and weekdays:

// date-utils.js 

export function addDays(date, days) {

  date = shiftTZ(date);

  date.setDate(date.getDate() + days);

  return backToTZ(date); 

}

export function addWeeks(date, weeks) {

  return addDays(date, weeks * 7);  

}

export function addWeekdays(date, days) {

  // ...impl...

}


// Reusable helpers
function shiftTZ(date) {

  date = new Date(date);

  date.setHours(date.getHours() - date.getTimezoneOffset()/60);

  return date;

}

function backToTZ(date) {

  date = new Date(date);

  date.setHours(date.getHours() + date.getTimezoneOffset()/60);

  return date;

}

Now we can import just the addDays function without any other helpers:

// main.js
import { addDays } from ‘./date-utils.js‘;

const nextWeek = addDays(new Date(), 7); 

This keeps our main code clean and focused.

For even more versatility, we could build a full date calculation engine handling intervals like:

  • Days
  • Weeks
  • Weekdays
  • Months
  • Years

With a battle-tested reusable library, incrementing dates becomes trivial anywhere in our apps!

Native JavaScript Dates vs Libraries

At this point, you may be wondering whether to use the built-in JavaScript Date object or rely on an external library? Let‘s do a quick comparison of the pros and cons.

Native Date

new Date().setDate(new Date().getDate() + 1); 
  • ✅ Simple syntax
  • ✅ High performance
  • ✅ Built into JavaScript by default
  • ❌ Handwritten fallbacks required
  • ❌ Verbose for complex duration logic

date-fns Library

import { addDays } from ‘date-fns‘;

addDays(new Date(), 1);
  • ✅ Clean readable chains
  • ✅ Robust durarion calculations
  • ✅ ISO 8601 string parsing
  • ❌ Slower performance
  • ❌ External dependency

As we can see, native Dates have the advantage of being builtin with good browser coverage support and speed. But they lack niceties like immutable date instances and custom duration adding functions.

Third party libraries like date-fns, Moment.js and dayjs fill the gaps with utility functions and locale support. But at the cost of increased bundle sizes.

So think carefully about your needs:

  • For simple use cases, prefer native Dates
  • For complex calendars, use a library!

With large applications, a library may be worth the tradeoff. But simpler pages can just utilize setDate() and getTime().

Visual Explanation of Dates & Offsets

Let‘s visualize what‘s actually happening when we add days to dates under the hood…

Here is a helpful metaphor:

Think of Date objects as individual calendar pages

Date calendar visualization

Methods like .setDate(15) will flip the page to the 15th day of the month.

And .getTime() peeks at the internal timestamp value used to track the position.

We can shift days by changing the position of the calendar:

date offset animation

Adding days offsets the calendar page position

The setDate() method handles moving to the next/previous month automatically.

This visualization helps build an intuitive understanding of how DateTime logic works – dates are just positions on a virtual calendar!

Okay, let‘s conclude by recapping some key learnings…

Recap of Best Practices

We‘ve covered quite a lot of techniques and concepts throughout this guide!

Let‘s recap some best practices when adding days to dates in JavaScript:

✅ Use setDate()/getDate() for simple increments
✅ Convert Dates to UTC temporarily to avoid DST issues
✅ Build reusable date utility functions
✅ Visually think of Dates as moveable calendar pages
✅ Consider a library like date-fns for advanced use cases

Following these tips will help you avoid common date manipulation pitfalls.

Understanding the root cause of issues with DST, timezones and calculations is critical for debugging date code. Expect some trial and error while ramping up!


And there you have it – everything you need to know to become a date shifting master in JavaScript. You now have a solid grasp of core concepts like:

  • Timestamps & Timezones
  • Daylight Saving Time exceptions
  • setDate() vs Millisecond Offsets
  • Encapsulating Date Utilities
  • Visualizing Date Movement

Phew, quite a tour! I hope you feel empowered to handle all kinds of date manipulations in your apps going forward. Let me know if any questions pop up!

Date work might not be glamorous, but it‘s a necessary skill we all need to learn. This guide aimed to help shorten that learning curve through lots of concrete examples and visuals.

Now get out there, have fun incrementing some dates! 🗓

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *