21 जन॰ 2026·8 मिनट पढ़ने में

TIMESTAMPTZ बनाम TIMESTAMP: PostgreSQL डैशबोर्ड और API

PostgreSQL में TIMESTAMPTZ और TIMESTAMP: आपके चुने हुए प्रकार का असर डैशबोर्ड, API प्रतिक्रियाओं, टाइम ज़ोन कनवर्ज़न और डेलाइट सेविंग टाइम बग्स पर कैसे पड़ता है।

TIMESTAMPTZ बनाम TIMESTAMP: PostgreSQL डैशबोर्ड और API

असली समस्या: एक समय, कई व्याख्याएँ

एक घटना एक बार होती है, लेकिन उसे दर्ज करने और दिखाने के दौरान कई तरह से रिपोर्ट किया जाता है। डेटाबेस एक मान स्टोर करता है, API उसे सीरियलाइज़ करता है, डैशबोर्ड उसे ग्रुप करता है, और हर व्यक्ति उसे अपने समय क्षेत्र में देखता है। अगर किसी भी लेयर ने अलग धारणा बनाई, तो वही पंक्ति दो अलग पलों जैसी लग सकती है।

इसी कारण TIMESTAMPTZ बनाम TIMESTAMP सिर्फ डेटा टाइप की पसंद नहीं है। यह तय करता है कि स्टोर किया गया मान किसी निश्चित क्षण का प्रतिनिधित्व करता है या एक ऐसी दीवार-घड़ी (wall-clock) समय है जिसका मतलब केवल किसी विशेष स्थान में ही समझ आता है।

सबसे पहले जो टूटता है वही है: एक सेल्स डैशबोर्ड न्यूयॉर्क और बर्लिन में अलग दैनिक टोटल दिखाता है। एक घंटे का चार्ट DST बदलाव के दौरान एक गुम घंटा या डुप्लिकेट घंटा दिखाता है। एक ऑडिट लॉग बाहर-से-क्रम (out of order) लगता है क्योंकि दो सिस्टम तारीख पर “सहमत” हैं लेकिन वास्तविक क्षण पर नहीं।

एक सरल मॉडल आपको मुसीबत से बचाए रखता है:

  • Storage: आप PostgreSQL में क्या सहेजते हैं और उसका क्या अर्थ है।
  • Display: आप UI, एक्सपोर्ट या रिपोर्ट में उसे कैसे फॉर्मेट करते हैं।
  • User locale: दर्शक का समय क्षेत्र और कैलेंडर नियम, जिसमें DST शामिल है।

इन्हें मिलाकर आप चुपचाप रिपोर्टिंग बग्स पाएंगे। सपोर्ट टीम डैशबोर्ड से “कल बनाए गए टिकट” एक्सपोर्ट करती है और फिर उसे API रिपोर्ट से मिलाती है। दोनों ठीक लगते हैं, पर एक ने दर्शक के लोकल मिडनाइट बॉउण्डरी इस्तेमाल की और दूसरे ने UTC।

लक्ष्य सरल है: हर समय मान के लिए दो स्पष्ट चुनाव करें। तय करें आप क्या सहेज रहे हैं, और तय करें आप क्या दिखाएंगे। वही स्पष्टता आपके डेटा मॉडल, API प्रतिक्रियाओं, और डैशबोर्ड्स में बनी रहनी चाहिए ताकि हर कोई एक ही टाइमलाइन देखे।

TIMESTAMP और TIMESTAMPTZ का असली मतलब

PostgreSQL में नामों से भ्रम होता है। ये दिखते हैं कि वे क्या स्टोर करते हैं, पर असल में वे बताते हैं कि PostgreSQL इनपुट को कैसे इंटरप्रेट करता और आउटपुट को कैसे फॉर्मेट करता है।

TIMESTAMP (यानी timestamp without time zone) सिर्फ एक कैलेंडर तारीख और घड़ी का समय है, जैसे 2026-01-29 09:00:00. कोई समय क्षेत्र जुड़ा नहीं है। PostgreSQL इसे आपके लिए कन्‍वर्ट नहीं करेगा। दो अलग समय क्षेत्रों के लोग एक ही TIMESTAMP पढ़कर अलग वास्तविक पलों की धारणा कर सकते हैं।

TIMESTAMPTZ (यानी timestamp with time zone) एक वास्तविक क्षण को दर्शाता है। इसे एक instant समझें। PostgreSQL इसे अंदरूनी तौर पर सामान्यीकृत करता है (वैसे तो UTC के रूप में) और फिर उस सेशन के समय क्षेत्र में दिखाता है जो वर्तमान में सेट है।

