MySQL aktuální časové razítko: NOW(), CURRENT_TIMESTAMP, SYSDATE(), UTC a osvědčené postupy

目次

1. Nejkratší SQL pro získání aktuálního data/času v MySQL

Pokud chcete získat aktuální datum/čas v MySQL, první funkce, které si musíte zapamatovat, jsou NOW() a CURRENT_TIMESTAMP. Níže jsou nejkratší SQL příklady podle použití.

1.1 Získání aktuálního data/času (základní)

SELECT NOW();

or

SELECT CURRENT_TIMESTAMP;
  • Obě vrací aktuální datum/čas (YYYY-MM-DD HH:MM:SS).
  • V rámci jednoho dotazu je čas pevně nastaven na „čas zahájení dotazu“.

Příklady použití

  • Protokolování
  • Získání časové značky vytvoření záznamu
  • Získání referenčního času

Častá chyba

  • Časová zóna aplikace a databáze se liší a dochází k „posunu času“. → Zkontrolujte pomocí SELECT @@session.time_zone;

1.2 Získání dnešního data pouze

SELECT CURDATE();
  • Návratový formát: YYYY-MM-DD
  • Typ je DATE (pouze datum, ne datetime)

Příklady použití

  • Vyhledávání „dnešních dat“
  • Denní agregace

Poznámky

  • Na rozdíl od NOW() neobsahuje čas.
  • Pokud potřebujete čas pro rozsahové dotazy, použijte NOW().

1.3 Získání aktuálního času pouze

SELECT CURTIME();
  • Návratový formát: HH:MM:SS
  • Typ je TIME (pouze čas)

Příklady použití

  • Zobrazení času provedení dávky
  • Výpis pouze časové části v protokolech

Častý úskalí

  • Protože neobsahuje datum, nemůžete jej použít pro porovnání datetime.

1.4 Získání aktuálního času v UTC (důležité)

SELECT UTC_TIMESTAMP();
  • Vrací UTC bez ohledu na časovou zónu serveru.
  • Doporučeno pro globální služby.

Základní politika v reálných projektech

  • Ukládat v UTC
  • Při zobrazování převést na místní čas

Poznámky

  • Pokud aplikace již převádí na UTC, dejte pozor na dvojí konverzi.

1.5 Získání milisekund / mikrosekund

SELECT NOW(3);  -- milliseconds (3 digits after the decimal point)
SELECT NOW(6);  -- microseconds (6 digits after the decimal point)
  • K dispozici v MySQL 5.6.4 a novějších.
  • Používá se pro vysoce přesné protokoly a auditování transakcí.

Časté nedorozumění

  • NOW() samotné nedokáže vrátit zlomkové sekundy.
  • Váš sloupec musí také specifikovat přesnost, např. DATETIME(6).

1.6 Nejlepší funkce podle použití (začněte zde, pokud si nejste jisti)

Use caseRecommended function
General current datetimeNOW()
Table default valueCURRENT_TIMESTAMP
Date onlyCURDATE()
Time onlyCURTIME()
Unified UTC managementUTC_TIMESTAMP()
High-precision logsNOW(6)

Klíčové body, které lidé často přehlížejí

  • NOW() a CURRENT_TIMESTAMP jsou v podstatě ekvivalentní (stejná hodnota)
  • V rámci jednoho dotazu je čas pevně nastaven
  • Zobrazená hodnota se mění podle nastavení časové zóny
  • Pro mikrosekundy musí definice sloupce specifikovat přesnost

2. Rozdíly mezi NOW() / CURRENT_TIMESTAMP / SYSDATE()

Existuje několik funkcí pro získání aktuálního času, ale nejzáhadnější částí je rozdíl mezi NOW(), CURRENT_TIMESTAMP a SYSDATE().
Pokud tomu nerozumíte správně, můžete v protokolech a zpracování transakcí narazit na neočekávané chování.

2.1 NOW() a CURRENT_TIMESTAMP jsou v podstatě ekvivalentní

