PostgreSQL: दो तिथियों के बीच दिन / महीने / वर्ष


94

मैं PostgreSQL में SQLServer-फ़ंक्शन datediff को लागू करने का एक तरीका ढूंढ रहा हूं । अर्थात्,

यह फ़ंक्शन निर्दिष्ट प्रारंभ और समाप्ति के बीच पार की गई निर्दिष्ट तिथि सीमाओं की गणना (एक हस्ताक्षरित पूर्णांक मान के रूप में) लौटाता है।

datediff(dd, '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval
datediff(mm, '2010-04-01', '2012-03-05') = 23  // 23 changes of month
datediff(yy, '2010-04-01', '2012-03-05') = 2   // 2 changes of year

मुझे पता है कि मैं केवल घटाव का उपयोग करके 'dd' कर सकता था, लेकिन अन्य दो के बारे में कोई विचार?


जवाबों:


116
SELECT
  AGE('2012-03-05', '2010-04-01'),
  DATE_PART('year', AGE('2012-03-05', '2010-04-01')) AS years,
  DATE_PART('month', AGE('2012-03-05', '2010-04-01')) AS months,
  DATE_PART('day', AGE('2012-03-05', '2010-04-01')) AS days;

इससे आपको पूरे साल, महीने, दिन ... दो तिथियों के बीच मिलेंगे :

          age          | years | months | days
-----------------------+-------+--------+------
 1 year 11 mons 4 days |     1 |     11 |    4

अधिक विस्तृत दिनांकित जानकारी


8
+1 उम्र समारोह के कारण, लेकिन मुझे लगता है कि यह तर्क गलत क्रम में हैं :)
dcarneiro

2
select date_part('month', age('2010-04-01', '2012-03-05'));देता है -11। महीनों में यह सही अंतर नहीं है
smac89

1
select_part ('माह', आयु ('2012-03-05', '2010-04-01')) का चयन करें;
Zuko

35
यह महीनों + साल आदि का हिसाब नहीं देता है। यह सिर्फ एक रोलिंग डे चेक करता है - यानी SELECT date_part('day', age('2016-10-05', '2015-10-02'))रिटर्न3
डॉन चीडल

सवाल यह है कि दो साल के बीच कितने साल की सीमा क्रॉसिंग और कितने महीने की सीमा क्रॉसिंग की गणना की जाए। उपयोग age()करना हमेशा वर्षों और महीनों तक ऐसा करना गलत होगा। बीच 2014-12-31और 2015-01-01पहले महीने और वर्ष के लिए 0 देंगे, जबकि datediff()1 और 1 देंगे। आप केवल एक age()परिणाम में नहीं जोड़ सकते क्योंकि age()+11 के बीच 2015-01-01और जब दे देंगे 2015-01-02, जबकि datediff()अब 0. देगा
एंड्रे सी एंडरसन

147

बस उन्हें घटाएँ:

SELECT ('2015-01-12'::date - '2015-01-01'::date) AS days;

परिणाम:

 days
------
   11

2
हां, यह PostgreSQL के लिए काम करता है जब आपको दो तिथियों के बीच दिनों की संख्या जानने की आवश्यकता होती है।
icl7126

महान! FYI करें मैं इसे दो तारीखों के बीच छोटी रेंज द्वारा रिकॉर्ड ऑर्डर करने के लिए इस्तेमाल किया, पूर्व:range_end - range_start ASC, id DESC
एडीसन मचाडो

1
ज्ञात हो, यह विधि रिटर्न प्रकार है interval, जिसे बस के रूप में नहीं डाला जा सकता है intमैं पोस्टग्रेज के साथ कितने घंटे में अंतराल को परिवर्तित करता हूं? date_part/ ageफ़ंक्शन कॉम्बो का उपयोग करना , जैसे @IgorRomanchenko के उत्तर में बताया गया हैdouble precision
WebWanderer

2
दूसरे विचार पर, यह सही तरीका है। दो तिथियों के बीच दिनों की संख्या प्राप्त करने के लिए इस पद्धति का उपयोग करते हुए महीनों और वर्षों के बीच के दिनों की गणना होगी, जबकि date_part/ ageउत्तर, जैसा कि स्वीकार किया गया है, दो दिनों के दिनों के अंतर के रूप में दिन प्रदान करेगा। date_part('day', age('2016-9-05', '2015-10-02'))रिटर्न 3.
वेबवंडर

