PHP Date and Time with DateTimeImmutable: Practical Guide

PHP date and time code can look simple until timezones, date calculations, or user input become involved. A date that works on your local computer may produce a different result on another server.

PHP still supports functions such as date(), time(), and strtotime(). They are useful for small tasks. For application code, DateTimeImmutable is usually easier to reason about because each change returns a new object instead of modifying the original value.

This guide explains how to create, format, parse, compare, and modify dates in PHP. It also shows how to handle timezones explicitly and avoid common date calculation mistakes. If you only need to display today’s date, see the focused guide on getting the current date in PHP.

Quick answer

Create a DateTimeImmutable object with an explicit timezone. You can then format the value or create a new value by adding a date interval.

<?php

$timezone = new DateTimeZone('Asia/Kolkata');
$now = new DateTimeImmutable('now', $timezone);

echo $now->format('Y-m-d H:i:s T');

$tomorrow = $now->add(new DateInterval('P1D'));

echo $tomorrow->format('Y-m-d H:i:s T');

The format Y-m-d H:i:s T displays the year, month, day, time, and timezone abbreviation. The original $now object remains unchanged. The added date is stored in $tomorrow.

How PHP represents dates and times

PHP commonly works with dates and times in three forms:

  • A formatted string, such as 2026-07-14 10:30:00
  • A Unix timestamp, which identifies a moment as the number of seconds since the Unix epoch
  • A date object, such as an instance of DateTimeImmutable

A formatted string is suitable for display, but it is not ideal for calculations. PHP must first interpret what the string means. Values such as 07/08/2026 are also ambiguous because they can represent different dates in different countries.

A Unix timestamp identifies a moment in time, but it does not contain a timezone. The timezone is applied when PHP converts that timestamp into a readable value.

<?php

$timestamp = time();

echo $timestamp;
echo PHP_EOL;
echo date('Y-m-d H:i:s', $timestamp);

A DateTimeImmutable object keeps the date, time, and timezone together. It also provides methods for formatting, comparison, timezone conversion, and date arithmetic.

<?php

$date = new DateTimeImmutable(
    '2026-07-14 10:30:00',
    new DateTimeZone('Asia/Kolkata')
);

echo $date->format(DateTimeInterface::ATOM);

The result includes the UTC offset:

2026-07-14T10:30:00+05:30

DateTimeImmutable or DateTime?

Both classes provide almost the same date and time operations. The important difference is how they handle changes.

DateTime modifies the existing object. DateTimeImmutable returns a new object and leaves the original unchanged.

<?php

$createdAt = new DateTimeImmutable('2026-07-14');
$expiresAt = $createdAt->add(new DateInterval('P30D'));

echo $createdAt->format('Y-m-d'); // 2026-07-14
echo PHP_EOL;
echo $expiresAt->format('Y-m-d'); // 2026-08-13

This behavior reduces accidental changes when the same date value is passed between methods. The examples in this guide therefore use DateTimeImmutable.

Create dates and times with DateTimeImmutable

The constructor accepts a date and time string followed by an optional DateTimeZone object. Pass the timezone explicitly when the value represents local time.

Get the current date and time

<?php

$timezone = new DateTimeZone('Asia/Kolkata');
$now = new DateTimeImmutable('now', $timezone);

echo $now->format('Y-m-d H:i:s T');

The word now tells PHP to use the current date and time. The result depends on the timezone supplied to the constructor.

Create a specific date and time

<?php

$timezone = new DateTimeZone('Europe/London');

$meeting = new DateTimeImmutable(
    '2026-10-15 14:30:00',
    $timezone
);

echo $meeting->format('Y-m-d H:i:s T');

PHP accepts many date strings, including values such as tomorrow and next Monday. These expressions are convenient when the value is written by a developer. When the input follows a known format or comes from a user, use createFromFormat() and validate the result instead.

Create a date from a Unix timestamp

Prefix a Unix timestamp with @ to create a date object from it.

<?php

$timestamp = 1784025000;