SELECT NOW(), CURRENT_TIMESTAMP;
  • Obě vrací aktuální datetime (hodnota DATETIME).
  • V rámci jednoho dotazu je čas pevně nastaven na „čas zahájení dotazu“.
  • CURRENT_TIMESTAMP lze také použít se syntaxí volání funkce:
    SELECT CURRENT_TIMESTAMP();
    

Jak vybírat v reálných projektech

Use caseRecommended
Simple retrievalNOW()
Table DEFAULT / ON UPDATECURRENT_TIMESTAMP

Důležité body

  • Význam získané hodnoty je stejný.
  • Hlavní rozdíl je v syntaxi/použití (např. povoleno v DEFAULT).
  • Nejedná se o rozdíl typu (snadno se mylně interpretuje).

2.2 SYSDATE() vrací čas v „čase vyhodnocení“

SYSDATE() vypadá podobně jako NOW(), ale čas, kdy je hodnota pevně stanovena, je jiný.

SELECT NOW(), SLEEP(2), NOW();

Výsledek (příklad):

2025-02-23 14:00:00
2025-02-23 14:00:00
SELECT SYSDATE(), SLEEP(2), SYSDATE();

Výsledek (příklad):

2025-02-23 14:00:00
2025-02-23 14:00:02

Základní rozdíl

FunctionWhen the time is fixed
NOW()Query start time
SYSDATE()Evaluation time

2.3 Poznámky k transakcím a replikaci

Protože NOW() je pevně nastaveno při zahájení dotazu, je
bezpečnější, když potřebujete konzistentní referenční čas uvnitř transakce.

Na druhou stranu, protože SYSDATE() závisí na čase provádění, může ovlivnit reprodukovatelnost v:

  • Replikace
  • Dávkové úlohy
  • Hromadné zpracování logů

Obecné pravidlo

  • Chcete pevný referenční čas → NOW()
  • Potřebujete přesný okamžik pokaždé → SYSDATE() (omezené použití)

2.4 Poznámka: CURRENT_DATE / CURRENT_TIME / LOCALTIME

MySQL také podporuje:

SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT LOCALTIME;
  • CURRENT_DATE → stejné jako CURDATE()
  • CURRENT_TIME → stejné jako CURTIME()
  • LOCALTIME → stejné jako NOW()

Časté zmatení

  • Jedná se převážně o „kosmetické rozdíly“; funkčně se téměř neliší.
  • Pro bezpečnost upřednostněte čitelnost a standardizujte v rámci projektu.

Klíčové poznatky z této sekce

  • NOW() a CURRENT_TIMESTAMP v podstatě znamenají totéž.
  • SYSDATE() se chová odlišně, protože je založeno na čase vyhodnocení.
  • Pro pevné referenční časy použijte jako výchozí NOW().
  • Použijte CURRENT_TIMESTAMP pro DEFAULT a ON UPDATE.

3. Změna formátu zobrazení aktuálního data/času

Aktuální čas získaný pomocí NOW() se ve výchozím nastavení zobrazuje jako YYYY-MM-DD HH:MM:SS. V praxi často potřebujete například:

  • Zobrazit pouze datum
  • Použít YYYY/MM/DD
  • Použít lokalizovaný formát (např. 23. února 2025)
  • Zobrazit milisekundy

K tomu použijte DATE_FORMAT() (převod datetime na libovolný řetězcový formát).

3.1 Základní syntaxe DATE_FORMAT()

DATE_FORMAT(datetime, 'format_string')

Příklad: Převést aktuální čas na YYYY/MM/DD HH:MM

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d %H:%i');

Příklad výstupu:

2025/02/23 14:35

Běžné specifikátory formátu

SpecifierMeaningExample
%Y4-digit year2025
%m2-digit month02
%d2-digit day23
%HHour (24-hour)14
%iMinutes35
%sSeconds50
%fMicroseconds123456

Poznámky

  • Některé specifikátory se liší mezi velkými a malými písmeny.
  • %h je 12‑hodinový čas, %H je 24‑hodinový čas.

3.2 Běžné příklady formátů (často v praxi)

1. Oddělené lomítky

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d');

2. Lokalizované (anglicky)

SELECT DATE_FORMAT(NOW(), '%b %d, %Y');

3. Bez sekund

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');

