--- name: localtime signature: 'localtime EXPR' signatures: - 'localtime EXPR' - 'localtime' since: 5.0 status: documented categories: ["Time"] --- ```{index} single: localtime; Perl built-in ``` *[Time](../perlfunc-by-category)* # 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`](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`](gmtime). ## Synopsis ```perl 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`: ```perl # 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 | `$sec` | `0..60` | `60` is possible for leap seconds | | 1 | `$min` | `0..59` | | | 2 | `$hour` | `0..23` | | | 3 | `$mday` | `1..31` | 1-based day of the month | | 4 | `$mon` | `0..11` | **0-based**: `0` = January, `11` = December | | 5 | `$year` | years - 1900 | e.g. `129` for 2029 | | 6 | `$wday` | `0..6` | `0` = Sunday, `3` = Wednesday | | 7 | `$yday` | `0..365` | 0-based day of the year; `365` in leap year | | 8 | `$isdst` | 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`: ```perl 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: ```perl 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`: ```perl use POSIX qw(strftime); my $now_string = strftime "%a %b %e %H:%M:%S %Y", localtime; ``` ## Global state it touches - **`TZ`** in [`%ENV`](../perlvar) — selects the local time zone. A program that wants to interpret a timestamp in a specific zone sets `$ENV{TZ}` and calls `POSIX::tzset` before `localtime` (see *Edge cases* for the caveat). - System zoneinfo (`/etc/localtime`, `/usr/share/zoneinfo/...`) when `TZ` is unset — read lazily by the C library, not by Perl directly. - [`%ENV`](../perlvar) changes to `TZ` do **not** always take effect on the next call; see *Edge cases*. `localtime` does not touch [`$_`](../perlvar) or any output-related globals. ## Examples Current wall-clock date in a human-readable string: ```perl my $now = localtime; # "Wed Apr 23 14:07:12 2025" ``` Current date as a 9-element list — note the two offsets: ```perl 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: ```perl 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: ```perl 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`: ```perl 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`](scalar) to force the string form: ```perl print localtime, "\n"; # e.g. "12724232312505230" print scalar localtime, "\n"; # "Wed Apr 23 14:07:12 2025" ``` ## Edge cases - **No argument**: `localtime` with no argument uses [`time`](time) — 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. - **`$year` pitfall**: `$year + 1900` gives the full year. Writing `"19$year"` was a Y2K bug and is still wrong; write `1900 + $year`. - **`$mon` pitfall**: `$mon` is 0-based. `localtime` output feeding anything 1-based (including `POSIX::mktime`) does **not** need adjustment — `mktime` expects the same 0-based convention. External systems (databases, ISO-8601 strings) usually want `$mon + 1`. - **`$isdst` is advisory**, not directly comparable across zones. `1` means "the local zone currently applies its DST offset"; `0` means "standard time"; `-1` occasionally appears when the zone rules cannot decide (e.g. the hour that does not exist on a spring-forward day). - **`TZ` reload 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 — call `POSIX::tzset` after every change, or the old zone will keep being used. - **Scalar string is always English** and is **not** affected by `LC_TIME` or any other locale setting. For a localized string, go through `POSIX::strftime` with `LC_TIME` set to the desired locale. - **Thread safety**: on systems where the C `localtime(3)` call is not reentrant, concurrent threads mutating `TZ` can race. In practice pperl and modern glibc use the reentrant `localtime_r` internally, but `TZ` is still a process-wide global. - **Leap seconds**: `$sec` can legally be `60` on systems with leap second support. Most systems smear or ignore them and you will never see it; code that must not break on `60` handles it already. - **`%a` / `%b` width** under `POSIX::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`](gmtime) — same decomposition in UTC; does not consult `TZ` and is the right choice when you want a time zone–independent value - [`time`](time) — the epoch source that `localtime` most often receives as its argument - `POSIX::strftime` — format a `localtime` list into any string layout you need, locale-aware - `POSIX::mktime` — inverse direction: take a 9-element list back to an epoch value - `POSIX::tzset` — re-read `TZ` after changing it, mandatory if you want the change to take effect - [`$ENV{TZ}`](../perlvar) — the environment variable `localtime` reads to pick the local zone