$date = new DateTimeImmutable('@' . $timestamp);
$date = $date->setTimezone(new DateTimeZone('Asia/Kolkata'));

echo $date->format('Y-m-d H:i:s T');

A timestamp represents a specific moment. PHP initially creates an @ timestamp value in UTC. Calling setTimezone() changes how that moment is displayed without changing the moment itself.

Create a date from separate values

You can also start with an object and set its date and time components explicitly.

<?php

$timezone = new DateTimeZone('UTC');

$releaseDate = (new DateTimeImmutable('now', $timezone))
    ->setDate(2026, 9, 20)
    ->setTime(9, 15, 0);

echo $releaseDate->format('Y-m-d H:i:s T');

This approach is useful when the year, month, day, hour, and minute are already available as separate validated values.

Format a PHP date and time

The format() method converts a date object into a string. Its argument contains characters that represent parts of the date and time.

<?php

$date = new DateTimeImmutable(
    '2026-07-14 16:45:30',
    new DateTimeZone('Asia/Kolkata')
);

echo $date->format('Y-m-d H:i:s');
echo PHP_EOL;
echo $date->format('F j, Y');
echo PHP_EOL;
echo $date->format('g:i A');

This code produces:

2026-07-14 16:45:30
July 14, 2026
4:45 PM

Common format characters

Character Meaning Example
Y Four-digit year 2026
m Month with a leading zero 07
d Day with a leading zero 14
H Hour in 24-hour format 16
i Minutes 45
s Seconds 30
T Timezone abbreviation IST
P UTC offset with a colon +05:30

Format characters are case-sensitive. For example, m represents a numeric month, while M returns a short month name.

Generate an ISO 8601 value

Use the DateTimeInterface::ATOM constant when another application or API expects an ISO 8601 date and time.

<?php

$date = new DateTimeImmutable(
    '2026-07-14 16:45:30',
    new DateTimeZone('Asia/Kolkata')
);

echo $date->format(DateTimeInterface::ATOM);

The output contains the local time and its UTC offset:

2026-07-14T16:45:30+05:30

For a more detailed format-character reference and additional output patterns, see formatting dates in PHP.

Parse and validate a date in a known format

Use DateTimeImmutable::createFromFormat() when an input must follow a specific format. This is more predictable than asking PHP to guess the meaning of a date string.

The following function accepts only a valid date in Y-m-d format:

<?php

function parseDate(
    string $input,
    DateTimeZone $timezone
): ?DateTimeImmutable {
    $date = DateTimeImmutable::createFromFormat(
        '!Y-m-d',
        $input,
        $timezone
    );

    $parseErrors = DateTimeImmutable::getLastErrors();

    $hasErrors = $parseErrors !== false
        && (
            $parseErrors['warning_count'] > 0
            || $parseErrors['error_count'] > 0
        );

    if (
        $date === false
        || $hasErrors
        || $date->format('Y-m-d') !== $input
    ) {
        return null;
    }

    return $date;
}

$timezone = new DateTimeZone('Asia/Kolkata');
$date = parseDate('2026-07-14', $timezone);

if ($date === null) {
    echo 'Invalid date';
} else {
    echo $date->format('F j, Y');
}

The function checks both errors and warnings. This matters because PHP may normalize an invalid date instead of rejecting it immediately. For example, a value such as 2026-02-30 can roll forward into March.

Why the format starts with an exclamation mark

The ! at the beginning of !Y-m-d resets fields that are not included in the input. The hour, minute, and second therefore become zero.

Without it, the missing time fields can inherit values from the current time. That behavior is easy to overlook when you expect a date-only value to represent midnight.

<?php

$date = DateTimeImmutable::createFromFormat(
    '!Y-m-d',
    '2026-07-14',
    new DateTimeZone('UTC')
);

echo $date->format('Y-m-d H:i:s');

The output is:

2026-07-14 00:00:00

Validate a date and time from an HTML form

An HTML datetime-local field normally submits a value such as 2026-07-14T16:45. It does not include a timezone, so your application must supply the timezone that gives the value meaning.

<?php