Častý úskalí

  • Protože vrací řetězec, nemůžete jej použít pro číselné výpočty.
  • Pro porovnávání a vyhledávání byste měli použít původní typ DATETIME.

3.3 Extrahovat pouze část data nebo času

Můžete také získat části při zachování typu (namísto formátování na řetězec).

SELECT DATE(NOW());   -- date only (DATE type)
SELECT TIME(NOW());   -- time only (TIME type)
SELECT YEAR(NOW());   -- year only
SELECT MONTH(NOW());  -- month only
SELECT DAY(NOW());    -- day only

Doporučené použití

GoalRecommended
Formatting for displayDATE_FORMAT
Calculation / comparisonDATE() / TIME()

3.4 Zobrazení s mikrosekundami

Když potřebujete logy s vysokou přesností:

SELECT NOW(6);

S formátováním:

SELECT DATE_FORMAT(NOW(6), '%Y-%m-%d %H:%i:%s.%f');

Důležité poznámky

  • Váš sloupec musí být DATETIME(6) nebo TIMESTAMP(6), jinak se přesnost neuloží.
  • Není k dispozici v MySQL verzích starších než 5.6.4 (závisí na prostředí).

Časté chyby

  • Použití DATE_FORMAT() ve WHERE klauzuli zabraňuje využití indexů. wp:list /wp:list

    • Špatný příklad: WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-23'
    • Doporučeno: WHERE created_at >= '2025-02-23 00:00:00' AND created_at < '2025-02-24 00:00:00'
    • Ukládání přímo řetězce ve formátu pro zobrazení (snižuje výkon vyhledávání)

Klíčové poznatky z této sekce

  • Použijte DATE_FORMAT() ke změně formátů zobrazení.
  • Pro výpočty/porovnání zachovejte původní typ.
  • Pokud potřebujete mikrosekundy, uveďte přesnost v definici sloupce.
  • Používání funkcí ve WHERE klauzulích může způsobit problémy s výkonem.

4. Výpočty datum/čas pomocí aktuálního času

In MySQL je běžné počítat věci jako „N hodin později“, „N dní zpět“ nebo „posledních N dní“ na základě aktuálního času.
Nejčastějším reálným případem je „získat data z posledních 24 hodin.“

Základem aritmetiky s datumy a časy je INTERVAL (syntaxe pro přidávání/odebírání časových jednotek).

4.1 Přidávání/odebírání pomocí INTERVAL

Získat 1 hodinu později

SELECT NOW() + INTERVAL 1 HOUR;

Získat 3 dny zpět

SELECT NOW() - INTERVAL 3 DAY;

Získat 1 měsíc později

SELECT NOW() + INTERVAL 1 MONTH;

Běžné jednotky

UnitMeaning
SECONDSeconds
MINUTEMinutes
HOURHours
DAYDays
WEEKWeeks
MONTHMonths
YEARYears

Časté chyby

  • DAY v INTERVAL 1 DAY funguje i v malých písmenech, ale měli byste to ve vašem týmu standardizovat.
  • Výpočty konce měsíce mohou být odlišné od očekávání, protože počet dní se liší (např. 31. ledna + 1 měsíc).

4.2 Získat data z posledních 24 hodin (nejčastější vzor)

SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL 1 DAY;

Význam

  • Cílí na „od právě teď zpět 24 hodin.“

Poznámky

  • Pokud použijete CURDATE(), základní hodnota se stane „dnes v 00:00“, což mění význam.

Příklad (dnešní data):

SELECT *
FROM users
WHERE created_at >= CURDATE();

Pochopení rozdílu je klíčové

ExpressionMeaning
NOW() - INTERVAL 1 DAYPast 24 hours
CURDATE()Since today 00:00

4.3 Získat rozdíly ve dnech pomocí DATEDIFF()

SELECT DATEDIFF('2025-03-01', '2025-02-23');

Výsledek:

6
  • Jednotka je „dny“
  • Časová část je ignorována

Poznámky

  • Znak se mění v závislosti na pořadí argumentů.
  • Nemůžete vypočítat rozdíly v hodinách/minutách/vteřinách.

4.4 Použít TIMESTAMPDIFF() pro hodiny/minuty/vteřiny

