Ce face NOW(), INTERVAL și date_trunc()
În PostgreSQL este o bună practică universală să folosești tipul timestamptz (timestamp with time zone) în loc de timestamp simplu. PostgreSQL stochează intern toate valorile timestamptz în UTC (pe 8 octeți) și le convertește automat la fusul orar al sesiunii curente la afișare.
Funcția NOW() (echivalentă cu CURRENT_TIMESTAMP și transaction_timestamp()) returnează momentul de început al tranzacției curente, tipul INTERVAL permite adunarea și scăderea intuitivă a perioadelor de timp (ex: INTERVAL '2 hours 30 minutes'), iar date_trunc(unitate, timestamp) trunchiază o dată la începutul orei, zilei, săptămânii, lunii sau anului — fiind esențială pentru grupările cronologice.
Clauze, operatori și argumente
| Clauză / Operator | Descriere |
|---|---|
NOW() / CURRENT_TIMESTAMP |
Returnează data și ora (cu fus orar) de la începutul tranzacției curente. |
clock_timestamp() |
Returnează data și ora reală a ceasului sistemului în momentul exact al evaluării (se schimbă și în cadrul aceleiași interogări). |
INTERVAL 'n unit' |
Reprezintă o durată de timp (ex: '1 year 2 months', '14 days', '45 minutes'). |
date_trunc('unitate', ts) |
Resetează câmpurile mai mici decât unitatea specificată (hour, day, week, month, quarter, year). |
AGE(ts_final, ts_start) |
Calculează diferența simbolică (în ani, luni și zile) dintre două timestamp-uri sub formă de interval. |
Exemple
Exemplul 1: Gruparea vânzărilor pe săptămâni calendaristice cu date_trunc() și filtrare cu INTERVAL
Selectăm comenzile din ultimele 30 de zile și le agregăm pe săptămâna calendaristică (începând de luni).
SELECT date_trunc('week', plasata_la)::date AS inceput_saptamana,
COUNT(*) AS nr_comenzi,
SUM(total_lei) AS total_saptamana
FROM comenzi
WHERE plasata_la >= NOW() - INTERVAL '30 days'
GROUP BY inceput_saptamana
ORDER BY inceput_saptamana DESC;
Rezultat interogare
inceput_saptamana | nr_comenzi | total_saptamana
-------------------+------------+-----------------
2025-03-17 | 19 | 9420.00
2025-03-10 | 34 | 16850.50
2025-03-03 | 28 | 12310.00
(3 rows)
Exemplul 2: Calcularea datelor de expirare și a vechimii contului cu INTERVAL și AGE()
Calculăm când expiră un abonament de 1 an și 15 zile bonus, precum și vechimea exactă a unui client.
SELECT id,
creat_la::date AS data_inscrierii,
(creat_la + INTERVAL '1 year 15 days')::date AS expira_la,
AGE(NOW(), creat_la) AS vechime_cont
FROM clienti
WHERE id = 101;
Rezultat interogare
id | data_inscrierii | expira_la | vechime_cont
-----+-----------------+------------+---------------------------
101 | 2023-11-05 | 2024-11-20 | 1 year 4 mons 15 days 09:12:04
(1 row)
Greșeli frecvente
- Așteptarea ca
NOW()să își schimbe valoarea între două instrucțiuni din același blocBEGIN ... COMMIT:NOW()este înghețat la începutul tranzacției; dacă măsori durata pașilor intermediari, foloseșteclock_timestamp(). - Folosirea tipului
timestamp without time zonepentru evenimente globale: la schimbarea orei de vară/iarnă sau la mutarea serverului apar ambiguități; folosește întotdeaunatimestamptz.
Comenzi și funcții înrudite
to_char() și EXTRACT(): Formatează date, ore și numere în șiruri personalizate (to_char) sau extrage componente numerice din timestamp-uri (EXTRACT).generate_series(): Generează pe loc serii de numere întregi sau calendare de date/ore pentru rapoarte fără zile lipsă și date de test.GROUP BY, HAVING și clauza FILTER: Grupează rândurile pentru agregări și aplică condiții individuale pe fiecare funcție agregată prin FILTER (WHERE …).