District5 Date Library

A fluent, intuitive PHP wrapper around DateTime — zero dependencies, PHP 8.1+.

PHP 8.1+ MIT License No Dependencies Fluent API

Installation

Install via Composer:

composer require district5/date

All functionality is accessed through the District5\Date\Date facade class using static methods.

use District5\Date\Date;

Quick Start

use District5\Date\Date;

// Get current time in UTC
$now = Date::nowUtc();

// Add 3 days
$future = Date::modify($now)->plus()->days(3);

// Format the result
echo Date::output($future)->toYMD();  // e.g. 2026-04-02

// How many days until then?
echo Date::diff($now)->days($future);  // 3

Getting the Current Time

Use Date::now() to obtain a NowTimezone helper, or the convenience shortcuts for the most common cases.

Convenience shortcuts

use District5\Date\Date;

// Current time in the server's default timezone as a DateTime
$default = Date::nowDefault();

// Current time in UTC
$utc = Date::nowUtc();

// Current Unix timestamp (int)
$ts = Date::time();

// Current microtime as float or string
$float  = Date::microtime(true);   // float
$string = Date::microtime(false);  // string

NowTimezone — named timezone shortcuts

$now = Date::now();

$utc     = $now->utc();              // UTC
$london  = $now->london();           // Europe/London
$eastern = $now->eastern();          // America/New_York
$central = $now->central();          // America/Chicago
$pacific = $now->pacific();          // America/Los_Angeles
$default = $now->default();          // Server default timezone

// Any IANA timezone string
$tokyo   = $now->inTimezone('Asia/Tokyo');

// From a UTC offset string (e.g. +0100, -0500)
$offset  = $now->fromOffset('+0200');

Creating DateTimes

From year / month / day components

use District5\Date\Date;

// Date only (time defaults to 00:00:00)
$date = Date::createYMDHISM(2026, 1, 15);

// Date + time
$datetime = Date::createYMDHISM(2026, 1, 15, 14, 30, 0);

// Date + time + microseconds + timezone
$dt = Date::createYMDHISM(2026, 1, 15, 14, 30, 0, 500000, 'America/New_York');

Unix epoch

// Returns a DateTime set to 1970-01-01 00:00:00 UTC
$epoch = Date::epoch();

From a string (auto-detect common formats)

$dt = Date::fromString('2026-03-30 14:30:00');  // DateTime or false

Calculate someone's age

$dob = Date::createYMDHISM(1990, 6, 15);
$age = Date::age($dob);  // int — full years since the given date

Parsing Strings & Timestamps

Use Date::input($value) to wrap a string, integer, or float and then call the relevant parser. All methods return DateTime|false.

Date-only strings

use District5\Date\Date;

$dt = Date::input('2026-03-30')->fromYMD();              // default separator '-'
$dt = Date::input('2026/03/30')->fromYMD('/');

$dt = Date::input('30-03-2026')->fromDMY();              // DD-MM-YYYY
$dt = Date::input('03-30-2026')->fromMDY();              // MM-DD-YYYY

Date + time strings

$dt = Date::input('2026-03-30 14:30:00')->fromYMDHIS();
// Custom separators
$dt = Date::input('2026/03/30 14:30:00')->fromYMDHIS('/', ':');

ISO 8601

$dt = Date::input('2026-03-30T14:30:00+0000')->fromISO8601();

Unix timestamps

$dt = Date::input(1743340200)->fromUnixTimestamp();
$dt = Date::input(1743340200)->fromTimestamp();        // alias

Millisecond & microsecond timestamps

$dt = Date::input(1743340200123)->fromMillisecondTimestamp();
$dt = Date::input(1743340200123456)->fromMicrosecondTimestamp();

Custom format

$dt = Date::input('30/03/2026')->fromFormat('d/m/Y');
$dt = Date::input('March 30, 2026')->fromFormat('F j, Y');

Formatting Output

Use Date::output($dateTime) to wrap a DateTime and extract components or formatted strings.

Extract date/time components

use District5\Date\Date;

$dt  = Date::createYMDHISM(2026, 3, 30, 14, 30, 45);
$out = Date::output($dt);

$out->getYear();         // 2026
$out->getMonth();        // 3
$out->getDay();          // 30
$out->getWeek();         // ISO week number, e.g. 14
$out->getDayOfWeek();    // 1 (Mon) – 7 (Sun)
$out->getDayName();      // "Monday"
$out->getMonthName();    // "March"
$out->getDaySuffix();    // "th" (st / nd / rd / th)