SELECT TIMESTAMPDIFF(HOUR,
                     '2025-02-23 12:00:00',
                     '2025-02-23 18:30:00');

Výsledek:

6

Minuty

SELECT TIMESTAMPDIFF(MINUTE,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:30:00');

Sekundy

SELECT TIMESTAMPDIFF(SECOND,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:00:45');

Případy použití

  • Výpočty trvání relace
  • Kontroly expirace
  • Rozhodování o timeoutu

4.5 Získat začátek měsíce / konec měsíce (běžná reálná past)

Získat první den tohoto měsíce:

SELECT DATE_FORMAT(NOW(), '%Y-%m-01');

První den následujícího měsíce:

SELECT DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');

Poznámky

  • Konec měsíce není pevný datum.
  • Pro dotazy v rozsahu je bezpečné použít „>= start AND < první den následujícího měsíce“.

Shrnutí častých chyb

  • Používání BETWEEN s hodnotami jen datum a zapomínání na čas
  • Vypínání indexů použitím DATE(created_at) ve WHERE podmínkách
  • Uvíznutí v problému „31. den“ při výpočtech měsíce
  • Nesprávné pochopení rozdílu mezi NOW() a CURDATE()

Hlavní poznatky z této sekce

  • INTERVAL je základem aritmetiky s datumy a časy.
  • Posledních 24 hodin = NOW() - INTERVAL 1 DAY .
  • Dny = DATEDIFF() ; menší jednotky = TIMESTAMPDIFF() .
  • Buďte opatrní s koncovými podmínkami při výpočtech založených na měsíci.

5. Pro dotazy v rozsahu je to bezpečnější než BETWEEN

Při vyhledávání v datech v MySQL mnoho začátečníků používá BETWEEN. Nicméně, často to vede k nechtěným výsledkům, pokud špatně zacházíte s časovými hranicemi, takže v praxi se doporučuje bezpečnější vzor.

5.1 Základy BETWEEN a úskalí

Běžný dotaz

SELECT *
FROM orders
WHERE order_date BETWEEN '2025-02-01' AND '2025-02-10';

Vypadá to v pořádku, ale interně je to ekvivalentní k:

WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;= '2025-02-10 00:00:00'

Takže nezahrnuje data po 00:00 dne 10. února.


5.2 Bezpečnější vzor (doporučeno)

Doporučený vzor

SELECT *
FROM orders
WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;  '2025-02-11 00:00:00';

Klíčové body

  • Specifikujte koncový limit jako „méně než další den v 00:00“
  • Bezpečnější než <= 23:59:59 (podporuje mikrosekundy)

5.3 Správný způsob, jak získat dnešní data

Špatný příklad:

WHERE DATE(created_at) = CURDATE();

Problémy:

  • Použití funkce na sloupec zneplatňuje indexy
  • Může způsobit vážné zpomalení u velkých tabulek

Doporučeno:

WHERE created_at &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

To zajišťuje:

  • Indexy mohou být použity
  • Rychlé vyhledávání
  • Žádné problémy s hranicemi

5.4 Bezpečné vzory pro posledních 7 / 30 dní

Posledních 7 dní

WHERE created_at &gt;= NOW() - INTERVAL 7 DAY;

Posledních 30 dní

WHERE created_at &gt;= NOW() - INTERVAL 30 DAY;

Poznámky

  • CURDATE() - INTERVAL 7 DAY je založeno na „dnes 00:00“
  • NOW() - INTERVAL 7 DAY je založeno na „aktuálním čase“
  • Zvolte podle požadavků

5.5 Klíčové pravidlo pro udržení efektivity indexů

Špatně:

WHERE DATE(created_at) = '2025-02-23';

Správně:

WHERE created_at &gt;= '2025-02-23 00:00:00'
  AND created_at &lt;  '2025-02-24 00:00:00';

Proč:

  • Indexy fungují na „samotném sloupci“
  • Použití funkce zabraňuje využití indexu (plné skenování)

Souhrn častých chyb

  • Zapomenutí zahrnout čas v koncovém limitu u BETWEEN
  • Chybějící mikrosekundy při použití 23:59:59
  • Použití DATE() ve WHERE podmínkách a zpomalení dotazů
  • Nejasnost mezi „now“ a „today 00:00“

Hlavní závěry z této sekce

  • Rozsahové dotazy jsou nejbezpečnější s >= start AND < end.
  • BETWEEN vyžaduje opatrné zacházení s hranicemi.
  • Aby byly indexy efektivní, neobalujte sloupce funkcemi.
  • Jasně si vyberte mezi logikou založenou na NOW() a na CURDATE().

6. DEFAULT CURRENT_TIMESTAMP a ON UPDATE (základy návrhu tabulek)

V návrhu databáze je běžné automaticky spravovat created_at a updated_at.
V MySQL CURRENT_TIMESTAMP umožňuje nastavit aktuální čas automaticky při vložení i aktualizaci.

6.1 Automatické nastavení created_at (DEFAULT CURRENT_TIMESTAMP)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Chování:

INSERT INTO users (name) VALUES ('Alice');

→ Aktuální čas je automaticky vložen do created_at.

Klíčové body

  • CURRENT_TIMESTAMP může být použito v DEFAULT.
  • NOW() nelze použít přímo v DEFAULT.

Častá chyba

created_at DATETIME DEFAULT NOW();  -- error

Důvod:

  • V MySQL obecně nelze nastavit funkci jako DEFAULT (výjimkou je CURRENT_TIMESTAMP).

6.2 Automatická aktualizace updated_at (ON UPDATE)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

Chování:

UPDATE users SET name = 'Bob' WHERE id = 1;

updated_at je automaticky aktualizováno na aktuální čas.

Případy použití

  • Sledování posledního přihlášení
  • Historie aktualizací
  • Auditní logy

6.3 DATETIME vs TIMESTAMP (důležité)

TypeRangeTime zone impact
DATETIMEYear 1000 to 9999No
TIMESTAMP1970 to 2038Yes

Základní rozdíl

  • TIMESTAMP je uložen interně v UTC a při zobrazení je převeden na časové pásmo relace.
  • DATETIME ukládá doslovnou hodnotu (bez konverze).

Pokyny

CaseRecommended type
Log managementTIMESTAMP
Future dates (after 2038)DATETIME
Fixed values not requiring TZ conversionDATETIME

6.4 CURRENT_TIMESTAMP lze také použít s DATETIME

V MySQL 5.6 a novějších můžete také specifikovat CURRENT_TIMESTAMP jako DEFAULT a ON UPDATE pro sloupce typu DATETIME.

created_at DATETIME DEFAULT CURRENT_TIMESTAMP

Poznámky

  • Starší verze MySQL mají omezení (závislé na prostředí).
  • Pokud potřebujete přesnost:
    DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6)
    

6.5 Pokud chcete použít NOW(): alternativa (trigger)

CREATE TRIGGER set_created_at
BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.created_at = NOW();

Případy použití

  • Složitá logika počátečních hodnot
  • Podmíněné přiřazení časové značky

Poznámky

  • Spouštěče jsou těžko debugovatelné.
  • Vyhněte se jim, pokud nejsou nezbytné.

Běžné chyby v designu

  • Přidání ON UPDATE k oběma created_at a updated_at
  • Zmatek chování DATETIME a TIMESTAMP
  • Odkládání rozhodnutí o časových pásmech

Klíčové závěry z této sekce

  • Používejte CURRENT_TIMESTAMP pro DEFAULT.
  • Používejte ON UPDATE CURRENT_TIMESTAMP pro sledování aktualizací.
  • Vyberte typy na základě chování časových pásem a problému s rokem 2038.
  • Pokud potřebujete přesnost, nezapomeňte na (6) .

7. Design časových pásem (ukládat v UTC, zobrazovat v místním čase)

Při práci s aktuálním časem špatný design časových pásem způsobuje posun času a dvojitou konverzi.
V praxi je nejbezpečnější výchozí nastavení „ukládat v UTC, konvertovat do místního času pro zobrazení.“

MySQL timezone architecture storing timestamps in UTC and converting to local time (JST)

Obrázek: Základní architektura pro ukládání UTC v MySQL a zobrazení místního času

7.1 Kontrola aktuálního časového pásma

Nejprve zkontrolujte, v jakém časovém pásmu běží MySQL.

SELECT @@global.time_zone, @@session.time_zone;
  • @@global.time_zone → nastavení platné pro celý server
  • @@session.time_zone → nastavení aktuálního připojení/sedání
  • Pokud zobrazuje SYSTEM , závisí na nastavení OS

Běžné problémy

  • Produkční a vývojové servery mají různá OS časová pásma
  • Aplikace konvertuje do UTC a databáze konvertuje znovu (dvojitá konverze)

7.2 Změna časového pásma pro sedání

SET time_zone = 'Asia/Tokyo';

nebo sjednotit do UTC:

SET time_zone = '+00:00';

Důležité body

  • Vrátí se zpět při uzavření připojení
  • Pokud používáte pooling připojení, zkontrolujte nastavení aplikace

7.3 Proč ukládat v UTC (princip ze skutečného světa)

Doporučená politika

  1. Ukládat data v UTC
  2. Konvertovat do časového pásma uživatele při zobrazení

Důvody:

  • Snadnější podpora internacionalizace
  • Vyhnout se problémům s letním časem (DST)
  • Minimalizovat dopad při přesunu serverů

Získat UTC:

SELECT UTC_TIMESTAMP();

7.4 Konverze časových pásem pomocí CONVERT_TZ()

Příklad: UTC → JST

SELECT CONVERT_TZ('2025-02-23 05:35:00', '+00:00', '+09:00');

Použití názvů časových pásem:

SELECT CONVERT_TZ('2025-02-23 05:35:00', 'UTC', 'Asia/Tokyo');

Příklad ze skutečného světa

SELECT CONVERT_TZ(created_at, 'UTC', 'Asia/Tokyo')
FROM users;

7.5 Proč CONVERT_TZ() vrací NULL

Pokud vrací NULL, běžné příčiny zahrnují:

  • Tabulky časových pásem MySQL nejsou načteny
  • Zadaný název časového pásma neexistuje

Příklad načtení na Linuxu:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

Poznámky

  • V produkci ověřte oprávnění a zda je vyžadován restart
  • V Dockeru může zoneinfo chybět v závislosti na imagi

7.6 Změna časového pásma pro celý server

Konfigurační soubor (my.cnf / my.ini):

[mysqld]
default_time_zone = '+00:00'

Ověření po restartu:

SELECT @@global.time_zone;

Důležité

  • Pro změny v produkci ověřte rozsah dopadu
  • Buďte opatrní s existujícími daty (někdy se změní pouze zobrazení)

Běžné chyby

  • Ukládání místního času místo UTC a pozdější přidání podpory internacionalizace
  • Dvojitá konverze mezi aplikací a databází
  • Design s DATETIME bez zohlednění časových pásem
  • Různá nastavení TZ mezi testováním a produkcí

Klíčové závěry z této sekce

  • Ukládat v UTC a konvertovat při zobrazení.
  • Používejte UTC_TIMESTAMP() .
  • Při používání CONVERT_TZ() ověřte tabulky TZ.
  • Vždy zohledněte rozdíly v prostředích pro časová pásma.

8. Praktické příklady, které můžete použít přímo

Zde jsou konkrétní příklady SQL ukazující jak používat aktuální čas MySQL v reálném vývoji/provozu.
Jsou napsány tak, abyste je mohli přímo kopírovat a vkládat.

8.1 Automatické vložení aktuálního času do logů

Vytvoření tabulky

CREATE TABLE system_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    level VARCHAR(50),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Vložení logu

INSERT INTO system_logs (level, message)
VALUES ('ERROR', 'Failed to connect to the DB');

Klíčové body

  • created_at je vloženo automaticky
  • Není nutné předávat časové razítko z aplikace
  • Základní návrh pro auditování a vyšetřování incidentů

Časté chyby

  • Správa času jak v aplikaci, tak v DB
  • Nesoulad času kvůli nejednotným časovým pásmům

8.2 Aktualizace času posledního přihlášení

Návrh tabulky

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255),
    last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

