Skip to content

Addition and Subtraction

The default DateTime provides a couple of different methods for easily adding and subtracting time. There is modify(), add() and sub(). change() is an enhanced version of modify() that can take magical date/time format string, 'last day of next month', that it parses and applies the modification while add() and sub() can take the same the same kind of string, intervals (DateInterval or CarbonInterval) or count+unit parameters. But you can still access the native methods of DateTime class using rawAdd() and rawSub().

php
$dt = CarbonImmutable::create(2012, 1, 15, 0);

echo $dt->toDateTimeString();                       // 2012-01-15 00:00:00

echo $dt->addCenturies(5);                          // 2512-01-15 00:00:00
echo $dt->addCentury();                             // 2112-01-15 00:00:00
echo $dt->subCentury();                             // 1912-01-15 00:00:00
echo $dt->subCenturies(5);                          // 1512-01-15 00:00:00

echo $dt->addYears(5);                              // 2017-01-15 00:00:00
echo $dt->addYear();                                // 2013-01-15 00:00:00
echo $dt->subYear();                                // 2011-01-15 00:00:00
echo $dt->subYears(5);                              // 2007-01-15 00:00:00

echo $dt->addQuarters(2);                           // 2012-07-15 00:00:00
echo $dt->addQuarter();                             // 2012-04-15 00:00:00
echo $dt->subQuarter();                             // 2011-10-15 00:00:00
echo $dt->subQuarters(2);                           // 2011-07-15 00:00:00

echo $dt->addMonths(60);                            // 2017-01-15 00:00:00
echo $dt->addMonth();                               // 2012-02-15 00:00:00 // equivalent of $dt->month($dt->month + 1); so it wraps
echo $dt->subMonth();                               // 2011-12-15 00:00:00
echo $dt->subMonths(60);                            // 2007-01-15 00:00:00

echo $dt->addDays(29);                              // 2012-02-13 00:00:00
echo $dt->addDay();                                 // 2012-01-16 00:00:00
echo $dt->subDay();                                 // 2012-01-14 00:00:00
echo $dt->subDays(29);                              // 2011-12-17 00:00:00

echo $dt->addWeekdays(4);                           // 2012-01-19 00:00:00
echo $dt->addWeekday();                             // 2012-01-16 00:00:00
echo $dt->subWeekday();                             // 2012-01-13 00:00:00
echo $dt->subWeekdays(4);                           // 2012-01-10 00:00:00

echo $dt->addWeeks(3);                              // 2012-02-05 00:00:00
echo $dt->addWeek();                                // 2012-01-22 00:00:00
echo $dt->subWeek();                                // 2012-01-08 00:00:00
echo $dt->subWeeks(3);                              // 2011-12-25 00:00:00

echo $dt->addHours(24);                             // 2012-01-16 00:00:00
echo $dt->addHour();                                // 2012-01-15 01:00:00
echo $dt->subHour();                                // 2012-01-14 23:00:00
echo $dt->subHours(24);                             // 2012-01-14 00:00:00

echo $dt->addMinutes(61);                           // 2012-01-15 01:01:00
echo $dt->addMinute();                              // 2012-01-15 00:01:00
echo $dt->subMinute();                              // 2012-01-14 23:59:00
echo $dt->subMinutes(61);                           // 2012-01-14 22:59:00

echo $dt->addSeconds(61);                           // 2012-01-15 00:01:01
echo $dt->addSecond();                              // 2012-01-15 00:00:01
echo $dt->subSecond();                              // 2012-01-14 23:59:59
echo $dt->subSeconds(61);                           // 2012-01-14 23:58:59

echo $dt->addMilliseconds(61);                      // 2012-01-15 00:00:00
echo $dt->addMillisecond();                         // 2012-01-15 00:00:00
echo $dt->subMillisecond();                         // 2012-01-14 23:59:59
echo $dt->subMillisecond(61);                       // 2012-01-14 23:59:59

echo $dt->addMicroseconds(61);                      // 2012-01-15 00:00:00
echo $dt->addMicrosecond();                         // 2012-01-15 00:00:00
echo $dt->subMicrosecond();                         // 2012-01-14 23:59:59
echo $dt->subMicroseconds(61);                      // 2012-01-14 23:59:59