ज्यादातर सरप्राइज़ के पीछे की व्यवहारिक बातें ये हैं:

  • इनपुट पर: PostgreSQL TIMESTAMPTZ मानों को एक सुसंगत तुलना योग्य क्षण में बदल देता है।
  • आउटपुट पर: PostgreSQL उस क्षण को वर्तमान सेशन समय क्षेत्र का उपयोग करके फॉर्मेट करता है।
  • TIMESTAMP के लिए: इनपुट या आउटपुट पर कोई स्वचालित रूपांतरण नहीं होता।

एक छोटा उदाहरण फर्क दिखाता है। मान लीजिए आपकी ऐप को यूज़र से 2026-03-08 02:30 मिलता है। अगर आप इसे TIMESTAMP कॉलम में डालते हैं, PostgreSQL ठीक वही वॉल-क्लॉक वैल्यू स्टोर करेगा। अगर वह स्थानीय समय DST कूद की वजह से मौजूद नहीं है, तो आप रिपोर्टिंग टूटने तक नोटिस नहीं कर पाएंगे।

अगर आप इसे TIMESTAMPTZ में डालते हैं, PostgreSQL को उस वैल्यू को समझने के लिए एक समय क्षेत्र चाहिए होगा। अगर आप देते हैं 2026-03-08 02:30 America/New_York, PostgreSQL उसे एक instant में बदल देगा (या नियमों और सटीक वैल्यू पर निर्भर करते हुए एरर फेंक सकता है)। बाद में लंदन में एक डैशबोर्ड अलग लोकल क्लॉक समय दिखाएगा, पर यह वही instant होगा।

एक आम गलत धारणा: लोग “with time zone” देखकर उम्मीद करते हैं कि PostgreSQL मूल समय क्षेत्र लेबल स्टोर करेगा। ऐसा नहीं होता। PostgreSQL क्षण स्टोर करता है, लेबल नहीं। अगर आपको उपयोगकर्ता का असली समय क्षेत्र डिस्प्ले के लिए चाहिए (उदा., “ग्राहक के लोकल समय में दिखाएं”), तो उस टाइम ज़ोन को अलग टेक्स्ट फील्ड में स्टोर करें।

सेशन टाइम ज़ोन: कई सरप्राइज़ के पीछे का छिपा हुआ सेटिंग

PostgreSQL में एक सेटिंग है जो चुपचाप आपको दिखने वाले समय को बदल सकती है: session time zone. दो लोग एक ही डेटा पर एक ही क्वेरी चला कर अलग क्लॉक टाइम देख सकते हैं क्योंकि उनकी सेशन टाइम ज़ोन अलग है।

यह ज़्यादातर TIMESTAMPTZ को प्रभावित करता है। PostgreSQL एक निश्चित क्षण स्टोर करता है, फिर उसे सेशन के समय क्षेत्र में दिखाता है। TIMESTAMP (बिना समय क्षेत्र) में PostgreSQL वैल्यू को सादे कैलेंडर टाइम की तरह ट्रीट करता है। यह डिस्प्ले के लिए शिफ्ट नहीं करता, पर जब आप इसे TIMESTAMPTZ में बदलते हैं या समय-क्षेत्र-सचेत मानों के साथ तुलना करते हैं तो सेशन टाइम ज़ोन समस्या पैदा कर सकता है।

सेशन टाइम ज़ोन अक्सर बिना ध्यान दिए सेट हो जाता है: ऐप स्टार्टअप कॉन्फ़िग, ड्राइवर पैरामीटर्स, कनेक्शन पूल पुराने सेशनों का पुन: उपयोग, BI टूल्स के डिफ़ॉल्ट, ETL जॉब्स जो सर्वर लोकेल इनहेरिट करते हैं, या मनमाना SQL कंसोल जो आपके लैपटॉप की प्राथमिकताएँ लेते हैं।

टीमें अक्सर इस पर बहस कर बैठती हैं। मान लीजिए कोई इवेंट TIMESTAMPTZ कॉलम में 2026-03-08 01:30:00+00 के रूप में स्टोर है। एक डैशबोर्ड सेशन America/Los_Angeles पर उसे पिछले शाम के लोकल टाइम के रूप में दिखाएगा, जबकि API सेशन UTC पर अलग क्लॉक टाइम दिखाएगा। अगर एक चार्ट सेशन-लोकल दिन के हिसाब से ग्रुप करता है, तो आपको अलग दैनिक टोटल मिल सकते हैं।