$input = '2026-07-14T16:45';
$timezone = new DateTimeZone('Asia/Kolkata');

$date = DateTimeImmutable::createFromFormat(
    '!Y-m-d\TH:i',
    $input,
    $timezone
);

$parseErrors = DateTimeImmutable::getLastErrors();

$hasErrors = $parseErrors !== false
    && (
        $parseErrors['warning_count'] > 0
        || $parseErrors['error_count'] > 0
    );

if (
    $date === false
    || $hasErrors
    || $date->format('Y-m-d\TH:i') !== $input
) {
    echo 'Enter a valid date and time.';
} else {
    echo $date->format(DateTimeInterface::ATOM);
}

Do not assume that a browser field makes the value valid. Client-side validation improves the form experience, but the server must still validate the submitted date.

Handle timezones correctly

A date and time string has no complete meaning until its timezone is known. The value 2026-07-14 09:00:00 represents different moments in London, New York, and Kolkata.

Use an IANA timezone identifier such as Asia/Kolkata or America/New_York. These identifiers allow PHP to apply the correct regional offset and daylight-saving rules.

<?php

$timezone = new DateTimeZone('America/New_York');

$appointment = new DateTimeImmutable(
    '2026-07-14 09:00:00',
    $timezone
);

echo $appointment->format('Y-m-d H:i:s P e');

The P character displays the UTC offset. The e character displays the timezone identifier.

Convert a date to another timezone

Use setTimezone() to display the same moment in another timezone.

<?php

$newYorkTime = new DateTimeImmutable(
    '2026-07-14 09:00:00',
    new DateTimeZone('America/New_York')
);

$kolkataTime = $newYorkTime->setTimezone(
    new DateTimeZone('Asia/Kolkata')
);

echo $newYorkTime->format('Y-m-d H:i:s P');
echo PHP_EOL;
echo $kolkataTime->format('Y-m-d H:i:s P');

The displayed clock time and offset change, but both objects represent the same instant. Their Unix timestamps are equal.

<?php

var_dump(
    $newYorkTime->getTimestamp()
    === $kolkataTime->getTimestamp()
);

This outputs true.

Use UTC for stored moments

UTC is a practical choice when storing moments such as payment times, login times, or audit events. Convert the value to the user’s timezone when displaying it.

<?php

$localDate = new DateTimeImmutable(
    '2026-07-14 09:00:00',
    new DateTimeZone('America/New_York')
);

$utcDate = $localDate->setTimezone(new DateTimeZone('UTC'));

echo $utcDate->format('Y-m-d H:i:s');

Not every date should be converted to UTC. A birthday or calendar-only deadline may be a civil date rather than a precise moment. Store the original date when the timezone is not part of its meaning.

Avoid timezone abbreviations in application logic

Abbreviations such as CST and IST can be ambiguous. A fixed offset such as +05:30 is clearer, but it does not contain regional daylight-saving rules.

Prefer identifiers such as Asia/Kolkata, Europe/London, and America/Chicago when the location matters. See the guide to PHP timezone conversion for more timezone-specific examples.

Add, subtract, and compare dates

Use DateInterval when the amount is known and structured. Its interval specification starts with P for a date period and PT for a time period.

<?php

$createdAt = new DateTimeImmutable(
    '2026-07-14 10:30:00',
    new DateTimeZone('Asia/Kolkata')
);

$afterSevenDays = $createdAt->add(
    new DateInterval('P7D')
);

$beforeTwoHours = $createdAt->sub(
    new DateInterval('PT2H')
);

echo $afterSevenDays->format('Y-m-d H:i:s');
echo PHP_EOL;
echo $beforeTwoHours->format('Y-m-d H:i:s');

The common interval units are:

  • P1D for one day
  • P2W for two weeks
  • P3M for three months
  • P1Y for one year
  • PT30M for 30 minutes
  • PT4H for four hours

Use modify() for readable date changes

The modify() method accepts relative date expressions. It is useful when the rule is easier to read as a phrase.

<?php