$out->getHour();         // 14
$out->getMinutes();      // 30
$out->getSeconds();      // 45
$out->getMicroseconds(); // 0
$out->getMilliseconds(); // 0

Date format strings

$out->toYMD();                  // "2026-03-30"
$out->toYMD(true, '/');         // "2026/03/30"
$out->toYMD(false);             // "20260330"

$out->toDMY();                  // "30-03-2026"
$out->toMDY();                  // "03-30-2026"

$out->toYMDHIS();               // "2026-03-30 14:30:45"

Time format strings

$out->toTimeHM();               // "14:30"
$out->toTimeHMS();              // "14:30:45"
$out->getHourMinutes();         // "14:30"  (alias)
$out->getHourMinutesSeconds();  // "14:30:45"  (alias)

ISO 8601 & custom formats

$out->toISO8601();              // "2026-03-30T14:30:45+0000"
$out->toFormat('l, F j Y');    // "Monday, March 30 2026"  (any PHP date format)

Timestamps

$out->toUnixTimestamp();             // int
$out->toUnixTimestamp(true);         // string
$out->toTimestamp();                 // int  (alias)

$out->toMillisecondTimestamp();      // float  e.g. 1743340245.000
$out->toMicrosecondTimestamp();      // float  e.g. 1743340245.000000

Modify

Date::modify($dt) returns a Modify object. By default it clones the DateTime so the original is untouched. Pass false as the second argument to mutate in place.

Set date or time components

use District5\Date\Date;

$dt = Date::createYMDHISM(2026, 3, 30, 14, 30, 0);

// Change only specific date parts (pass null to leave unchanged)
$new = Date::modify($dt)->setDate(1, null, 2027);   // day=1, same month, year=2027

// Change time
$new = Date::modify($dt)->setTime(9, 0);            // 09:00:00
$new = Date::modify($dt)->setTime(9, 0, 30, 0);     // 09:00:30.000000

// Set individual time components
$new = Date::modify($dt)->setHours(23);
$new = Date::modify($dt)->setMinutes(59);
$new = Date::modify($dt)->setSeconds(0);
$new = Date::modify($dt)->setMicroseconds(500000);

Free-form string modification

// Same syntax as PHP's DateTime::modify()
$new = Date::modify($dt)->withString('+5 days');
$new = Date::modify($dt)->withString('next Friday');
$new = Date::modify($dt)->withString('last day of this month');

Mutate in place

// $dt itself is modified, no clone
Date::modify($dt, false)->setHours(0);

Adding Time

Access addition via Date::modify($dt)->plus() (returns DateTime|false) or the chainable fluid API via Date::modify($dt)->plusFluid().

Single additions

use District5\Date\Date;

$dt = Date::nowUtc();

Date::modify($dt)->plus()->microseconds(500);
Date::modify($dt)->plus()->milliseconds(500);
Date::modify($dt)->plus()->seconds(30);
Date::modify($dt)->plus()->minutes(15);
Date::modify($dt)->plus()->hours(2);
Date::modify($dt)->plus()->hoursAndMinutes(1, 30);
Date::modify($dt)->plus()->hoursAndMinutesAndSeconds(1, 30, 15);
Date::modify($dt)->plus()->days(7);
Date::modify($dt)->plus()->weeks(2);
Date::modify($dt)->plus()->months(3);
Date::modify($dt)->plus()->years(1);
Date::modify($dt)->plus()->decades(1);
Date::modify($dt)->plus()->centuries(1);
Date::modify($dt)->plus()->millennia(1);

// Aliases — add() and addFluid() work identically
Date::modify($dt)->add()->days(3);

Chainable (fluid) additions

$result = Date::modify($dt)
    ->plusFluid()
    ->years(1)
    ->months(2)
    ->days(10)
    ->hours(3)
    ->minutes(30)
    ->seconds(0)
    ->getDateTime();  // returns the final DateTime

Subtracting Time

Mirror of the addition API. Use ->minus() / ->subtract() / ->sub() for single steps, or ->minusFluid() / ->subtractFluid() / ->subFluid() for chaining.

Single subtractions

use District5\Date\Date;

$dt = Date::nowUtc();