-- Make your output consistent for a reporting job
SET TIME ZONE 'UTC';

SELECT created_at, date_trunc('day', created_at) AS day_bucket
FROM events;

जो कुछ भी रिपोर्ट या API प्रतिक्रियाएँ पैदा करता है, उसके लिए टाइम ज़ोन स्पष्ट रखें। कनेक्ट पर इसे सेट करें (या पहले SET TIME ZONE चलाएँ), मशीन आउटपुट के लिए एक मानक चुनें (अक्सर UTC), और “लोकल बिजनेस टाइम” रिपोर्ट के लिए बिज़नेस ज़ोन को उसी जॉब के अंदर सेट करें, न कि किसी के लैपटॉप पर। अगर आप पूल्ड कनेक्शन उपयोग कर रहे हैं तो कनेक्शन चेक-आउट पर सेशन सेटिंग्स रीसेट करें।

डैशबोर्ड कैसे टूटते हैं: ग्रुपिंग, बकेट्स, और DST गैप्स

डैशबोर्ड सरल दिखते हैं: दिन के अनुसार ऑर्डर गिनें, घंटे के अनुसार साइनअप दिखाएँ, हफ्ते-दर-हफ्ते तुलना करें। समस्या तब शुरू होती है जब डेटाबेस एक “क्षण” स्टोर करता है पर चार्ट उसे कई भिन्न “दिनों” में बदल देता है, यह निर्भर करता है कि कौन देख रहा है।

अगर आप यूज़र के लोकल समय ज़ोन के अनुसार दिन ग्रुप करते हैं तो दो लोग एक ही इवेंट के लिए अलग तारीख देख सकते हैं। लॉस एंजिल्स में 23:30 पर दिया गया ऑर्डर बर्लिन में पहले से ही “अगले दिन” हो सकता है। और अगर आपकी SQL DATE(created_at) पर ग्रुप कर रही है और वह कॉलम TIMESTAMP है, तो आप वास्तविक क्षण के अनुसार ग्रुप नहीं कर रहे हैं। आप एक वॉल-क्लॉक रीडिंग के अनुसार ग्रुप कर रहे हैं जिसका कोई टाइम ज़ोन नहीं जुड़ा।

DST के आसपास घंटा चार्ट और भी उलझ जाते हैं। वसंत में एक लोकल घंटा कभी नहीं होता, इसलिए चार्ट में गैप दिख सकता है। पतझड़ में एक लोकल घंटा दो बार होता है, इसलिए आप स्पाइक या डबल बकेट देख सकते हैं अगर आपका क्वेरी और डैशबोर्ड यह तय नहीं करते कि आप किस 01:30 की बात कर रहे हैं।

एक व्यावहारिक प्रश्न मदद करता है: क्या आप वास्तविक पलों को चार्ट कर रहे हैं (जो सुरक्षित है कन्‍वर्ट करने के लिए), या लोकल शेड्यूल टाइम (जिसे कन्वर्ट नहीं करना चाहिए)? डैशबोर्ड लगभग हमेशा वास्तविक पलों को दिखाना चाहते हैं।

कब UTC के अनुसार ग्रुप करें बनाम बिजनेस टाइम ज़ोन के अनुसार

एक नियम चुनिए और हर जगह लागू कीजिए (SQL, API, BI टूल), वरना टोटल्स डिफ्ट करेंगे।

जब आप ग्लोबल, सुसंगत सीरीज़ चाहते हैं तो UTC के अनुसार ग्रुप करें (सिस्टम स्वास्थ्य, API ट्रैफ़िक, ग्लोबल साइनअप)। जब “दिन” का कोई कानूनी या ऑपरेशनल अर्थ हो तब बिज़नेस टाइम ज़ोन के अनुसार ग्रुप करें (स्टोर का दिन, सपोर्ट SLA, फाइनेंस क्लोज)। केवल तभी व्यूअर के टाइम ज़ोन के अनुसार ग्रुप करें जब पर्सनलाइज़ेशन तुलना-योग्यता से ज्यादा महत्वपूर्ण हो (व्यक्तिगत गतिविधि फीड)।

कंसिस्टेंट “बिज़नेस डे” ग्रुपिंग के लिए पैटर्न:

SELECT date_trunc('day', created_at AT TIME ZONE 'America/New_York') AS business_day,
       count(*)