Aktualizace při přihlášení

UPDATE users
SET last_login = NOW()
WHERE id = 1;

Poznámky

  • ON UPDATE se spustí pouze když se sloupec změní
  • Některé UPDATE příkazy nemusí změnit hodnotu a tedy neaktualizují

8.3 Fixace referenčního času v dávkových úlohách

Pro dlouho běžící procesy je bezpečnější fixovat referenční čas.

SET @base_time = NOW();

SELECT *
FROM orders
WHERE created_at &gt;= @base_time - INTERVAL 1 DAY;

Proč

  • Čas se během procesu neposouvá
  • Konzistence je zachována

8.4 Agregace pro dnes / včera / posledních 7 dní

Prodeje za dnešek

SELECT SUM(amount)
FROM orders
WHERE created_at &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

Prodeje za včerejšek

SELECT SUM(amount)
FROM orders
WHERE created_at &gt;= CURDATE() - INTERVAL 1 DAY
  AND created_at &lt;  CURDATE();

Posledních 7 dní

SELECT COUNT(*)
FROM users
WHERE created_at &gt;= NOW() - INTERVAL 7 DAY;

Důležité

  • Nevkládejte funkce na sloupce ve WHERE podmínkách
  • Pište podmínky, které umožní využití indexů

8.5 Kontroly expirace (sessiony/tokeny)