Date::modify($dt)->minus()->microseconds(500);
Date::modify($dt)->minus()->milliseconds(500);
Date::modify($dt)->minus()->seconds(30);
Date::modify($dt)->minus()->minutes(15);
Date::modify($dt)->minus()->hours(2);
Date::modify($dt)->minus()->hoursAndMinutes(1, 30);
Date::modify($dt)->minus()->hoursAndMinutesAndSeconds(1, 30, 15);
Date::modify($dt)->minus()->days(7);
Date::modify($dt)->minus()->weeks(2);
Date::modify($dt)->minus()->months(3);
Date::modify($dt)->minus()->years(1);
Date::modify($dt)->minus()->decades(1);

Chainable (fluid) subtractions

$result = Date::modify($dt)
    ->minusFluid()
    ->years(1)
    ->months(6)
    ->days(15)
    ->getDateTime();

Differences Between Dates

Date::diff($dateTime) returns a Diff object. Pass a second DateTime to each method to compute the absolute difference as complete units.

use District5\Date\Date;

$start = Date::createYMDHISM(2020, 1, 1);
$end   = Date::createYMDHISM(2026, 3, 30);

$diff = Date::diff($start);

$diff->milliseconds($end);  // int — total ms difference
$diff->seconds($end);
$diff->minutes($end);
$diff->hours($end);
$diff->days($end);
$diff->weeks($end);
$diff->months($end);
$diff->years($end);          // 6
$diff->decades($end);
$diff->centuries($end);
$diff->millennia($end);
Note: All diff values are the absolute difference expressed in complete units (floor).

Calendar Calculations

Date::calculate($dateTime) returns a Calculate object for the given date.

Days in a month

use District5\Date\Date;

$dt   = Date::createYMDHISM(2026, 2, 10);
$calc = Date::calculate($dt);

$calc->numberDaysInMonth();      // 28  (Feb 2026 — not a leap year)
$calc->numberDaysLeftInMonth();  // 18  (days remaining in Feb after the 10th)

// Static helpers — no DateTime required
use District5\Date\Calculators\Calculate;

Calculate::numberDaysInMonthByGivenValues(2, 2024);       // 29  (leap year)
Calculate::numberDaysLeftInMonthByGivenValues(10, 2, 2026); // 18

Comparison helpers

$earlier = Date::createYMDHISM(2024, 1, 1);
$later   = Date::createYMDHISM(2026, 1, 1);

$calc = Date::calculate($earlier);

$calc->isOlderThan($later);              // true
$calc->isNewerThan($later);              // false
$calc->isOlderThanOrEqualTo($later);     // true
$calc->isNewerThanOrEqualTo($later);     // false

// Hours / minutes / seconds between two dates (absolute)
$calc->hours($later);    // int
$calc->minutes($later);  // int
$calc->seconds($later);  // int

Validating DateTime Objects

Date::validateObject($dateTime) returns a DateTimeValidator with boolean query methods.

Time of day

use District5\Date\Date;

$dt = Date::createYMDHISM(2026, 3, 30, 9, 0, 0);
$v  = Date::validateObject($dt);

$v->isAM();   // true
$v->isPM();   // false

Day of week

$v->isMonday();    $v->isTuesday();   $v->isWednesday();
$v->isThursday();  $v->isFriday();    $v->isSaturday();  $v->isSunday();

// Generic (1 = Monday … 7 = Sunday)
$v->isDayOfWeekX(5);  // true if Friday

Month

$v->isJanuary();   $v->isFebruary();  $v->isMarch();
$v->isApril();     $v->isMay();       $v->isJune();
$v->isJuly();      $v->isAugust();    $v->isSeptember();
$v->isOctober();   $v->isNovember();  $v->isDecember();

// Generic (1 = January … 12 = December)
$v->isMonthNumberX(3);  // true if March

Relative to today

$v->isYesterday();  // true if date is yesterday
$v->isToday();      // true if date is today
$v->isTomorrow();   // true if date is tomorrow

Leap year & comparisons

$v->isLeapYear();                    // true/false

$other = Date::createYMDHISM(2020, 1, 1);
$v->isOlderThan($other);
$v->isNewerThan($other);
$v->isOlderThanOrEqualTo($other);
$v->isNewerThanOrEqualTo($other);

$v->isHourLessThan(12);              // true if hour < 12
$v->isHourGreaterThan(8);            // true if hour > 8