$date = new DateTimeImmutable(
    '2026-07-14 10:30:00',
    new DateTimeZone('UTC')
);

$nextMonday = $date->modify('next Monday');
$endOfMonth = $date->modify('last day of this month');

echo $nextMonday->format('Y-m-d');
echo PHP_EOL;
echo $endOfMonth->format('Y-m-d');

Keep relative expressions in application code. Do not pass unchecked user text directly to modify().

Do not add a fixed number of seconds for calendar days

A calendar day is not always the same as 86,400 elapsed seconds in regions that observe daylight-saving time. Use a calendar operation when the requirement says “tomorrow” or “seven days later.”

<?php

$date = new DateTimeImmutable(
    '2026-03-07 09:00:00',
    new DateTimeZone('America/New_York')
);

$nextDay = $date->add(new DateInterval('P1D'));

echo $nextDay->format('Y-m-d H:i:s P');

This asks PHP for the next calendar date in the same regional timezone. It also allows PHP to apply the timezone rules for that date.

Be careful when adding months

Months have different lengths. Adding one month to a date near the end of a month can produce an unexpected result.

<?php

$date = new DateTimeImmutable('2026-01-31');
$result = $date->add(new DateInterval('P1M'));

echo $result->format('Y-m-d');

The result is 2026-03-03. PHP first moves to February 31 and then normalizes the overflow into March.

If the business rule means the last day of the following month, state that rule directly:

<?php

$date = new DateTimeImmutable('2026-01-31');
$result = $date->modify('last day of next month');

echo $result->format('Y-m-d'); // 2026-02-28

Calculate the difference between two dates

The diff() method returns a DateInterval that describes the difference between two objects.

<?php

$start = new DateTimeImmutable('2026-07-14');
$end = new DateTimeImmutable('2026-07-25');

$difference = $start->diff($end);

echo $difference->format('%a days');

The output is 11 days. Use %r%a instead of %a when the sign of the difference matters.

Compare two date objects

Date objects can be compared directly with PHP comparison operators.

<?php

$expiresAt = new DateTimeImmutable(
    '2026-07-20 18:00:00',
    new DateTimeZone('UTC')
);

$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));

if ($now >= $expiresAt) {
    echo 'Expired';
} else {
    echo 'Active';
}

Use the same timezone for both values when possible. PHP can compare objects with different timezones, but normalizing them to UTC makes the intent easier to review.

When to use PHP date and time functions

The object API is a good default for application code, but PHP’s procedural date and time functions remain useful for small, focused tasks.

date(): Format a timestamp

The date() function accepts a required format and an optional Unix timestamp. When the timestamp is omitted, PHP uses the current time.

<?php

date_default_timezone_set('Asia/Kolkata');

echo date('Y-m-d H:i:s');
echo PHP_EOL;
echo date('Y-m-d', 1784025000);

The function uses PHP’s configured default timezone when formatting the value. Set that timezone in the application configuration instead of relying on the server default.

time(): Get the current Unix timestamp

The time() function returns the current Unix timestamp as an integer.

<?php

$timestamp = time();

echo $timestamp;

A Unix timestamp identifies a moment without storing a regional timezone. It is useful for expiration checks, sorting, and communication between systems. See the guide to PHP timestamps for more conversion and storage examples.

strtotime(): Parse a relative date string

The strtotime() function converts a supported date string into a Unix timestamp.

<?php

date_default_timezone_set('UTC');

$timestamp = strtotime('next Monday 09:00');

if ($timestamp === false) {
    echo 'Could not parse the date.';
} else {
    echo date('Y-m-d H:i:s', $timestamp);
}

Always compare the return value with false. Do not use a loose condition such as if (!$timestamp), because 0 is a valid Unix timestamp.

strtotime() is convenient for date expressions written by a developer. Use createFromFormat() when user input must follow a known format.

getdate(): Get separate date components

The getdate() function returns an associative array containing components such as the year, month, weekday, hours, and minutes.

<?php

date_default_timezone_set('UTC');

$parts = getdate();