FROM orders
GROUP BY 1
ORDER BY 1;

भरोसा रोकने वाले लेबल

लोग चार्ट पर भरोसा तब खो देते हैं जब नंबर कूदते हैं और कोई समझा नहीं पाता कि क्यों। UI में नियम स्पष्ट रूप से लेबल करें: “Daily orders (America/New_York)” या “Hourly events (UTC)”. एक्सपोर्ट्स और APIs में भी वही नियम इस्तेमाल करें।

रिपोर्टिंग और APIs के लिए एक सरल नियम सेट

Make time handling consistent
Build your backend and API from one place so timestamp rules stay consistent.
Try AppMaster

फैसला करें कि आप एक instant स्टोर कर रहे हैं या एक लोकल क्लॉक रीडिंग। इन्हें मिलाना ही वह जगह है जहां डैशबोर्ड और API असहमति शुरू करते हैं।

एक नियम सेट जो रिपोर्टिंग को भविष्यवाणी योग्य रखे:

  • वास्तविक-विश्व इवेंट्स को instants के रूप में TIMESTAMPTZ में स्टोर करें, और UTC को सत्य का स्रोत मानें।
  • “बिज़नेस” अवधारणाएँ जैसे “billing day” को अलग DATE के रूप में स्टोर करें (या अगर वॉल-क्लॉक टाइम चाहिए तो लोकल-टाइम फील्ड के साथ)।
  • APIs में timestamps ISO 8601 में लौटाएँ और सुसंगत रहें: हमेशा ऑफ़सेट शामिल करें (जैसे +02:00) या हमेशा UTC के लिए Z उपयोग करें।
  • एज पर कन्वर्ट करें (UI और रिपोर्टिंग लेयर)। डेटाबेस लॉजिक और बैकग्राउंड जॉब्स के अंदर बार-बार कन्वर्ट करने से बचें।

यह क्यों टिकता है: डैशबोर्ड बकेट और तुलना रेंज करते हैं। अगर आप instants (TIMESTAMPTZ) स्टोर करते हैं, PostgreSQL इवेंट्स को विश्वसनीय रूप से ऑर्डर और फ़िल्टर कर सकता है भले ही DST शिफ्ट हो। फिर आप चुनते हैं कि उन्हें कैसे दिखाना या ग्रुप करना है। अगर आप किसी लोकल क्लॉक टाइम (TIMESTAMP) को बिना समय क्षेत्र के स्टोर करते हैं, PostgreSQL इसका मतलब नहीं जान सकता, इसलिए ग्रुपिंग तब बदल सकती है जब सेशन टाइम ज़ोन बदले।

“लोकल बिजनेस डेट्स” को अलग रखें क्योंकि वे instants नहीं हैं। “2026-03-08 को डिलीवर” एक तारीख का निर्णय है, कोई क्षण नहीं। अगर आप इसे जबरदस्ती किसी timestamp में डालते हैं, तो DST दिनों में गायब या डुप्लिकेट लोकल घंटे बन सकते हैं, जो बाद में गैप या स्पाइक के रूप में दिखेंगे।

चरण-दर-चरण: हर टाइम वैल्यू के लिए सही टाइप चुनना

Fix daily totals in dashboards
Create admin screens that label the reporting time zone so teams trust the numbers.
Build Dashboard

TIMESTAMPTZ बनाम TIMESTAMP चुनना एक प्रश्न से शुरू होता है: क्या यह वैल्यू एक वास्तविक क्षण बताती है जो हुआ था, या एक लोकल समय है जिसे आप बिल्कुल जैसा लिखा है वैसा ही रखना चाहते हैं?

1) वास्तविक इवेंट्स को शेड्यूल किए गए लोकल टाइम से अलग करें

अपने कॉलम्स का एक त्वरित इन्वेंटरी बनाएं।

वास्तविक इवेंट्स (क्लिक्स, पेमेंट्स, लॉगिन, शिपमेंट, सेंसर रीडिंग, सपोर्ट मैसेज) आमतौर पर TIMESTAMPTZ में स्टोर होने चाहिए। आप एक निर्विवाद instant चाहते हैं, भले ही लोग अलग समय क्षेत्रों से देखें।

शेड्यूल किए गए लोकल टाइम अलग हैं: “स्टोर 09:00 पर खुलता है”, “पिकअप विंडो 16:00 से 18:00”, “बिलिंग हर महीने की 1 तारीख को 10:00 लोकल टाइम पर।” ये अक्सर TIMESTAMP के साथ अलग time zone फील्ड के बेहतर होते हैं, क्योंकि मकसद किसी स्थान की वॉल-क्लॉक से जुड़ा होता है।