SELECT *
FROM sessions
WHERE expires_at &gt; NOW();

Smazat expirující řádky

DELETE FROM sessions
WHERE expires_at &lt;= NOW();

Časté chyby

  • Používání CURDATE() a ignorování času
  • Ukládání v UTC, ale porovnávání s lokálním NOW()

8.6 Získat řádky expirující během N hodin

SELECT *
FROM coupons
WHERE expires_at &lt;= NOW() + INTERVAL 1 HOUR;

Případy použití:

  • Upozornění na expiraci
  • Notifikace o expiraci

Co byste si vždy měli pamatovat

  • Buďte explicitní, zda je vaším výchozím bodem „now“ nebo „today 00:00“
  • Pište predikáty, které udržují efektivitu indexů
  • Rozhodněte o návrhu časových pásem předem
  • Nemíchejte NOW() a UTC_TIMESTAMP() bez jasné politiky

Klíčové poznatky z této sekce

  • Pro logy/audity/sledování aktualizací použijte CURRENT_TIMESTAMP
  • Pro agregaci použijte bezpečný vzor >= AND <
  • Pro správu sessionů porovnávejte s NOW()
  • Fixujte výchozí čas, aby byl proces konzistentní

9. Často kladené otázky (FAQ)

Zde jsou běžné otázky ohledně aktuálního času v MySQL, zejména úskalí, která se objevují v praxi.