// and so on for any unit: millenium, century, decade, year, quarter, month, week, day, weekday,
// hour, minute, second, microsecond.

// Generic methods add/sub (or subtract alias) can take many different arguments:
echo $dt->add(61, 'seconds');                       // 2012-01-15 00:01:01
echo $dt->sub('1 day');                             // 2012-01-14 00:00:00
echo $dt->add(CarbonInterval::months(2));           // 2012-03-15 00:00:00
echo $dt->subtract(new \DateInterval('PT1H'));      // 2012-01-14 23:00:00

// You can also add or subtract multiple units at once with:
echo $dt->plus(days: 2, hours: 12, minutes: 30);    // 2012-01-17 12:30:00
echo $dt->minus(years: 1, seconds: 120);            // 2011-01-14 23:58:00
// plus() and minus() can take float numbers for any unit except month and years:
echo $dt->plus(days: 0.5);                          // 2012-01-15 12:00:00

You can also pass negative values to addXXX(), in fact that's how subXXX() is implemented.

P.S. Don't worry if you forget and use addDay(5) or subYear(3) (singular), I have your back 😉

By default, Carbon relies on the underlying parent class PHP DateTime behavior. As a result adding or subtracting months can overflow, example:

php
$dt = CarbonImmutable::create(2017, 1, 31, 0);

echo $dt->addMonth();      // 2017-03-03 00:00:00
echo "\n";                
echo $dt->subMonths(2);    // 2016-12-01 00:00:00

Since Carbon 2, you can set a local overflow behavior for each instance:

php
$dt = CarbonImmutable::create(2017, 1, 31, 0);
$dt->settings([
	'monthOverflow' => false,
]);

echo $dt->addMonth();      // 2017-02-28 00:00:00
echo "\n";                
echo $dt->subMonths(2);    // 2016-11-30 00:00:00

This will apply for methods addMonth(s), subMonth(s), add($x, 'month'), sub($x, 'month') and equivalent quarter methods. But it won't apply for intervals objects or strings like add(CarbonInterval::month()) or add('1 month').

Note that CarbonInterval::monthNoOverflow() is available to produce an interval of 1 month that does not overflow. CarbonInterval::monthWithAnchorDay() is also available and allow you to specify an anchor day (after stepping to the next month it will try to go up to the given anchor day if available, else it will go to the last day of the month).

Because the same can also happen when adding/subtracting year(s) starting from a February 29th (leap year), then there also exist CarbonInterval::yearNoOverflow() and CarbonInterval::yearWithAnchorDay().

Same overflow mode are available with plus() and minus():

php
// It can take an overflow mode:
echo CarbonImmutable::create(2012, 1, 31)->plus(
    months: 1,
    overflow: OverflowMode::NoOverflow,
);    // 2012-02-29 00:00:00
// (overflow: false is a shortcut for overflow: OverflowMode::NoOverflow)

// Or it can take an anchorDay:
echo CarbonImmutable::create(2012, 2, 28)
    ->plus(months: 1, anchorDay: 30);                               // 2012-03-30 00:00:00
// Meaning that after adding months/years, it will try to set current day to this number
// if it exists in the current month, else it will go to the last day of the month

If overflow is set to OverflowMode::AnchorDay without specifying anchorDay it will use the day of the initial date.

You also can use ->addMonthsNoOverflow, ->subMonthsNoOverflow, ->addMonthsWithOverflow and ->subMonthsWithOverflow (or the singular methods with no s to "month") to explicitly add/sub months with or without overflow no matter the current mode and the same for any bigger unit (quarter, year, decade, century, millennium).

php
$dt = Carbon::createMidnightDate(2017, 1, 31)->settings([
	'monthOverflow' => false,
]);

echo $dt->copy()->addMonthWithOverflow();      // 2017-03-03 00:00:00
// plural addMonthsWithOverflow() method is also available
echo $dt->copy()->subMonthsWithOverflow(2);    // 2016-12-01 00:00:00
// singular subMonthWithOverflow() method is also available
echo $dt->copy()->addMonthNoOverflow();        // 2017-02-28 00:00:00
// plural addMonthsNoOverflow() method is also available
echo $dt->copy()->subMonthsNoOverflow(2);      // 2016-11-30 00:00:00
// singular subMonthNoOverflow() method is also available