2) एक स्टैण्डर्ड चुनें और लिखकर रखें

अधिकांश उत्पादों के लिए एक अच्छा डिफ़ॉल्ट है: इवेंट टाइम्स को UTC में स्टोर करें, और उन्हें उपयोगकर्ता के समय क्षेत्र में प्रस्तुत करें। इसे उन जगहों पर दस्तावेज़ करें जहाँ लोग सच में देखते हैं: स्कीमा नोट्स, API डॉक्स, और डैशबोर्ड विवरण। साथ ही यह भी परिभाषित करें कि “बिज़नेस डे” का मतलब क्या है (UTC दिन, बिज़नेस ज़ोन दिन, या व्यूअर-लोकल दिन), क्योंकि यह दैनिक रिपोर्टिंग को निर्देशित करेगा।

एक छोटा चेकलिस्ट जो व्यवहार में काम करता है:

  • प्रत्येक समय कॉलम को “event instant” या “local schedule” टैग करें।
  • इवेंट इंस्टेंट्स को डिफ़ॉल्ट के तौर पर TIMESTAMPTZ और UTC में रखें।
  • स्कीमा बदलते समय सावधानी से बैकफिल करें और थोडे़ सैंपल रो हाथ से वेलिडेट करें।
  • API फ़ॉर्मैट्स स्टैण्डर्ड करें (इंस्टेंट्स के लिए हमेशा Z या ऑफ़सेट शामिल करें)।
  • ETL जॉब्स, BI कनेक्टर्स, और बैकग्राउंड वर्कर्स में सेशन टाइम ज़ोन स्पष्ट रूप से सेट करें।

“कन्वर्ट और बैकफिल” काम में सावधानी बरतें। कॉलम टाइप बदलने से अर्थ चुपचाप बदल सकता है अगर पुरानी वैल्यूज़ किसी अलग सेशन टाइम ज़ोन के तहत इंटरप्रेट की गई थीं।

सामान्य गलतियाँ जो एक-दिन-की-गलत और DST बग्स पैदा करती हैं

ज्यादातर समय बग “PostgreSQL अजीब है” के कारण नहीं होते। वे इसलिए होते हैं क्योंकि सही दिखने वाली वैल्यू गलत मतलब के साथ स्टोर की गई, और फिर अलग लेयर्स ने गायब संदर्भ का अनुमान लगवा लिया।

गलती 1: वॉल-क्लॉक टाइम को जैसे-का-तैसा अभेद्य मानकर स्टोर करना

एक आम जाल यह है कि स्थानीय वॉल-क्लॉक टाइम (जैसे “2026-03-29 09:00” बर्लिन में) को TIMESTAMPTZ में स्टोर कर देना। PostgreSQL इसे एक instant समझकर वर्तमान सेशन टाइम ज़ोन के आधार पर कन्वर्ट कर देता है। अगर असली मंशा थी “हमेशा स्थानीय 9 AM”, तो आपने वह अर्थ खो दिया। किसी अलग सेशन टाइम ज़ोन के तहत वही पंक्ति देख कर दिखने वाला घंटा शिफ्ट हो जाएगा।

अपॉइंटमेंट्स के लिए लोकल टाइम को TIMESTAMP के रूप में और अलग समय ज़ोन (या लोकेशन) फील्ड के साथ स्टोर करें। जो इवेंट्स वास्तव में किसी क्षण पर हुए थे (पेमेंट, लॉगिन), उन्हें TIMESTAMPTZ में रखें।

गलती 2: अलग- अलग परिवेश, अलग धारणाएँ

आपके लैपटॉप, स्टेजिंग, और प्रोडक्शन का समय क्षेत्र अलग हो सकता है। एक वातावरण UTC पर चलता है, दूसरा लोकल टाइम पर, और “दिन के हिसाब से ग्रुप” रिपोर्टिंग असहमति दिखाने लगती है। डेटा नहीं बदला, सेशन सेटिंग बदली।

गलती 3: समय फ़ंक्शंस का उपयोग बिना यह जाने कि वे क्या करते हैं

