localtime#
Convert an epoch time to a broken-down calendar time in the local time zone.
localtime takes a Unix epoch value — seconds since 1970-01-01 UTC,
the shape returned by time — and decomposes it into year,
month, day, hour, minute, second, weekday, yearday, and a
daylight-saving flag, all expressed in the local time zone. The
time zone is read from the TZ environment variable if set, otherwise
from the system default (typically /etc/localtime). For the UTC
companion that ignores TZ, see gmtime.
Synopsis#
localtime EXPR
localtime
What you get back#
The return shape depends on context, and localtime is one of the
handful of built-ins where the same expression in list context and
scalar context produces completely different answers.
List context — a 9-element list, all numeric, taken straight out
of the C struct tm:
# 0 1 2 3 4 5 6 7 8
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime(time);
Index |
Name |
Range |
Notes |
|---|---|---|---|
0 |
|
|
|
1 |
|
|
|
2 |
|
|
|
3 |
|
|
1-based day of the month |
4 |
|
|
0-based: |
5 |
|
years - 1900 |
e.g. |
6 |
|
|
|
7 |
|
|
0-based day of the year; |
8 |
|
boolean |
true when DST is in effect for the local TZ |
The 0-based $mon and 1900-based $year are long-standing C
inheritances; most bugs written against localtime come from
forgetting exactly one of them. The fix for $year is += 1900:
my @t = localtime;
my $full_year = $t[5] + 1900;
Scalar context — the familiar English ctime(3) string, always
24 characters, always in English regardless of locale:
my $now_string = localtime; # "Thu Oct 13 04:54:34 1994"
For a locale-aware or custom-formatted string, do not try to pick
apart the scalar form. Go through the list form and
POSIX::strftime:
use POSIX qw(strftime);
my $now_string = strftime "%a %b %e %H:%M:%S %Y", localtime;
Global state it touches#
TZin%ENV— selects the local time zone. A program that wants to interpret a timestamp in a specific zone sets$ENV{TZ}and callsPOSIX::tzsetbeforelocaltime(see Edge cases for the caveat).System zoneinfo (
/etc/localtime,/usr/share/zoneinfo/...) whenTZis unset — read lazily by the C library, not by Perl directly.%ENVchanges toTZdo not always take effect on the next call; see Edge cases.
localtime does not touch $_ or any output-related globals.
Examples#
Current wall-clock date in a human-readable string:
my $now = localtime; # "Wed Apr 23 14:07:12 2025"
Current date as a 9-element list — note the two offsets:
my ($s,$m,$h,$md,$mo,$y,$wd,$yd,$dst) = localtime;
printf "%04d-%02d-%02d %02d:%02d:%02d\n",
$y+1900, $mo+1, $md, $h, $m, $s; # "2025-04-23 14:07:12"
Month name from $mon using a lookup table — this is the canonical
way, because $mon is 0-based exactly so it indexes an array:
my @abbr = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my ($mday, $mon) = (localtime)[3,4];
print "$abbr[$mon] $mday"; # e.g. "Apr 23"
Formatting with POSIX::strftime
— the right answer whenever you need anything other than the bare
English ctime string:
use POSIX qw(strftime);
my @now = localtime;
my $stamp = strftime "%Y-%m-%d %H:%M:%S", @now; # "2025-04-23 14:07:12"
Interpreting a stored epoch in a specific zone. Set TZ, call
POSIX::tzset, then localtime:
use POSIX qw(tzset);
local $ENV{TZ} = "Europe/Berlin";
tzset();
my $wall = localtime(1_700_000_000); # "Tue Nov 14 23:13:20 2023"
Context trap — localtime inside print LIST is in list
context, so you get nine numbers concatenated with no spaces. Use
scalar to force the string form:
print localtime, "\n"; # e.g. "12724232312505230"
print scalar localtime, "\n"; # "Wed Apr 23 14:07:12 2025"
Edge cases#
No argument:
localtimewith no argument usestime— the current wall-clock moment.Negative epoch: dates before 1970-01-01 UTC are accepted on systems with a signed
time_t. Portability of very distant past or future times depends on the platform’s C library.$yearpitfall:$year + 1900gives the full year. Writing"19$year"was a Y2K bug and is still wrong; write1900 + $year.$monpitfall:$monis 0-based.localtimeoutput feeding anything 1-based (includingPOSIX::mktime) does not need adjustment —mktimeexpects the same 0-based convention. External systems (databases, ISO-8601 strings) usually want$mon + 1.$isdstis advisory, not directly comparable across zones.1means “the local zone currently applies its DST offset”;0means “standard time”;-1occasionally appears when the zone rules cannot decide (e.g. the hour that does not exist on a spring-forward day).TZreload caveat: most C libraries (glibc included) cache the parsed zone rules on the first lookup. A later assignment to$ENV{TZ}is not picked up automatically — callPOSIX::tzsetafter every change, or the old zone will keep being used.Scalar string is always English and is not affected by
LC_TIMEor any other locale setting. For a localized string, go throughPOSIX::strftimewithLC_TIMEset to the desired locale.Thread safety: on systems where the C
localtime(3)call is not reentrant, concurrent threads mutatingTZcan race. In practice pperl and modern glibc use the reentrantlocaltime_rinternally, butTZis still a process-wide global.Leap seconds:
$seccan legally be60on systems with leap second support. Most systems smear or ignore them and you will never see it; code that must not break on60handles it already.%a/%bwidth underPOSIX::strftime: the abbreviated weekday and month names are not guaranteed three characters in every locale. Code that assumes a fixed column width will misalign in German, French, and many others.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
gmtime— same decomposition in UTC; does not consultTZand is the right choice when you want a time zone–independent valuetime— the epoch source thatlocaltimemost often receives as its argumentPOSIX::strftime— format alocaltimelist into any string layout you need, locale-awarePOSIX::mktime— inverse direction: take a 9-element list back to an epoch valuePOSIX::tzset— re-readTZafter changing it, mandatory if you want the change to take effect$ENV{TZ}— the environment variablelocaltimereads to pick the local zone