echo $dt->copy()->addMonth();                  // 2017-02-28 00:00:00
echo $dt->copy()->subMonths(2);                // 2016-11-30 00:00:00

$dt = Carbon::createMidnightDate(2017, 1, 31)->settings([
	'monthOverflow' => true,
]);

echo $dt->copy()->addMonthWithOverflow();      // 2017-03-03 00:00:00
echo $dt->copy()->subMonthsWithOverflow(2);    // 2016-12-01 00:00:00
echo $dt->copy()->addMonthNoOverflow();        // 2017-02-28 00:00:00
echo $dt->copy()->subMonthsNoOverflow(2);      // 2016-11-30 00:00:00

echo $dt->copy()->addMonth();                  // 2017-03-03 00:00:00
echo $dt->copy()->subMonths(2);                // 2016-12-01 00:00:00

The same is available for years.

You also can control overflow for any unit when working with unknown inputs:

php
$dt = CarbonImmutable::create(2018, 8, 30, 12, 00, 00);

// Add hours without overflowing day
echo $dt->addUnitNoOverflow('hour', 7, 'day');                  // 2018-08-30 19:00:00
echo "\n";                                                     
echo $dt->addUnitNoOverflow('hour', 14, 'day');                 // 2018-08-30 23:59:59
echo "\n";                                                     
echo $dt->addUnitNoOverflow('hour', 48, 'day');                 // 2018-08-30 23:59:59

echo "\n-------\n";                                             // -------

// Substract hours without overflowing day
echo $dt->subUnitNoOverflow('hour', 7, 'day');                  // 2018-08-30 05:00:00
echo "\n";                                                     
echo $dt->subUnitNoOverflow('hour', 14, 'day');                 // 2018-08-30 00:00:00
echo "\n";                                                     
echo $dt->subUnitNoOverflow('hour', 48, 'day');                 // 2018-08-30 00:00:00

echo "\n-------\n";                                             // -------

// Set hours without overflowing day
echo $dt->setUnitNoOverflow('hour', -7, 'day');                 // 2018-08-30 00:00:00
echo "\n";                                                     
echo $dt->setUnitNoOverflow('hour', 14, 'day');                 // 2018-08-30 14:00:00
echo "\n";                                                     
echo $dt->setUnitNoOverflow('hour', 25, 'day');                 // 2018-08-30 23:59:59

echo "\n-------\n";                                             // -------

// Adding hours without overflowing month
echo $dt->addUnitNoOverflow('hour', 7, 'month');                // 2018-08-30 19:00:00
echo "\n";                                                     
echo $dt->addUnitNoOverflow('hour', 14, 'month');               // 2018-08-31 02:00:00
echo "\n";                                                     
echo $dt->addUnitNoOverflow('hour', 48, 'month');               // 2018-08-31 23:59:59

echo "\n-------\n";                                             // -------

// An anchor day can be passed so try to go up to
// this day if it exists in the current month
echo $dt->addUnitNoOverflow(Unit::Month, 2, Unit::Year, 31);    // 2018-10-31 12:00:00
echo "\n";                                                     
echo $dt->subUnitNoOverflow(Unit::Month, 2, Unit::Year, 31);    // 2018-06-30 12:00:00
echo "\n";                                                     
echo $dt->setUnitNoOverflow(Unit::Month, 9, Unit::Year, 31);    // 2018-09-30 12:00:00

Any modifiable unit can be passed as argument of those methods:

php
$units = [];
foreach (['millennium', 'century', 'decade', 'year', 'quarter', 'month', 'week', 'weekday', 'day', 'hour', 'minute', 'second', 'millisecond', 'microsecond'] as $unit) {
	$units[$unit] = Carbon::isModifiableUnit($unit);
}

echo json_encode($units, JSON_PRETTY_PRINT);   
/*
{
    "millennium": true,
    "century": true,
    "decade": true,
    "year": true,
    "quarter": true,
    "month": true,
    "week": true,
    "weekday": true,
    "day": true,
    "hour": true,
    "minute": true,
    "second": true,
    "millisecond": true,
    "microsecond": true
}
*/