now() और current_timestamp एक ट्रांज़ैक्शन के भीतर स्थिर रहते हैं। clock_timestamp() हर कॉल पर बदलता है। अगर आप एक ट्रांज़ैक्शन में कई बिंदुओं पर टाइमस्टैम्प जेनरेट करते हैं और इन फ़ंक्शंस को मिलाते हैं, तो ऑर्डर और अवधि अजीब दिख सकती है।

गलती 4: दो बार कन्वर्ट करना (या बिल्कुल भी नहीं)

एक सामान्य API बग: ऐप एक लोकल टाइम को UTC में कन्वर्ट करता है, उसे एक 'नैवी' स्ट्रिंग के रूप में भेजता है, फिर डेटाबेस सेशन फिर से कन्वर्ट कर देता है क्योंकि वह इनपुट को लोकल समझता है। विपरीत भी होता है: ऐप लोकल टाइम भेजता है पर उसे Z (UTC) के साथ लेबल कर देता है, जिससे रेंडर करते समय शिफ्ट हो जाता है।

गलती 5: तारीख के अनुसार ग्रुपिंग बिना बताए कि किस टाइम ज़ोन का अर्थ है

“डेली टोटल्स” इस बात पर निर्भर करते हैं कि आप किस दिन बॉउण्डरी को मान रहे हैं। अगर आप date(created_at) से ग्रुप करते हैं और कॉलम TIMESTAMPTZ है, तो परिणाम सेशन टाइम ज़ोन का पालन करेगा। देर रात के इवेंट्स पिछले या अगले दिन में जा सकते हैं।

किसी डैशबोर्ड या API को शिप करने से पहले बेसिक्स का सैनीटी-चेक करें: प्रति चार्ट एक रिपोर्टिंग टाइम ज़ोन चुनें और उसे सुसंगत रूप से लागू करें, API में ऑफ़सेट या Z शामिल करें, स्टेजिंग और प्रोडक्शन को टाइम ज़ोन नीति पर बराबर रखें, और ग्रुपिंग करते समय स्पष्ट रूप से बताएं कि आप किस समय ज़ोन का मतलब ले रहे हैं।

डैशबोर्ड या API भेजने से पहले त्वरित चेक्स

Control reporting time zones
Run jobs and reports with an explicit time zone to avoid hidden session settings.
Set UTC

टाइम बग अक्सर एक बुरी क्वेरी का परिणाम नहीं होते। वे होते हैं क्योंकि स्टोरेज, रिपोर्टिंग, और API हर कोई थोड़ा अलग धारणा करता है।

एक छोटा प्री-शिप चेकलिस्ट:

  • वास्तविक-विश्व इवेंट्स (साइनअप, पेमेंट, सेंसर पिंग) को TIMESTAMPTZ के रूप में स्टोर करें।
  • बिज़नेस-लोकल अवधारणाओं (बिलिंग डे, रिपोर्टिंग डेट) को DATE या TIME के रूप में स्टोर करें, न कि उस तरह के timestamp में जो आप बाद में कन्वर्ट करने का इरादा रखते हों।
  • शेड्यूल्ड जॉब्स और रिपोर्ट रनर्स में सेशन टाइम ज़ोन उद्देश्यपूर्ण रूप से सेट करें।
  • API प्रतिक्रियाओं में ऑफ़सेट या Z शामिल करें, और पुष्टि करें कि क्लाइंट उसे टाइम-जोन-सचेत के रूप में पार्स करता है।
  • कम से कम एक लक्षित टाइम ज़ोन के लिए DST ट्रांज़िशन सप्ताह का परीक्षण करें।

एक तेज एंड-टू-एंड वेलिडेशन: एक ज्ञात एज-केस इवेंट चुनें (उदा., 2026-03-08 01:30 किसी DST-निगरानी ज़ोन में) और उसे स्टोरेज, क्वेरी आउटपुट, API JSON, और अंतिम चार्ट लेबल तक फॉलो करें। अगर चार्ट सही दिन दिखाता है पर टूलटिप गलत घंटा दिखाती है (या इसके विपरीत), तो आपके पास कन्वर्शन मिक्समैच है।

उदाहरण: क्यों दो टीमें एक ही दिन के नंबर पर असहमत हैं

Design your Postgres schema
Model PostgreSQL tables with TIMESTAMPTZ and keep meaning clear across the app.
Start Building

न्यूयॉर्क की सपोर्ट टीम और बर्लिन की फाइनेंस टीम एक ही डैशबोर्ड देखती हैं। डेटाबेस सर्वर UTC पर चलता है। हर कोई अपने नंबरों पर अड़ा हुआ है, पर “कल” उस पर निर्भर करता है कि आप किससे पूछते हैं।