9.1 Jaký je rozdíl mezi NOW() a CURRENT_TIMESTAMP?

Závěr: význam vrácené hodnoty je stejný.

SELECT NOW(), CURRENT_TIMESTAMP;

Obě vrací aktuální datum a čas.

Hlavní rozdíl je v syntaktickém použití

  • CURRENT_TIMESTAMP lze použít v DEFAULT a ON UPDATE
  • NOW() nelze použít přímo v DEFAULT

Poznámky

  • Nejedná se o rozdíl typu
  • Můžete specifikovat přesnost pomocí argumentů jako (6)

9.2 Měli byste použít SYSDATE()?

SYSDATE() vrací čas v „čase vyhodnocení“.

SELECT SYSDATE(), SLEEP(2), SYSDATE();

Hodnota se může změnit i v rámci jedné dotazu.

Kdy jej použít

  • Když potřebujete zaznamenat přesný reálný časový okamžik

Kdy se mu vyhnout

  • Replikace
  • Zpracování transakcí, kde je důležitá konzistence

Ve většině případů je použití NOW() dostačující.

9.3 Proč je čas posunutý?

Hlavní příčiny:

  1. Nastavení časové zóny serveru
  2. Nastavení časové zóny relace
  3. Dvojitá konverze s aplikací
  4. Automatické chování konverze typu TIMESTAMP

Zkontrolujte s:

SELECT @@global.time_zone, @@session.time_zone;