Validating Strings

Date::validateString($input) returns a StringFormatValidator that checks whether the string can be parsed as various date formats.

use District5\Date\Date;

$v = Date::validateString('2026-03-30');

$v->isValidYMD();        // true  (YYYY-MM-DD)
$v->isValidDMY();        // false (DD-MM-YYYY)
$v->isValidMDY();        // false (MM-DD-YYYY)
$v->isValidYMDHIS();     // false (YYYY-MM-DD HH:MM:SS)
$v->isValidISO8601();    // false
$v->isValidUnixTimestamp();        // false
$v->isValidMillisecondTimestamp(); // false
$v->isValidMicrosecondTimestamp(); // false

Validating Arrays of DateTimes

Date::validateArray($dateTimes) returns a DateTimesValidator that works over a collection.

use District5\Date\Date;

$dates = [
    Date::createYMDHISM(2026, 1, 1),
    Date::createYMDHISM(2026, 6, 15),
    Date::createYMDHISM(2025, 12, 25),
];

$v = Date::validateArray($dates);

$v->allAreValid();       // true — all elements are DateTime instances
$v->hasAny();            // true — array is non-empty
$v->count();             // 3

Timezones

Convert DateTime objects between timezones using Date::timezone($dt).

Convert to a timezone

use District5\Date\Date;
use District5\Date\Tz\TzConstants;

$utc = Date::nowUtc();
$tz  = Date::timezone($utc);

// Using an IANA string
$ny = $tz->toTimezone('America/New_York');

// Using TzConstants
$london = $tz->toTimezone(TzConstants::EUROPE_LONDON);

Convert from one timezone to another

// Convert a DateTime that is in Europe/London to America/New_York
$converted = Date::timezone($dt)->toTimezoneFromTimezone(
    TzConstants::AMERICA_NEW_YORK,  // to
    TzConstants::EUROPE_LONDON       // from (optional, uses $dt's tz if omitted)
);

Selected TzConstants

ConstantValue
TzConstants::UTCUTC
TzConstants::EUROPE_LONDONEurope/London
TzConstants::EUROPE_PARISEurope/Paris
TzConstants::AMERICA_NEW_YORKAmerica/New_York
TzConstants::AMERICA_CHICAGOAmerica/Chicago
TzConstants::AMERICA_LOS_ANGELESAmerica/Los_Angeles
TzConstants::ASIA_TOKYOAsia/Tokyo
TzConstants::AUSTRALIA_SYDNEYAustralia/Sydney
Tip: TzConstants covers all standard IANA timezones. Use your IDE's autocomplete to browse the full list.

Sorting

Use Date::sorter() to sort arrays of DateTime objects or find extremes.

use District5\Date\Date;

$a = Date::createYMDHISM(2025, 6, 1);
$b = Date::createYMDHISM(2024, 1, 15);
$c = Date::createYMDHISM(2026, 12, 31);

$sorter = Date::sorter();

// Sort — variadic arguments
$asc  = $sorter->sortOldestToNewest($a, $b, $c);   // [$b, $a, $c]
$desc = $sorter->sortNewestToOldest($a, $b, $c);   // [$c, $a, $b]

// Find the oldest / newest from an array
$oldest = $sorter->oldest([$a, $b, $c]);  // $b (Jan 2024)
$newest = $sorter->newest([$a, $b, $c]);  // $c (Dec 2026)

Month Helpers

Use Date::month() to query information about months.

First and last day of a month

use District5\Date\Date;

$month = Date::month();

// By month number (and optional year — defaults to current year)
$first = $month->firstDateInMonth(3, 2026);  // 2026-03-01 00:00:00
$last  = $month->lastDateInMonth(3, 2026);   // 2026-03-31 00:00:00

// From a DateTime
$dt    = Date::createYMDHISM(2026, 2, 15);
$first = $month->firstDateInMonthFromDateTime($dt);  // 2026-02-01
$last  = $month->lastDateInMonthFromDateTime($dt);   // 2026-02-28

// For the current month
$first = $month->firstDateInCurrentMonth();
$last  = $month->lastDateInCurrentMonth();

Number of days in a month

$month->numberDaysInMonth(2, 2024);               // 29 (leap year)
$month->numberDaysInMonth(2, 2026);               // 28

$dt = Date::createYMDHISM(2026, 2, 1);
$month->numberDaysInMonthFromDateTime($dt);       // 28