यहाँ इवेंट है: एक कस्टमर टिकट न्यूयॉर्क में 23:30 पर मार्च 10 को बनाया गया। वह UTC में 04:30 मार्च 11 है, और बर्लिन में 05:30 है। एक वास्तविक क्षण, तीन अलग कैलेंडर तारीखें।

अगर टिकट का creation time TIMESTAMP (बिना टाइम ज़ोन) में स्टोर है और आपकी ऐप मान लेती है कि यह "लोकल" है, तो आप चुपचाप इतिहास बदल सकते हैं। न्यूयॉर्क 2026-03-10 23:30 को न्यूयॉर्क टाइम मान सकता है, जबकि बर्लिन वही स्टोर किए गए मान को बर्लिन टाइम मान लेता है। वही पंक्ति अलग-दिन पर पहुंच जाती है अलग दर्शकों के लिए।

अगर यह TIMESTAMPTZ में स्टोर है, PostgreSQL क्षण को सुसंगत रूप से स्टोर करता है और केवल तब कन्वर्ट करता है जब कोई इसे देखता या फॉर्मेट करता है। यही कारण है कि TIMESTAMPTZ बनाम TIMESTAMP रिपोर्ट्स में “एक दिन” का मतलब बदल देता है।

फिक्स यह है कि दो विचार अलग करें: घटना का क्षण कब हुआ, और आप किस रिपोर्टिंग तारीख का उपयोग करना चाहते हैं।

एक व्यावहारिक पैटर्न:

  1. इवेंट टाइम को TIMESTAMPTZ के रूप में स्टोर करें।
  2. रिपोर्टिंग नियम तय करें: व्यूअर-लोकल (पर्सनल डैशबोर्ड) या एक बिज़नेस टाइम ज़ोन (कंपनी-वाइड फाइनेंस)।
  3. उस नियम का उपयोग करके क्वेरी समय पर रिपोर्टिंग तारीख निकालें: इंस्टेंट को चुने हुए ज़ोन में कन्वर्ट करें, फिर तारीख लें।

अगले कदम: अपने स्टैक में समय हैंडलिंग को स्टैण्डर्ड करें

अगर समय हैंडलिंग लिखी नहीं है तो हर नया रिपोर्ट एक अनुमान गेम बन जाता है। डेटाबेस, APIs, और डैशबोर्ड्स में एक नीरस और भविष्यवाणी योग्य समय व्यवहार का लक्ष्य रखें।

एक छोटा “टाइम कॉन्ट्रैक्ट” लिखें जो तीन सवालों का जवाब दे:

  • Event time standard: घटना के इंस्टेंट्स को TIMESTAMPTZ (आम तौर पर UTC) के रूप में स्टोर करें जब तक कि आपके पास मज़बूत कारण न हो।
  • Business time zone: रिपोर्टिंग के लिए एक ज़ोन चुनें, और इसे “दिन”, “सप्ताह”, और “महीना” पर लागू करते समय सुसंगत रूप से उपयोग करें।
  • API format: हमेशा ऑफ़सेट के साथ टाइमस्टैम्प भेजें (ISO 8601 Z या +/-HH:MM) और दस्तावेज़ करें कि कौन से फील्ड “instant” हैं और कौन से “local wall time”।

DST स्टार्ट और DST एंड के आसपास छोटे टेस्ट जोड़ें। ये महँगे बग्स जल्दी पकड़ लेते हैं। उदाहरण के लिए, यह वेलिडेट करें कि “डेली टोटल” क्वेरी एक फिक्स्ड बिज़नेस ज़ोन के लिए DST परिवर्तन के दौरान स्थिर रहे, और API इनपुट जैसे 2026-11-01T01:30:00-04:00 और 2026-11-01T01:30:00-05:00 को दो अलग इंस्टैंट्स के रूप में ट्रीट किया जाए।

माइग्रेशन्स की सावधानीपूर्वक योजना बनायें। टाइप और धारणाएँ inplace बदलने से चार्ट्स में इतिहास चुपचाप बदल सकता है। एक सुरक्षित तरीका है नया कॉलम जोड़ना (उदा., created_at_utc TIMESTAMPTZ), उसे समीक्षा कर के बैकफिल करना, पढ़ने को नया कॉलम उपयोग करने के लिए अपडेट करना, फिर लिखने को अपडेट करना। थोड़ी देर के लिए पुराने और नए रिपोर्ट्स को साथ चलाएँ ताकि दैनिक संख्याओं में कोई शिफ्ट स्पष्ट दिखे।