echo $parts['year'];
echo PHP_EOL;
echo $parts['month'];
echo PHP_EOL;
echo $parts['weekday'];

This can be useful when an older API expects an array. For most new code, methods such as format() provide a clearer way to retrieve individual components.

mktime(): Build a timestamp from date components

The mktime() function creates a timestamp from separate hour, minute, second, month, day, and year values.

<?php

date_default_timezone_set('Asia/Kolkata');

$timestamp = mktime(
    14,
    30,
    0,
    7,
    14,
    2026
);

echo date('Y-m-d H:i:s', $timestamp);

The parameter order is easy to misread. When clarity matters, creating a DateTimeImmutable object with setDate() and setTime() is usually easier to maintain.

Common PHP date and time errors

The displayed time is several hours wrong

This usually means PHP is using an unexpected default timezone. Check the configured timezone before changing the date value itself.

<?php

echo date_default_timezone_get();

For application code, pass the intended timezone explicitly:

<?php

$now = new DateTimeImmutable(
    'now',
    new DateTimeZone('Asia/Kolkata')
);

echo $now->format('Y-m-d H:i:s P');

The month appears where the minutes should be

PHP format characters are case-sensitive. Lowercase m represents the month. Lowercase i represents minutes.

<?php

$date = new DateTimeImmutable('2026-07-14 16:45:00');

echo $date->format('Y-m-d H:i:s');

Use H:i:s for a 24-hour time. Use h:i:s A for a 12-hour time with AM or PM.

DateTimeImmutable does not appear to change

Methods such as add(), modify(), and setTimezone() return a new object. They do not alter the existing object.

<?php

$date = new DateTimeImmutable('2026-07-14');

$date->modify('+1 day');

echo $date->format('Y-m-d'); // Still 2026-07-14

Assign the returned object to a variable:

<?php

$date = new DateTimeImmutable('2026-07-14');
$date = $date->modify('+1 day');

echo $date->format('Y-m-d'); // 2026-07-15

An invalid date silently changes

PHP may normalize an out-of-range value. For example, the 31st day of a 30-day month can roll into the following month.

When a date must match a known format, parse it with createFromFormat(). Check getLastErrors() and compare the formatted result with the original input.

A timestamp produces a date near January 1970

PHP timestamps use seconds. Some systems, including browser-side JavaScript APIs, commonly use milliseconds.

<?php

$milliseconds = 1784025000000;
$seconds = intdiv($milliseconds, 1000);

$date = (new DateTimeImmutable('@' . $seconds))
    ->setTimezone(new DateTimeZone('UTC'));

echo $date->format('Y-m-d H:i:s T');

Confirm the unit before storing or converting a timestamp. A value with 13 digits is commonly a millisecond value, while current Unix timestamps in seconds have 10 digits. Treat the digit count as a clue, not as the only validation.

strtotime() returns false

strtotime() returns false when it cannot parse the supplied string. Check for that result before passing the value to date().

<?php

$timestamp = strtotime('not a real date');

if ($timestamp === false) {
    echo 'Invalid date string';
} else {
    echo date('Y-m-d', $timestamp);
}

If false is used as though it were a timestamp, it can become 0 and display a date close to the Unix epoch.

The ISO date has an unexpected timezone offset

Use DateTimeInterface::ATOM or DateTimeInterface::RFC3339 when generating a standard date and time for an API.

<?php

$date = new DateTimeImmutable(
    '2026-07-14 16:45:00',
    new DateTimeZone('Asia/Kolkata')
);

echo $date->format(DateTimeInterface::RFC3339);

The result includes the local UTC offset. Convert the object to UTC first if the receiving system requires a UTC value.

<?php

$utcDate = $date->setTimezone(new DateTimeZone('UTC'));

echo $utcDate->format(DateTimeInterface::RFC3339);

Security considerations

Date and time values are still user input. Validate them before using them in calculations, database queries, access rules, or expiry checks.

Accept a known input format

Do not rely on PHP to guess the meaning of a submitted date. Define the expected format and reject values that do not match it exactly.

<?php

