date('Y-m-d') returns today's date as a string, such as 2026-03-14. The first argument is a format string where each letter stands for a part of the date (Y the year, m the month, d the day, H:i:s the time), and an optional second argument is a Unix timestamp to format instead of the current moment.
The output changes every time you press Run, because it is the current date and time in UTC. Every letter of the format string, and how to put plain text between them, is on the PHP date format page.
Timestamps: time(), mktime() and strtotime()
A Unix timestamp is the number of seconds since January 1, 1970 at midnight UTC. time() returns the current one, mktime(hour, minute, second, month, day, year) builds one from parts, and strtotime() reads a date written in English ('2026-03-14', '+1 week', 'next monday'). Pass any timestamp as the second argument of date(). The second argument of strtotime() is the moment a relative phrase counts from; without it, it counts from now.
Output:
1773480600
Sat, 14 Mar 2026 09:30
2027-01-01
tomorrow Sun 2026-03-15
+1 week Sat 2026-03-21
next monday Mon 2026-03-16
last day of this month Tue 2026-03-31
first monday of next month Mon 2026-04-06
bool(false)
The roll-over in mktime() is useful: day 0 of a month is the last day of the month before, so mktime(0, 0, 0, 3, 0, 2026) is February 28. Always compare the result with false before passing it on: date('Y-m-d', false) quietly prints 1970-01-01, a date nobody meant.
Add days to a date
For anything beyond printing, use DateTimeImmutable. Its modify() method takes the same phrases as strtotime() and returns a new date, and add() takes a DateInterval such as P7D (a period of 7 days) or PT90M (90 minutes).
Output:
2026-03-21
2026-03-13
2026-04-14
11:00
2025-03-14
2026-03-03
2026-02-28
February 31 does not exist, so +1 month on January 31 lands on March 3. When you mean "the end of next month", say so with last day of next month.
DateTime vs DateTimeImmutable
DateTime changes itself when you call modify(), add() or setDate(), and returns the same object. That surprises people who keep the original date in a variable:
Output:
2026-03-21
2026-03-21
bool(true)
2026-03-14
2026-03-21
Prefer DateTimeImmutable in new code. Both classes have the same methods and both implement DateTimeInterface, so a function can accept either.
Difference between two dates
diff() returns a DateInterval. Its days property is the total number of days between the two dates, while y, m and d split the gap into years, months and days, which is exactly what an age calculation needs. Change the dates and run it again:
Output:
Age: 35
Exactly: 35 years, 7 months, 22 days
Days alive: 13021
286 days to go
9 months and 11 days
-286 days
In format(), %a is the total days and %d is only the day part, so %a is the one to use for "days until". To compare two dates without a difference, the ordinary operators work on date objects: $today < $christmas is true.
Timezones
date() and new DateTimeImmutable() use the default timezone, which comes from date.timezone in php.ini (UTC when it is not set). Set it for the whole script with date_default_timezone_set(), or give a single date its own DateTimeZone and convert with setTimezone():
Output:
Asia/Tokyo 2026-03-14 18:30 JST +09:00
Europe/Berlin 2026-03-14 10:30 CET +01:00
America/New_York 2026-03-14 05:30 EDT -04:00
Asia/Tokyo
2026-03-14 18:30
A timestamp is the same number everywhere; the timezone only changes how it is written. That is why the usual advice is to store dates in UTC and convert when you display them.
Show a calendar on a web page
Dates are most often printed into HTML. This block draws the current month as a calendar and highlights today. Run it, then click Previous or Next: the same script runs again with $_GET['m'] set from the link, such as ?m=2026-04.
format('N') gives the weekday as 1 (Monday) to 7 (Sunday), which is how many empty cells go before the 1st, and format('t') gives the number of days in the month. The ! in '!Y-m' resets every field that the format does not mention, so the day is the 1st and the time is midnight.
Common mistakes with date()
The second argument of date() must be a timestamp, not a date string. This line:
<?php
echo date('d/m/Y', '2026-03-14');
stops the script with a TypeError:
PHP Fatal error: Uncaught TypeError: date(): Argument #2 ($timestamp) must be of type ?int, string given in /home/index.php:2
Convert the string first, with strtotime() or an object:
Output:
14/03/2026
14/03/2026
bool(false)
bool(true)
Two more to watch for: m is the month and i is the minutes, so 'H:m' prints the month where you wanted minutes; and new DateTimeImmutable('garbage') throws an exception instead of returning false, so wrap user input in try/catch or parse it with DateTimeImmutable::createFromFormat(), which returns false on a mismatch.
Frequently Asked Questions
How do I get the current date in PHP?
Call date() with a format string: echo date('Y-m-d'); prints today's date like 2026-03-14, and date('Y-m-d H:i:s') adds the time. The object version is (new DateTimeImmutable())->format('Y-m-d').
How do I add days to a date in PHP?
Use modify() on a DateTimeImmutable: (new DateTimeImmutable('2026-03-14'))->modify('+7 days')->format('Y-m-d') gives 2026-03-21. With timestamps, date('Y-m-d', strtotime('+7 days', $timestamp)) does the same.
How do I calculate the difference between two dates in PHP?
Call diff() on one date with the other: $a->diff($b) returns a DateInterval. Its days property is the total number of days, and y, m, d hold the years, months and days, which is how you calculate someone's age.
How do I convert a Unix timestamp to a date in PHP?
Pass it as the second argument of date(): date('Y-m-d H:i:s', 1773479107) returns 2026-03-14 09:05:07 in UTC. For an object, use new DateTimeImmutable('@1773479107').
Why does PHP date() show the wrong time?
date() uses the default timezone, which comes from date.timezone in php.ini and is often UTC. Set your own with date_default_timezone_set('Europe/Berlin') at the top of the script, or pass a DateTimeZone to DateTimeImmutable.