अगर आप इस “टाइम कॉन्ट्रैक्ट” को डेटा मॉडल, APIs, और स्क्रीन में लागू करने के लिए एक जगह चाहते हैं, एक यूनिफाइड बिल्ड सेटअप मदद करता है। AppMaster (appmaster.io) एक प्रोजेक्ट से बैकएंड, वेब ऐप, और APIs जनरेट करता है, जो आपके ऐप बढ़ने के साथ टाइमस्टैम्प स्टोरेज और डिस्प्ले नियमों को सुसंगत रखने में आसान बनाता है।

सामान्य प्रश्न

When should I use TIMESTAMPTZ instead of TIMESTAMP?

Use TIMESTAMPTZ for anything that happened at a real moment (signups, payments, logins, messages, sensor pings). It stores one unambiguous instant and can be safely sorted, filtered, and compared across systems. Use plain TIMESTAMP only when the value is meant to be a wall-clock time that should stay exactly as written, usually paired with a separate time zone or location field.

What’s the real difference between TIMESTAMP and TIMESTAMPTZ in PostgreSQL?

TIMESTAMPTZ represents a real instant in time; PostgreSQL normalizes it internally and then displays it in your session time zone. TIMESTAMP is just a date and clock time with no zone attached, so PostgreSQL won’t shift it automatically. The key difference is meaning: instant versus local wall time.

Why do I see different times for the same row depending on who runs the query?

Because the session time zone controls how TIMESTAMPTZ is formatted on output and how some inputs are interpreted. Two tools can query the same row and show different clock times if one session is set to UTC and another to America/Los_Angeles. For reports and APIs, set the session time zone explicitly so results don’t depend on hidden defaults.

Why do daily totals change between New York and Berlin?

Because “a day” depends on a time zone boundary. If one dashboard groups by viewer-local time while another groups by UTC (or a business zone), late-night events can fall on different dates and change daily totals. Fix it by picking one grouping rule per chart (UTC or a specific business zone) and using it consistently in SQL, BI, and exports.

How do I avoid DST bugs like missing or duplicated hours in hourly charts?

DST creates missing or duplicated local hours, which can produce gaps or double-counted buckets when grouping by local time. If your data represents real moments, store it as TIMESTAMPTZ and choose a clear chart time zone for bucketing. Also test the DST transition week for your target zones to catch surprises early.

Does TIMESTAMPTZ store the user’s time zone?

No, PostgreSQL does not preserve the original time zone label with TIMESTAMPTZ; it stores the instant. When you query it, PostgreSQL displays it in the session time zone, which may differ from the user’s original zone. If you need “show it in the customer’s time zone,” store that zone separately in another column.

What should my API return for timestamps to avoid confusion?

Return ISO 8601 timestamps that include an offset, and be consistent. A simple default is to always return UTC with Z for event instants, then let clients convert for display. Avoid sending “naive” strings like 2026-03-10 23:30:00 because clients will guess the zone differently.

Where should time zone conversion happen: database, API, or UI?

Convert at the edges: store event instants as TIMESTAMPTZ, then convert to the desired zone when you display or bucket for reporting. Avoid converting back and forth inside triggers, background jobs, and ETL unless you have a clear contract. Most reporting problems come from double conversion or from mixing naive and time-zone-aware values.

How should I store business days and schedules like “run at 10:00 local time”?

Use DATE for business concepts that are truly dates, like “billing day,” “reporting date,” or “delivery date.” Use TIME (or TIMESTAMP plus a separate time zone) for schedules like “opens at 09:00 local time.” Don’t force these into TIMESTAMPTZ unless you really mean a single instant, because DST and zone changes can shift the intended meaning.

How can I migrate from TIMESTAMP to TIMESTAMPTZ without breaking reports?

First, decide whether it’s an instant (TIMESTAMPTZ) or a local wall time (TIMESTAMP plus zone), then add a new column instead of rewriting in place. Backfill with a reviewed conversion under a known session time zone, and validate sample rows around midnight and DST boundaries. Run old and new reports side by side briefly so any shifts in totals are obvious before you remove the old column.

शुरू करना आसान
कुछ बनाएं अद्भुत

फ्री प्लान के साथ ऐपमास्टर के साथ प्रयोग करें।
जब आप तैयार होंगे तब आप उचित सदस्यता चुन सकते हैं।

शुरू हो जाओ