$input = $_POST['event_date'] ?? '';

$date = DateTimeImmutable::createFromFormat(
    '!Y-m-d',
    $input,
    new DateTimeZone('UTC')
);

$parseErrors = DateTimeImmutable::getLastErrors();

$hasErrors = $parseErrors !== false
    && (
        $parseErrors['warning_count'] > 0
        || $parseErrors['error_count'] > 0
    );

if (
    $date === false
    || $hasErrors
    || $date->format('Y-m-d') !== $input
) {
    exit('Invalid date.');
}

Allow only supported timezones

Avoid passing an unchecked timezone string directly into DateTimeZone. Use an allow-list when the application supports a limited number of regions.

<?php

$allowedTimezones = [
    'UTC',
    'Asia/Kolkata',
    'Europe/London',
    'America/New_York',
];

$timezoneInput = $_POST['timezone'] ?? 'UTC';

if (!in_array($timezoneInput, $allowedTimezones, true)) {
    exit('Unsupported timezone.');
}

$timezone = new DateTimeZone($timezoneInput);

If users may choose any valid regional timezone, compare the submitted value against DateTimeZone::listIdentifiers().

Do not pass unchecked text to modify()

The modify() method understands a wide range of relative expressions. Build the expression from a validated number instead of accepting the full expression from a request.

<?php

$days = filter_input(
    INPUT_POST,
    'days',
    FILTER_VALIDATE_INT,
    [
        'options' => [
            'min_range' => -365,
            'max_range' => 365,
        ],
    ]
);

if ($days === false || $days === null) {
    exit('Enter a valid number of days.');
}

$date = new DateTimeImmutable('now', new DateTimeZone('UTC'));
$result = $date->modify(sprintf('%+d days', $days));

echo $result->format('Y-m-d');

The range check also prevents unexpectedly large calculations that do not make sense for the application.

Escape date-related output

A formatted date created entirely by your code is usually safe to display. A timezone label, event name, or original date string supplied by a user must still be escaped before it is added to HTML.

<?php

function escape(string $value): string
{
    return htmlspecialchars(
        $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );
}

echo escape($timezoneInput);

Use server time for security decisions

Do not trust a browser-supplied current time when checking whether a token, subscription, or session has expired. A user can change values submitted by the browser.

<?php

$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));

if ($now >= $expiresAt) {
    echo 'Expired';
}

Calculate the current time and enforce the rule on the server. Client-side clocks can still be used for display-only countdowns and interface updates.

PHP date and time best practices

  • Use DateTimeImmutable for application logic involving timezones, comparisons, or date calculations.
  • Attach an explicit timezone when a date represents local time.
  • Use IANA identifiers such as Asia/Kolkata instead of ambiguous abbreviations.
  • Parse known input formats with createFromFormat().
  • Check both warnings and errors after parsing a date.
  • Use calendar operations for days and months instead of adding a fixed number of seconds.
  • Use UTC for stored moments, then convert them for display.
  • Keep civil dates, such as birthdays, as date-only values when a timezone has no meaning.
  • Use ISO 8601 or RFC 3339 when exchanging date and time values with APIs.
  • Get the current time from the server when enforcing expiry or access rules.

Choose the right PHP date API

Requirement Recommended API
Get the current Unix timestamp time()
Format one timestamp quickly date()
Work with timezones DateTimeImmutable and DateTimeZone
Parse a known input format DateTimeImmutable::createFromFormat()
Add or subtract a structured period DateInterval with add() or sub()
Calculate the difference between dates DateTimeImmutable::diff()
Convert between timezones DateTimeImmutable::setTimezone()
Parse a developer-controlled relative expression modify() or strtotime()

The procedural functions are not obsolete. They remain useful for short operations. The object API becomes more valuable as soon as a date crosses a timezone, requires validation, or participates in business logic.

Developer FAQ

What is the recommended way to get the current date and time in PHP?

Create a DateTimeImmutable object with an explicit timezone:

<?php

$now = new DateTimeImmutable(
    'now',
    new DateTimeZone('Asia/Kolkata')
);

