chronia

subMonths

Overview

The subMonths function subtracts a specified number of months from the given date. It provides a reliable way to perform month-based date arithmetic with proper handling of month-end overflow, leap years, and fractional amounts.

Signature

function subMonths(date: DateInput, amount: number): Date;

Parameters

Parameter Type Description
date DateInput The base date as a Date object, numeric timestamp, or ISO 8601 string
amount number The number of months to subtract (can be negative to add months)

Return Value

Type Description
Date A new Date object with the specified number of months subtracted, or Invalid Date if any input is invalid

Description

The subMonths function performs month-based date arithmetic by subtracting a specified number of months from the provided date. It internally uses the addMonths function with a negated amount, ensuring consistent behavior across the library. The function handles edge cases such as month-end overflow (e.g., March 31 → February 28/29) and preserves all time components.

Specification

Returns a valid Date when:

Returns Invalid Date when:

Month-end overflow behavior:

Behavior Notes

Use Cases

Usage Examples

Relative Date Calculation

import { subMonths } from "chronia";

// Calculate "3 months ago"
const today = new Date(2025, 3, 15); // April 15, 2025
const threeMonthsAgo = subMonths(today, 3);
// Returns: Date representing January 15, 2025

// Calculate using timestamp
const timestamp = Date.now();
const oneMonthAgo = subMonths(timestamp, 1);
// Returns: Date representing one month before current time

Billing Cycles

import { subMonths } from "chronia";

function getPreviousBillingDate(currentBillingDate: Date): Date {
  return subMonths(currentBillingDate, 1);
}

// Monthly billing cycle
const currentBilling = new Date(2025, 2, 31); // March 31, 2025
const previousBilling = getPreviousBillingDate(currentBilling);
// Returns: February 28, 2025 (Feb doesn't have 31 days)

// Quarterly billing
const quarterlyBilling = new Date(2025, 3, 1); // April 1, 2025
const lastQuarter = subMonths(quarterlyBilling, 3);
// Returns: January 1, 2025

Timeline Navigation

import { subMonths } from "chronia";

// Navigate calendar backward
function navigateMonthsBackward(currentMonth: Date, steps: number): Date {
  return subMonths(currentMonth, steps);
}

const currentMonth = new Date(2025, 11, 1); // December 2025
const sixMonthsBack = navigateMonthsBackward(currentMonth, 6);
// Returns: June 1, 2025

// Time-preserving navigation
const exactTime = new Date(2025, 5, 15, 14, 30, 45, 123);
const twoMonthsBack = subMonths(exactTime, 2);
// Returns: April 15, 2025, 14:30:45.123 (time preserved)

Handling Edge Cases

import { subMonths } from "chronia";

// Fractional months are truncated
const date1 = new Date(2025, 5, 15);
const result1 = subMonths(date1, 2.9);
// Returns: April 15, 2025 (2.9 truncated to 2)

// Negative amount adds months
const date2 = new Date(2025, 0, 15);
const result2 = subMonths(date2, -3);
// Returns: April 15, 2025 (adding 3 months)

// Month-end overflow handling
const marchEnd = new Date(2025, 2, 31); // March 31, 2025
const febResult = subMonths(marchEnd, 1);
// Returns: February 28, 2025

// Leap year handling
const marchEnd2024 = new Date(2024, 2, 31); // March 31, 2024
const febResult2024 = subMonths(marchEnd2024, 1);
// Returns: February 29, 2024 (2024 is a leap year)

// Invalid inputs
const invalidDate = subMonths(new Date("invalid"), 3);
// Returns: Invalid Date

const invalidAmount = subMonths(new Date(2025, 0, 15), NaN);
// Returns: Invalid Date

Date Range Generation

import { subMonths } from "chronia";

// Generate last N months for a report
function generateMonthlyRange(endDate: Date, monthCount: number): Date[] {
  const months: Date[] = [];
  for (let i = 0; i < monthCount; i++) {
    months.push(subMonths(endDate, i));
  }
  return months.reverse();
}

const today = new Date(2025, 3, 1); // April 1, 2025
const lastSixMonths = generateMonthlyRange(today, 6);
// Returns: [Nov 2024, Dec 2024, Jan 2025, Feb 2025, Mar 2025, Apr 2025]

// Create a date range filter
const endDate = new Date(2025, 11, 31); // December 31, 2025
const startDate = subMonths(endDate, 12); // 12 months earlier
// startDate: December 31, 2024