Start & End of Periods

Use Date::startAndEnd() to obtain boundary DateTimes for days, months, and years.

Day boundaries

use District5\Date\Date;

$se = Date::startAndEnd();

// 2026-03-30 00:00:00
$start = $se->startOfDayFromYearMonthDay(2026, 3, 30);

// 2026-03-30 23:59:59
$end   = $se->endOfDayFromYearMonthDay(2026, 3, 30);

// From a DateTime
$dt    = Date::createYMDHISM(2026, 3, 30, 14, 0, 0);
$start = $se->startOfDayFromDateTime($dt);
$end   = $se->endOfDayFromDateTime($dt);

// Today / yesterday / tomorrow shortcuts
$se->startOfToday();     $se->endOfToday();
$se->startOfYesterday(); $se->endOfYesterday();
$se->startOfTomorrow();  $se->endOfTomorrow();

Month boundaries

// 2026-03-01 00:00:00
$start = $se->startOfMonthFromYearMonth(2026, 3);
// 2026-03-31 23:59:59
$end   = $se->endOfMonthFromYearMonth(2026, 3);

// From a DateTime
$start = $se->startOfMonthFromDateTime($dt);
$end   = $se->endOfMonthFromDateTime($dt);

Year boundaries

// 2026-01-01 00:00:00
$start = $se->startOfYearFromYear(2026);
// 2026-12-31 23:59:59
$end   = $se->endOfYearFromYear(2026);

// From a DateTime
$start = $se->startOfYearFromDateTime($dt);
$end   = $se->endOfYearFromDateTime($dt);

Recurring Dates

Use Date::recurring() to work with fixed annual dates. Each helper returns a RecurringDateManipulator.

Available dates

MethodDate
newYearsDay()January 1st
newYearsEve()December 31st
valentinesDay()February 14th
stDwynwensDay()January 25th
christmasEve()December 24th
christmasDay()December 25th
boxingDay()December 26th
starWarsDay()May 4th

RecurringDateManipulator methods

use District5\Date\Date;

$christmas = Date::recurring()->christmasDay();

$christmas->thisYear();    // 2026-12-25 00:00:00
$christmas->nextYear();    // 2027-12-25 00:00:00
$christmas->getNext();     // next upcoming occurrence (this or next year)
$christmas->getPrevious(); // most recent past occurrence

Example — how many days until Christmas?

$nextXmas = Date::recurring()->christmasDay()->getNext();
$today    = Date::nowUtc();
$days     = Date::diff($today)->days($nextXmas);
echo "Christmas is in {$days} days.";

MongoDB Integration

Requires the mongodb/mongodb PHP extension. Use Date::mongo() to convert between PHP DateTime and MongoDB BSON types.

UTCDateTime

use District5\Date\Date;

$dt    = Date::nowUtc();
$mongo = Date::mongo();

// DateTime → MongoDB\BSON\UTCDateTime
$bson = $mongo->convertTo($dt);

// MongoDB\BSON\UTCDateTime → DateTime
$dt   = $mongo->convertFrom($bson);

ObjectId

// DateTime → MongoDB\BSON\ObjectId  (timestamp-seeded)
$objectId = $mongo->toObjectId($dt);

// MongoDB\BSON\ObjectId → DateTime  (extracts creation timestamp)
$dt       = $mongo->fromObjectId($objectId);

Parsing from InputFormatter

// If you have a raw UTCDateTime or ObjectId as a variable $raw:
$dt = Date::input($raw)->fromMongoUtcDateTime($raw);
$dt = Date::input($raw)->fromMongoObjectId($raw);

NTP Server

Retrieve the current time from a Network Time Protocol server using Date::ntpServer(). Requires the ext-sockets PHP extension.

use District5\Date\Date;

$ntp = Date::ntpServer();

// Fetch Unix timestamp from pool.ntp.org (default)
$timestamp = $ntp->getUnixTimestamp();           // int|false

// Fetch from a custom NTP server
$timestamp = $ntp->getUnixTimestamp('time.google.com');

// Convert directly to a DateTime
$dt = $ntp->getDateTime();                       // DateTime|false
$dt = $ntp->getDateTime('time.cloudflare.com');
Note: NTP lookups make a UDP socket connection to the server on port 123. Ensure your server allows outbound UDP on that port.