V dnevniških datotekah, podatkovnih bazah in odgovorih API je namesto datuma pogosto dolgo število, na primer 1767225600. To je časovni žig Unix (angleško Unix timestamp ali epoch time). V tem opisu prikažemo, kaj pomeni, kako ga na strežniku Linux, na primer na KVM VPS, pretvoriš v berljiv datum in nazaj in na kaj paziti zaradi časovnih pasov in milisekund.
Za hitro pretvorbo posamezne vrednosti lahko uporabiš tudi naš pretvornik, ki teče v brskalniku; na strežniku isto opraviš s spodnjimi ukazi.
Pretvornik časovnih žigov Unix
Pretvorba časovnega žiga v datum
- Lokalni čas
- UTC
- ISO 8601 (UTC)
- ISO 8601 (lokalno)
- Glede na zdaj
- V ukazni vrstici
Pretvorba datuma v časovni žig
- Časovni žig Unix
- V milisekundah
- Lokalni čas
- UTC
- V ukazni vrstici
Pretvorba teče v tvojem brskalniku in ne pošilja nobenih podatkov.
Ukaze smo novembra 2026 preizkusili v sistemih AlmaLinux 10.2 (GNU coreutils 9.5, gawk 5.3) in Ubuntu 26.04 (uutils coreutils 0.10, gawk 5.3, mawk 1.3.4), različice za macOS pa v macOS 26.
Kaj je časovni žig Unix?
Časovni žig Unix je število sekund, ki so pretekle od 1. januarja 1970 00:00:00 UTC („epoch”). Nekaj pomembnih lastnosti:
- Nima časovnega pasu. Isto število pomeni isti trenutek v Ljubljani, New Yorku in Tokiu; časovni pas pride v poštev šele, ko ga pretvoriš v datum.
1767225600je na primer 1. januar 2026 00:00:00 UTC, kar je v Ljubljani 01:00:00 (CET). - Prestopnih sekund ne šteje. Po standardu POSIX ima vsak dan natanko 86 400 sekund, zato je med časovnim žigom in astronomskim časom nekaj sekund razlike, kar v praksi ni pomembno.
- Trenutki pred letom 1970 so negativni:
-1je 31. december 1969 23:59:59 UTC.
Kje ga srečaš? V izpisu journalctl -o short-unix, v revizijskem dnevniku (/var/log/audit/audit.log, npr. msg=audit(1794162987.503:641)), v stolpcih INT ali BIGINT podatkovnih baz, v API-jih JSON, v polju exp žetonov JWT in pri času spremembe datotek (stat -c %Y fajl). O branju dnevnikov beri v našem opisu Branje dnevniških datotek v Linuxu.
Sekunda, milisekunda ali mikrosekunda?
Veliko sistemov časovni žig ne hrani v sekundah, temveč v drobnejši enoti. Trenutno (do leta 2286) je iz števila števk mogoče prepoznati, za katero gre:
| Števke | Enota | Primer | Kje se pojavlja |
|---|---|---|---|
| 10 | sekunda | 1767225600 |
date +%s, PHP time(), MySQL UNIX_TIMESTAMP() |
| 13 | milisekunda (ms) | 1767225600123 |
JavaScript Date.now(), Java, veliko API-jev REST |
| 16 | mikrosekunda (µs) | 1767225600123456 |
nekatere oblike dnevnikov in podatkovne baze |
| 19 | nanosekunda (ns) | 1767225600123456789 |
date +%s%N, Go |
Najpogostejša napaka je, da program vrednost v milisekundah razume kot sekunde. date takrat ne javi napake, temveč izpiše zelo oddaljen datum:
date -d @1767225600123
# Thu Feb 25 01:02:03 AM CET 57971
Takrat vrednost deli s 1000 (ali izpusti zadnje tri števke) oziroma jo navedi kot decimalno:
date -d @$((1767225600123 / 1000))
date -d @1767225600.123 +'%F %T.%3N'
# 2026-01-01 01:00:00.123
Poizvedba po trenutnem času Unix
# V sekundah
date +%s
# V milisekundah oziroma nanosekundah
date +%s%3N
date +%s%N
# V Bash 5 tudi brez zunanjega ukaza (na sekundo oziroma mikrosekundo natančno)
echo $EPOCHSECONDS
echo $EPOCHREALTIME
Pretvorba časovnega žiga v datum z ukazom date
GNU date trenutek dobi s stikalom -d (--date); @ označuje, da gre za časovni žig Unix:
# V časovnem pasu strežnika
date -d @1767225600
# Thu Jan 1 01:00:00 AM CET 2026
# UTC-ben
date -u -d @1767225600
# Thu Jan 1 12:00:00 AM UTC 2026
# V drugem časovnem pasu (nastavitve strežnika ne spremeni)
TZ=America/New_York date -d @1767225600
# Wed Dec 31 07:00:00 PM EST 2025
# V obliki ISO 8601, z odmikom časovnega pasu
date -d @1767225600 --iso-8601=seconds
# 2026-01-01T01:00:00+01:00
# V obliki RFC 5322 (glava e-pošte)
date -d @1767225600 -R
# Thu, 01 Jan 2026 01:00:00 +0100
# V lastni obliki
date -d @1767225600 +'%Y-%m-%d %H:%M:%S'
# 2026-01-01 01:00:00
Jezik in obliko izpisa določa jezikovna nastavitev (locale). Na cloud image AlmaLinux 10 je privzet en_US.UTF-8, zato dobiš angleško, 12-urno obliko. Za drug jezik namesti jezikovni paket (spodnji primer je madžarski, sudo dnf install glibc-langpack-hu; za slovenščino glibc-langpack-sl in sl_SI.UTF-8) in nastavi spremenljivko LC_TIME:
LC_TIME=hu_HU.UTF-8 date -d @1767225600
# čet 1. jan. 2026 01:00:00 CET
V skriptih je dobro uporabljati lastno obliko (+'%Y-%m-%d %H:%M:%S' ali +%F %T), ker ni odvisna od jezikovne nastavitve.
Tudi vgrajeni ukaz Bash printf zna oblikovati časovni žig, brez zagona zunanjega programa, kar je v zankah hitreje:
printf '%(%F %T)T\n' 1767225600
# 2026-01-01 01:00:00
Pretvorba datuma v časovni žig
Oblika +%s izpiše časovni žig Unix podanega trenutka. Brez časovnega pasu date datum razume v časovnem pasu strežnika, zato lahko isti datum na drugem strežniku da drug časovni žig:
# V časovnem pasu strežnika (tu Europe/Ljubljana)
date -d '2026-11-08 14:30' +%s
# 1794144600
# Razumljeno kot UTC
date -u -d '2026-11-08 14:30' +%s
date -d '2026-11-08 14:30 UTC' +%s
# 1794148200
# Z odmikom časovnega pasu (ISO 8601)
date -d '2026-11-08T14:30:00+01:00' +%s
# 1794144600
# V določenem časovnem pasu
TZ=Europe/Ljubljana date -d '2026-11-08 14:30' +%s
date -d 'TZ="America/New_York" 2026-11-08 14:30' +%s
# 1794166200
# Le datum: 00:00 tega dne v časovnem pasu strežnika
date -d '2026-11-08' +%s
# 1794092400
date razume tudi relativne trenutke, kar je uporabno pri načrtovanih opravilih in izračunu rokov veljavnosti:
date -d 'now + 7 days' +%s
date -d 'tomorrow 00:00' +%s
date -d '+7 days'
Čas spremembe datoteke da stat kot časovni žig, stikalo -r ukaza GNU date pa kot datum:
stat -c %Y /etc/hostname
date -r /etc/hostname +%s
date -r /etc/hostname
Pretvorba časovnih žigov v dnevniških datotekah
Če je prvi stolpec datoteke časovni žig Unix, ga lahko s funkcijo strftime() ukaza awk pretvoriš po vrsticah. Vzorčna datoteka (esemenyek.log):
1767225600 login alice
1767229200 logout alice
1794144600 login bob
# Zamenjava prvega stolpca z berljivim datumom (v časovnem pasu strežnika)
awk '{ $1 = strftime("%Y-%m-%d %H:%M:%S", $1); print }' esemenyek.log
# 2026-01-01 01:00:00 login alice
# 2026-01-01 02:00:00 logout alice
# 2026-11-08 14:30:00 login bob
# V UTC: tretji parameter je 1
awk '{ print strftime("%F %T", $1, 1), $2, $3 }' esemenyek.log
# Pri časovnem žigu v milisekundah deli s 1000
awk '{ $1 = strftime("%F %T", $1 / 1000); print }' esemenyek-ms.log
strftime() ni del standarda POSIX awk, poznata pa ga GNU awk (gawk) in različica 1.3.4 mawk v Debianu/Ubuntuju: v preizkusu sta oba dala isto. V preizkusu je bil ukaz awk v AlmaLinux in Ubuntu 26.04 gawk. Če na starejšem sistemu vseeno ne bi deloval, uporabi zanko while read:
while read -r ts rest; do
echo "$(date -d @"$ts" '+%F %T') $rest"
done < esemenyek.log
To je pri velikih datotekah počasneje, ker za vsako vrstico zažene proces date; takrat je printf '%(%F %T)T' hitrejši.
Nekatera orodja časovne žige pretvorijo sama: journalctl privzeto kaže datum (-o short-unix ravno obratno, časovni žig), v revizijskem dnevniku pa ausearch -i vrednosti msg=audit(...) izpiše kot datum. O analizi dnevnikov spletnega strežnika smo pisali v zapisu Analiza dnevnikov spletnega strežnika.
Hitre ustreznice v drugih jezikih
PHP
php -r 'echo date("c", 1767225600), PHP_EOL;'
php -r 'echo time(), PHP_EOL;'
php -r 'echo strtotime("2026-11-08 14:30"), PHP_EOL;'
PHP ne uporablja časovnega pasu sistema, temveč nastavitve date.timezone, okoljsko spremenljivko TZ pa prezre. V AlmaLinux 10 je bil privzeti časovni pas PHP 8.3 v ukazni vrstici UTC, zato je prvi ukaz vrnil 2026-01-01T00:00:00+00:00, strtotime pa je, razumljen kot UTC, vrnil 1794148200. Časovni pas lahko nastaviš v datoteki php.ini ali za vsak ukaz posebej:
php -d date.timezone=Europe/Ljubljana -r 'echo date("c", 1767225600), PHP_EOL;'
# 2026-01-01T01:00:00+01:00
Python
python3 -c 'import time; print(int(time.time()))'
python3 -c 'import datetime as d; print(d.datetime.fromtimestamp(1767225600))'
python3 -c 'import datetime as d; print(d.datetime.fromtimestamp(1767225600, d.timezone.utc).isoformat())'
python3 -c 'import datetime as d; print(int(d.datetime(2026, 11, 8, 14, 30).timestamp()))'
fromtimestamp() brez časovnega pasu uporabi časovni pas sistema (2026-01-01 01:00:00), s parametrom d.timezone.utc pa UTC (2026-01-01T00:00:00+00:00).
MySQL in MariaDB
SELECT FROM_UNIXTIME(1767225600);
SELECT FROM_UNIXTIME(1767225600, '%Y.%m.%d %H:%i');
SELECT UNIX_TIMESTAMP('2026-11-08 14:30:00');
SELECT UNIX_TIMESTAMP();
Obe funkciji uporabljata časovni pas povezave (time_zone), ki je privzeto sistemski časovni pas strežnika (SYSTEM). Za UTC ga nastavi na začetku povezave: SET time_zone = '+00:00';. Poimenovani časovni pasovi (npr. 'Europe/Ljubljana') delujejo šele po nalaganju tabel časovnih pasov (mariadb-tzinfo-to-sql), sicer dobiš napako Unknown or incorrect time zone. MariaDB 10.11 za časovne žige po 19. januarju 2038 vrne NULL (glej spodaj). O namestitvi MariaDB beri v opisu Namestitev strežnika podatkovnih baz MariaDB.
JavaScript
Date.now(); // milisekunde
Math.floor(Date.now() / 1000); // sekunde
new Date(1767225600 * 1000).toISOString(); // "2026-01-01T00:00:00.000Z"
JavaScript Date računa v milisekundah, zato je treba časovni žig v sekundah pomnožiti s 1000, vrednost Date.now() pa deliti, preden jo predaš strežniškemu programu.
macOS in BSD: date -r
Ukaz date v sistemih macOS in BSD deluje drugače: namesto -d @... časovni žig Unix pričakuje stikalo -r, iz datuma pa časovni žig naredi s stikaloma -j -f:
# macOS / BSD
date -r 1767225600
date -u -r 1767225600 '+%Y-%m-%d %H:%M:%S'
date -j -f '%Y-%m-%d %H:%M:%S' '2026-11-08 14:30:00' +%s
V Linuxu (GNU date) -r izpiše čas spremembe datoteke, zato date -r 1767225600 tam vrne napako No such file or directory.
V Ubuntu 26.04 je ukaz date del uutils coreutils, napisanih v jeziku Rust. Ukazi GNU date iz tega opisa so v preizkusu dali enak rezultat; če vseeno opaziš razliko, je različica GNU na voljo tudi pod imenom gnudate.
Problem leta 2038
Stari sistemi časovni žig hranijo kot predznačeno 32-bitno celo število, katerega največja vrednost je 2147483647, torej 19. januar 2038 03:14:07 UTC. Sekundo pozneje se število prevrne in datum postane 13. december 1901.
64-bitni sistemi Linux in ukaz date niso več prizadeti (date -u -d @2147483648 brez težav izpiše 19. januar 2038 03:14:08), problem pa ostaja predvsem v starih, 32-bitnih programih in podatkovnih bazah:
- stolpci tipa
INT, v katerih hranijo časovne žige: namesto tega uporabiBIGINTaliDATETIME; - tip stolpca
TIMESTAMPv MySQL in MariaDB, ki hrani datum do leta 2038; v preizkusu je tudi klicFROM_UNIXTIME(2147483648)v MariaDB 10.11 vrnilNULL. Po dokumentaciji v MariaDB od 11.5 na 64-bitnih sistemihTIMESTAMPin te funkcije delujejo do leta 2106; v MySQL od 8.0.28FROM_UNIXTIME()inUNIX_TIMESTAMP()do leta 3001, tip stolpcaTIMESTAMPpa še vedno le do leta 2038.
Časovni pas in točen čas na strežniku
Pretvorba da pravilen rezultat le, če je ura strežnika točna, njegov časovni pas pa pričakovan. O preverjanju in nastavitvi govori naš opis Nastavitev imena gostitelja, časovnega pasu in sinhronizacije časa. Tudi načrtovana opravila tečejo po lokalnem času strežnika, o tem beri v članku Sintaksa crontab in načrtovana opravila v Linuxu.