1
सवाल दिनों के बारे में नहीं था, यह महीने और साल की सीमाओं की संख्या के बारे में है जिसे दो तिथियों के बीच पार किया जाना है। पूछने वाला पहले से ही जानता था कि दिन कैसे करना है।
एंड्रे सी। एंडरसन

41

मैंने सर्वश्रेष्ठ उत्तर की तलाश में कुछ समय बिताया, और मुझे लगता है कि मेरे पास यह है।

यह वर्ग आपको दो तिथियों के बीच के दिनों की संख्या देगा integer:

SELECT
    (EXTRACT(epoch from age('2017-6-15', now())) / 86400)::int

..जब, आज चला ( 2017-3-28), मुझे प्रदान करता है:

?column?
------------
77

स्वीकृत उत्तर के बारे में गलत धारणा:

select age('2010-04-01', '2012-03-05'),
   date_part('year',age('2010-04-01', '2012-03-05')),
   date_part('month',age('2010-04-01', '2012-03-05')),
   date_part('day',age('2010-04-01', '2012-03-05'));

.. कि आप तारीख के तारों के हिस्सों के बीच शाब्दिक अंतर प्राप्त करेंगे, न कि दो तिथियों के बीच के समय की मात्रा।

अर्थात:

Age(interval)=-1 years -11 mons -4 days;

Years(double precision)=-1;

Months(double precision)=-11;

Days(double precision)=-4;


7
यह स्वीकृत उत्तर होना चाहिए। एकमात्र ट्वीक मेरा सुझाव है कि कास्टिंग के बजाय इंट (ट्रंकिंग के बजाय आंशिक दिनों तक गोल करने के लिए) का उपयोग करना है।
रोब

2
अच्छी बात @Rob। पाठकों को इस पर ध्यान देना चाहिए। मैं इसे एक प्राथमिकता के रूप में देख सकता हूं। मुझे लगता है कि मेरे अधिकांश मामलों में, मैं तारीखों के बीच के दिनों की शाब्दिक संख्या के रूप में अपने मूल्य को कम करना चाहता हूं, लेकिन मैं देख सकता हूं कि दिनों की संख्या को गोल करने के साथ ही उपयोग किया जाना चाहिए।
वेबवैंडर

2
इस दृष्टिकोण को ब्रिटेन के दिन के उजाले की बचत के समय से
आगे बढ़ाया

वाह @qcodepeter! अच्छी पकड़! आप बिल्कुल सही हैं! हम इसे कैसे ठीक करते हैं?
WebWanderer

1
यह वास्तव में सवाल का जवाब नहीं देता है। सवाल यह है कि दो साल के बीच कितने साल की सीमा पार की जाए, और कितने महीने की सीमा पार की जाए। यह उत्तर केवल उत्तर देता है कि कितने दिन हैं, और लीप वर्षों का हिसाब नहीं है।
एंड्रे सी। एंडरसन

9

लगभग वही कार्य जो आपको आवश्यक था (एतिरुज़ के उत्तर पर आधारित, यहाँ से यूडीएफ का छोटा संस्करण )

CREATE OR REPLACE FUNCTION datediff(type VARCHAR, date_from DATE, date_to DATE) RETURNS INTEGER LANGUAGE plpgsql
AS
$$
DECLARE age INTERVAL;
BEGIN
    CASE type
        WHEN 'year' THEN
            RETURN date_part('year', date_to) - date_part('year', date_from);
        WHEN 'month' THEN
            age := age(date_to, date_from);
            RETURN date_part('year', age) * 12 + date_part('month', age);
        ELSE
            RETURN (date_to - date_from)::int;
    END CASE;
END;
$$;

उपयोग:

