Dates and logging
A page's PHP asks for the date all the time: to stamp a record, to say how old a comment is, to write down what happened. These helpers give "now" in the application's timezone, read a date whatever form it arrives in, put an age into words and keep a log of the application's own - plain functions, loaded on every request.
| function | what it answers |
|---|---|
padNow ( $format = NULL )
|
now, as a DateTimeImmutable in $padTimezone (else PHP's zone) - or, with a format, the formatted text
|
padToday ( $format = NULL )
|
today at midnight |
padNowFreeze ( $time = NULL )
|
fixes now for the rest of the request; NULL lets the clock run again
|
padDateParse ( $value )
|
a DateTimeImmutable from a timestamp, a date in text or a date object - NULL for what is none of those
|
padAgo ( $date, $now = NULL )
|
the age in words: just now, 5 minutes ago, yesterday, in 3 days |
padLog ( $message, $level = 'info', $context = [] )
|
appends one line to the application's log of the day |
Now and today
The example freezes the clock first, so it shows the same on every day it is read - what a test does too. Without the freeze, now is the real moment.
|
PHP fragments/dates_and_logging_1.php |
HTML fragments/dates_and_logging_1.pad |
Result |
|---|---|---|
|
|
Now: Monday 5 October 2026, 14:30 Today: 2026-10-05 00:00:00 Christmas: Friday 25 December A week from now: 2026-10-12 30 February: NULL |
- A number is a Unix timestamp, as the
datepipe reads it; text is read the way PHP'sDateTimereads it. A timestamp and text without a zone are in the application's zone; a zone that was given is kept. - A date that does not exist -
2026-02-30, which PHP itself would make 2 March - is no date, nor areNULL,''and booleans:padDateParseanswersNULLfor them, never an error. -
$padTimezoneis read when a function is called, so a page can set it for itself.
Freezing the clock
padNowFreeze ( '2026-10-05 14:30:00' ) fixes now for the rest of the request: padNow, padToday, padAgo, the time stamp of padLog, and text like tomorrow or +1 week given to padDateParse all count from that moment. A test gets the same answer on every run, and a page can be looked at as it will be on another day. padNowFreeze () lets the clock run again.
How long ago
padAgo says the age of a moment in words, and the ago pipe does the same in a template: {$posted | ago}.
|
PHP fragments/dates_and_logging_2.php |
HTML fragments/dates_and_logging_2.pad |
Result |
|---|---|---|
|
|
The deadline is in 3 days. |
- Under ten seconds is just now, then seconds, minutes and hours. From a day on the calendar counts: the day before today is yesterday whatever the hour, then days, weeks, months and years.
- A moment still to come is said the other way round: in 3 days, tomorrow.
- A second argument -
padAgo ( $start, $end ), or{$start | ago($end)}- counts from that moment instead of now. An empty value answers nothing.
Logging
padLog appends one line to DATA/logs/<application>/<Y-m-d>.log: the time, the level, the message and the context as JSON. The levels are those of PSR-3 - debug, info, notice, warning, error, critical, alert and emergency - and {name} in the message is filled from the context.
|
PHP fragments/dates_and_logging_3.php |
HTML fragments/dates_and_logging_3.pad |
Result |
|---|---|---|
|
|
2026-10-05 14:30:00 INFO Order 1042 paid by Ann {"order":1042,"customer":"Ann"}
|
- One call is always one line: a newline in the message is written
\n. - A message that is no text is written as JSON; a
Throwablein the context as its class, message, file and line. - A log line never stops the page: a disk that refuses the write is answered
FALSE, not an exception. An unknown level is an error, the author's mistake. - The engine's own errors go to PHP's error log; this log is for what the application wants to remember - a payment, a login, a failed import.