echo $now->format('Y-m-d H:i:s');

This keeps the timezone visible in the code and avoids depending on an unknown server configuration.

What is the difference between date() and DateTimeImmutable?

date() formats a Unix timestamp and returns a string. DateTimeImmutable represents a date, time, and timezone as an object. It also provides methods for parsing, comparison, date arithmetic, and timezone conversion.

Use date() for simple formatting. Use DateTimeImmutable when the value is part of application logic.

Does a Unix timestamp contain a timezone?

No. A Unix timestamp identifies a moment as a number of seconds from the Unix epoch. PHP applies a timezone when it converts that timestamp into a readable date and time.

Two date objects in different timezones can have the same timestamp because they represent the same moment.

Why does PHP show a different time on the server?

The server may have a different default timezone from your local computer. Check it with date_default_timezone_get().

You can configure the application’s default timezone or pass a DateTimeZone object explicitly. Explicit timezones are easier to understand when reading the code.

How should PHP dates be stored in a database?

Store precise moments, such as payment or login times, in UTC. Convert them into the user’s timezone when displaying them.

Store date-only values, such as birthdays, without timezone conversion. For a future local event, you may need both the local date and its IANA timezone identifier because regional offsets can change.

Why can createFromFormat() accept an invalid-looking date?

PHP may normalize an out-of-range component instead of returning false. For example, an extra day can roll into the next month.

Call DateTimeImmutable::getLastErrors() after parsing. Reject the value if it contains warnings or errors, and compare the formatted result with the original input.

Why does getLastErrors() sometimes return false?

On current PHP versions, getLastErrors() returns false when the last parsing operation produced no warnings or errors. Code should handle both an array and false.

<?php

$errors = DateTimeImmutable::getLastErrors();

$hasErrors = $errors !== false
    && (
        $errors['warning_count'] > 0
        || $errors['error_count'] > 0
    );

Should I use strtotime() for form input?

Use strtotime() when you intentionally accept flexible date expressions. For a form field with a defined format, use createFromFormat() and validate the result. This prevents PHP from guessing an unintended date.

Download the PHP date and time example project

The example project provides a working date and time converter built with DateTimeImmutable. It accepts a local date, an IANA timezone, and the number of days to add or subtract.

The result displays:

  • The formatted local date and time
  • An ISO 8601 value
  • The corresponding UTC date and time
  • The Unix timestamp
  • The adjusted calendar date

The form validates the date on the server. It also restricts timezone values and date adjustments to supported ranges. No database or third-party package is required.

Project files

php-date-time-demo/
├── assets/
│   └── styles.css
├── index.php
└── README.md

Run the project locally

  1. Download and extract the ZIP file.
  2. Open a terminal inside the php-date-time-demo directory.
  3. Start the PHP development server with the following command.
php -S localhost:8000

Open http://localhost:8000 in your browser. Select a timezone, enter a date and time, and choose how many days to add or subtract.

PHP DateTimeImmutable converter showing local time, UTC, Unix timestamp, and adjusted date

PHP date and time converter built with DateTimeImmutable and DateTimeZone.

Download the PHP date and time example project

Photo of Vincy, PHP developer
Written by Vincy Last updated: July 14, 2026
I'm a PHP developer with 20+ years of experience and a Master's degree in Computer Science. I build and improve production PHP systems for eCommerce, payments, webhooks, and integrations, including legacy upgrades (PHP 5/7 to PHP 8.x).

Continue Learning

These related tutorials may help you continue learning.

2 Comments on "PHP Date and Time with DateTimeImmutable: Practical Guide"

  • krishna says:

    hi vincy, how can i create year 1900 to 2014 dropdown by using loop? please help this

    • kodfabriken says:

      // Start the dropdown
      echo ”;

      // Loop from 1900 to 2025
      for ($year = 1900; $year <= 2025; $year++) {
      // Create an option for each year
      echo '’ . $year . ”;
      }

      // End the dropdown
      echo ”;

Leave a Reply

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

Explore topics
Need PHP help?