/* Get months count between two dates */
SELECT datediff('month', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 10 */

/* Get years count between two dates */
SELECT datediff('year', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 1 */

/* Get days count between two dates */
SELECT datediff('day', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 323 */

/* Get months count between specified and current date */
SELECT datediff('month', '2015-02-14'::date, NOW()::date);
/* Result: 47 */

यह उत्तर गलत है। DATEDIFF()एमएस एसक्यूएल में फ़ंक्शन 1के लिए datediff(year, '2015-02-14', '2016-01-03')। ऐसा इसलिए है क्योंकि आपको उन तिथियों के बीच एक बार वर्ष सीमा पार करनी होगी
André C. Andersen

उत्तर सही है क्योंकि मूल प्रश्न PostgreSQL के बारे में था, न कि MS SQL के बारे में।
Riki_tiki_tavi

मैं समझता हूं कि यह कठिन हो सकता है, लेकिन मूल प्रश्न "PostgreSQL में SQLServer-function datediff को लागू करने का एक तरीका" खोजना था। MS SQL Server के उपयोगकर्ता इसे SQL सर्वर कहते हैं। "SQL सर्वर" को देखने का प्रयास करें: i.imgur.com/USCHdLS.png उपयोगकर्ता एक विशिष्ट तकनीक से एनोथर में एक फ़ंक्शन पोर्ट करना चाहता था।
एंड्रे सी। एंडरसन

क्षमा करें, आप सही थे। ऐसा लगता है कि मैं जल्दी कर रहा था और आपकी पहली टिप्पणी का अर्थ नहीं समझ पाया। जवाब अपडेट किया गया था।
Riki_tiki_tavi

7
SELECT date_part ('year', f) * 12
     + date_part ('month', f)
FROM age ('2015-06-12'::DATE, '2014-12-01'::DATE) f

परिणाम: 6


1

यह सवाल गलतफहमियों से भरा है। पहले प्रश्न को पूरी तरह से समझने दें। पूछने वाला एमएस SQL ​​सर्वर फ़ंक्शन को चलाने के लिए , या , DATEDIFF ( datepart , startdate , enddate )जहां datepartले जाता है dd, उसी परिणाम को प्राप्त करना चाहता हैmmyy

इस फ़ंक्शन द्वारा परिभाषित किया गया है:

यह फ़ंक्शन निर्दिष्ट प्रारंभ और समाप्ति के बीच पार की गई निर्दिष्ट तिथि सीमाओं की गणना (एक हस्ताक्षरित पूर्णांक मान के रूप में) लौटाता है।

इसका मतलब है कि कितने दिन की सीमाएं, महीने की सीमा या वर्ष की सीमाएं पार की जाती हैं। उनके बीच कितने दिन, महीने, या साल नहीं हैं। इसीलिएdatediff(yy, '2010-04-01', '2012-03-05') 2, और 1 नहीं है। उन तारीखों के बीच 2 साल से कम का समय है, जिसका मतलब है कि केवल 1 पूरा साल बीत गया है, लेकिन 2 साल की सीमाएं 2010 से 2011 तक और 2011 से 2012 तक पार हो गई हैं।

निम्नलिखित तर्क को सही ढंग से दोहराने के लिए मेरा सबसे अच्छा प्रयास है।

-- datediff(dd`, '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval
select ('2012-03-05'::date - '2010-04-01'::date );
-- 704 changes of day

-- datediff(mm, '2010-04-01', '2012-03-05') = 23  // 23 changes of month
select (date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date)) * 12 + date_part('month', '2012-03-05'::date) - date_part('month', '2010-04-01'::date)
-- 23 changes of month

-- datediff(yy, '2010-04-01', '2012-03-05') = 2   // 2 changes of year
select date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date);
-- 2 changes of year

1

मैं Riki_tiki_tavi के उत्तर पर विस्तार करना चाहता हूं और वहां डेटा प्राप्त करना चाहता हूं। मैंने एक datediff फ़ंक्शन बनाया है जो लगभग सब कुछ sql सर्वर करता है। इस तरह हम किसी भी इकाई को ध्यान में रख सकते हैं।

create function datediff(units character varying, start_t timestamp without time zone, end_t timestamp without time zone) returns integer
language plpgsql
 as
 $$
DECLARE
 diff_interval INTERVAL; 
 diff INT = 0;
 years_diff INT = 0;
BEGIN
 IF units IN ('yy', 'yyyy', 'year', 'mm', 'm', 'month') THEN
   years_diff = DATE_PART('year', end_t) - DATE_PART('year', start_t);

   IF units IN ('yy', 'yyyy', 'year') THEN
     -- SQL Server does not count full years passed (only difference between year parts)
     RETURN years_diff;
   ELSE
     -- If end month is less than start month it will subtracted
     RETURN years_diff * 12 + (DATE_PART('month', end_t) - DATE_PART('month', start_t)); 
   END IF;
 END IF;

 -- Minus operator returns interval 'DDD days HH:MI:SS'  
 diff_interval = end_t - start_t;

 diff = diff + DATE_PART('day', diff_interval);

 IF units IN ('wk', 'ww', 'week') THEN
   diff = diff/7;
   RETURN diff;
 END IF;

 IF units IN ('dd', 'd', 'day') THEN
   RETURN diff;
 END IF;

 diff = diff * 24 + DATE_PART('hour', diff_interval); 

 IF units IN ('hh', 'hour') THEN
    RETURN diff;
 END IF;

 diff = diff * 60 + DATE_PART('minute', diff_interval);

 IF units IN ('mi', 'n', 'minute') THEN
    RETURN diff;
 END IF;

 diff = diff * 60 + DATE_PART('second', diff_interval);

 RETURN diff;
END;
$$;

1

@WebWanderer का उत्तर SQL सर्वर का उपयोग करके डेटडिफ़ के बहुत करीब है, लेकिन गलत है। इसका कारण है कि आयु () फ़ंक्शन का उपयोग।

उदाहरण के लिए '2019-07-29' और '2020-06-25' के बीच के दिनों को 332 पर लौटना चाहिए, हालाँकि, आयु का उपयोग करते हुए () यह 327 लौटेगा। क्योंकि उम्र () 27 दिनों में लौटता है "और यह मानता है प्रत्येक माह 30 दिनों के रूप में गलत है।

आप सही परिणाम प्राप्त करने के लिए टाइमस्टैम्प का उपयोग करते हैं। जैसे

ceil((select extract(epoch from (current_date::timestamp - <your_date>::timestamp)) / 86400))


0

यहां आउटपुट के साथ एक पूर्ण उदाहरण है। psql (10.1, सर्वर 9.5.10)।

आपको 58 मिलता है, 30 से कम मूल्य नहीं है।
निकालें () फ़ंक्शन, पिछले पोस्ट में बताई गई समस्या को हल किया।

drop table t;
create table t(
    d1 date
);

insert into t values(current_date - interval '58 day');

select d1
, current_timestamp - d1::timestamp date_diff
, date_part('day', current_timestamp - d1::timestamp)
from t;

     d1     |        date_diff        | date_part
------------+-------------------------+-----------
 2018-05-21 | 58 days 21:41:07.992731 |        58

1
यह उत्तर दिनांकित (yy, '2010-04-01', '2012-03-05') = 2, और महीने के संस्करण को दोहराने के तरीके के सवाल का जवाब नहीं देता है।
एंड्रे सी। एंडरसन

0

एक और समाधान, 'वर्ष' अंतर के लिए संस्करण:

SELECT count(*) - 1 FROM (SELECT distinct(date_trunc('year', generate_series('2010-04-01'::timestamp, '2012-03-05', '1 week')))) x

    2

(1 पंक्ति)

और महीनों के लिए एक ही चाल:

SELECT count(*) - 1 FROM (SELECT distinct(date_trunc('month', generate_series('2010-04-01'::timestamp, '2012-03-05', '1 week')))) x

   23

(1 पंक्ति)

वास्तविक जीवन क्वेरी में जनरेट_सेरीज के बजाय घंटे / दिन / सप्ताह / आदि द्वारा समूहीकृत कुछ टाइमस्टैम्प अनुक्रम हो सकते हैं।

यह 'count(distinct(date_trunc('month', ts)))'चयन के 'बाईं ओर' में दाईं ओर इस्तेमाल किया जा सकता है:

SELECT sum(a - b)/count(distinct(date_trunc('month', c))) FROM d

मैंने केवल संक्षिप्तता के लिए यहां generate_series () का उपयोग किया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.