Opatření

  • Ukládat v UTC jako výchozí
  • Konvertovat pouze při zobrazení
  • Sjednotit politiku mezi aplikací a DB

9.4 CONVERT_TZ() vrací NULL

Příčiny:

  • Časové zóny tabulky nejsou načteny
  • Nesprávný název časové zóny

Oprava:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

Buďte zvláště opatrní v prostředích Docker.

9.5 Posuny rozsahu s BETWEEN

Špatně:

WHERE created_at BETWEEN '2025-02-01' AND '2025-02-10';

Bezpečně:

WHERE created_at &gt;= '2025-02-01 00:00:00'
  AND created_at &lt;  '2025-02-11 00:00:00';

Důvody:

  • Problém s časem koncové hranice
  • Únik mikrosekund
  • Efektivita indexu

9.6 Jak vybrat mezi DATETIME a TIMESTAMP?

  • Mezinárodní podpora / správa UTC → TIMESTAMP
  • Po roce 2038 nebo pevné datetimes → DATETIME

Rozhodněte o tom během návrhu.

9.7 Mikrosekundy nejsou ukládány

Příčina:

  • Žádná přesnost není specifikována v definici sloupce

Oprava:

created_at DATETIME(6)

Klíčové závěry z této sekce

  • Začněte s NOW() a CURRENT_TIMESTAMP
  • Pro dotazy rozsahu použijte >= AND <
  • Uložení v UTC je nejbezpečnější výchozí nastavení
  • Nezapomeňte na výběr typu a přesnost

10. Shrnutí

Tento článek organizuje praktické způsoby získávání, formátování, výpočtu a správy aktuálního času v MySQL.
Nakonec zde jsou minimální esenciály, které byste měli znát pro bezpečnost.

10.1 Získání aktuálního času (základy)

  • Obecné získání → NOW()
  • DEFAULT tabulky / sledování aktualizací → CURRENT_TIMESTAMP
  • Pouze datum → CURDATE()
  • Pouze čas → CURTIME()
  • UTC → UTC_TIMESTAMP()
  • Vysoká přesnost → NOW(6)

Pravidla palce

  • Pokud si nejste jisti, použití NOW() je většinou v pořádku.
  • Pro návrh schématu použijte CURRENT_TIMESTAMP .

10.2 Dotazy rozsahu: „>= AND <“ je zlaté pravidlo

Bezpečný vzor:

WHERE created_at &gt;= 'START'
  AND created_at &lt;  'END'

Proč:

  • Zabraňuje ztrátě řádků na koncové hranici
  • Funguje s mikrosekundami
  • Udržuje indexy použitelnými

Špatný příklad

WHERE DATE(created_at) = CURDATE();

Neobalujte sloupec do funkce.

10.3 Základy aritmetiky datetime

  • Přidání/odebrání → INTERVAL
  • Rozdíly dnů → DATEDIFF()
  • Rozdíly času → TIMESTAMPDIFF()

Vždy mějte na paměti, zda je vaším základem „nyní“ nebo „dnes 00:00“.

10.4 Principy návrhu časových zón

  • Ukládat v UTC
  • Konvertovat při zobrazení
  • Sjednotit politiku mezi aplikací a DB

Zkontrolujte s:

SELECT @@global.time_zone, @@session.time_zone;

10.5 Nejlepší postupy návrhu tabulek

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
           ON UPDATE CURRENT_TIMESTAMP
  • Standardní vybavení pro auditování/logování/sledování aktualizací
  • Pokud potřebujete přesnost, specifikujte (6)

4 nejdůležitější body z reálného světa

  1. Nezapomeňte na rozdíl mezi NOW() a CURRENT_TIMESTAMP
  2. Pro dotazy rozsahu použijte >= AND <
  3. Ukládat v UTC jako výchozí
  4. Rozhodněte o typech (DATETIME vs TIMESTAMP) během návrhu

Zpracování aktuálního času v MySQL je základní pro logování, agregaci prodejů, správu autentizace/sedání, dávkové úlohy a další.
Pokud budete dodržovat principy v tomto článku, vyhnete se mnoha běžným problémům, jako je posun času, chyby na hranicích a zhoršení výkonu.