Static helpers exist but are deprecated. If you're sure to need to apply global setting or work with version 1 of Carbon, check the section below:

Overflow static helpers

You can prevent the overflow with Carbon::useMonthsOverflow(false)

php
Carbon::useMonthsOverflow(false); 

$dt = Carbon::createMidnightDate(2017, 1, 31);

echo $dt->copy()->addMonth();      // 2017-02-28 00:00:00
echo "\n";                        
echo $dt->copy()->subMonths(2);    // 2016-11-30 00:00:00

// Call the method with true to allow overflow again
Carbon::resetMonthsOverflow();     // same as Carbon::useMonthsOverflow(true);

The method Carbon::shouldOverflowMonths() allows you to know if the overflow is currently enabled.

php
Carbon::useMonthsOverflow(false);             

$dt = Carbon::createMidnightDate(2017, 1, 31);

echo $dt->copy()->addMonthWithOverflow();      // 2017-03-03 00:00:00
// plural addMonthsWithOverflow() method is also available
echo $dt->copy()->subMonthsWithOverflow(2);    // 2016-12-01 00:00:00
// singular subMonthWithOverflow() method is also available
echo $dt->copy()->addMonthNoOverflow();        // 2017-02-28 00:00:00
// plural addMonthsNoOverflow() method is also available
echo $dt->copy()->subMonthsNoOverflow(2);      // 2016-11-30 00:00:00
// singular subMonthNoOverflow() method is also available

echo $dt->copy()->addMonth();                  // 2017-02-28 00:00:00
echo $dt->copy()->subMonths(2);                // 2016-11-30 00:00:00

Carbon::useMonthsOverflow(true);              

$dt = Carbon::createMidnightDate(2017, 1, 31);

echo $dt->copy()->addMonthWithOverflow();      // 2017-03-03 00:00:00
echo $dt->copy()->subMonthsWithOverflow(2);    // 2016-12-01 00:00:00
echo $dt->copy()->addMonthNoOverflow();        // 2017-02-28 00:00:00
echo $dt->copy()->subMonthsNoOverflow(2);      // 2016-11-30 00:00:00

echo $dt->copy()->addMonth();                  // 2017-03-03 00:00:00
echo $dt->copy()->subMonths(2);                // 2016-12-01 00:00:00

Carbon::resetMonthsOverflow();

From version 1.23.0, overflow control is also available on years:

php
Carbon::useYearsOverflow(false);             

$dt = Carbon::createMidnightDate(2020, 2, 29);

var_dump(Carbon::shouldOverflowYears());      // bool(false)

echo $dt->copy()->addYearWithOverflow();      // 2021-03-01 00:00:00
// plural addYearsWithOverflow() method is also available
echo $dt->copy()->subYearsWithOverflow(2);    // 2018-03-01 00:00:00
// singular subYearWithOverflow() method is also available
echo $dt->copy()->addYearNoOverflow();        // 2021-02-28 00:00:00
// plural addYearsNoOverflow() method is also available
echo $dt->copy()->subYearsNoOverflow(2);      // 2018-02-28 00:00:00
// singular subYearNoOverflow() method is also available

echo $dt->copy()->addYear();                  // 2021-02-28 00:00:00
echo $dt->copy()->subYears(2);                // 2018-02-28 00:00:00

Carbon::useYearsOverflow(true);              

$dt = Carbon::createMidnightDate(2020, 2, 29);

var_dump(Carbon::shouldOverflowYears());      // bool(true)

echo $dt->copy()->addYearWithOverflow();      // 2021-03-01 00:00:00
echo $dt->copy()->subYearsWithOverflow(2);    // 2018-03-01 00:00:00
echo $dt->copy()->addYearNoOverflow();        // 2021-02-28 00:00:00
echo $dt->copy()->subYearsNoOverflow(2);      // 2018-02-28 00:00:00

echo $dt->copy()->addYear();                  // 2021-03-01 00:00:00
echo $dt->copy()->subYears(2);                // 2018-03-01 00:00:00

Carbon::resetYearsOverflow();