अजगर में कुशल तिथि सीमा ओवरलैप गणना?


85

मेरे पास दो तारीख सीमाएं हैं जहां प्रत्येक सीमा एक शुरुआत और समाप्ति तिथि (जाहिर है, datetime.date () इंस्टेंस) द्वारा निर्धारित की जाती है। दो रेंज ओवरलैप कर सकते हैं या नहीं। मुझे ओवरलैप के दिनों की संख्या की आवश्यकता है। बेशक, मैं दोनों श्रेणियों के भीतर सभी तिथियों के साथ दो सेटों को पूर्व-भरण कर सकता हूं और एक सेट चौराहे का प्रदर्शन कर सकता हूं लेकिन यह संभवतः अक्षम है ... क्या सभी मामलों को कवर करने वाले लंबे-एलिफ अनुभाग का उपयोग करके एक और समाधान के अलावा एक बेहतर तरीका है?

जवाबों:


174
  • दो प्रारंभ तिथियों में से नवीनतम और दो अंतिम तिथियों में से सबसे पहले निर्धारित करें।
  • उन्हें घटाकर समयबद्धता की गणना करें।
  • यदि डेल्टा सकारात्मक है, तो यह ओवरलैप के दिनों की संख्या है।

यहाँ एक उदाहरण गणना है:

>>> from datetime import datetime
>>> from collections import namedtuple
>>> Range = namedtuple('Range', ['start', 'end'])

>>> r1 = Range(start=datetime(2012, 1, 15), end=datetime(2012, 5, 10))
>>> r2 = Range(start=datetime(2012, 3, 20), end=datetime(2012, 9, 15))
>>> latest_start = max(r1.start, r2.start)
>>> earliest_end = min(r1.end, r2.end)
>>> delta = (earliest_end - latest_start).days + 1
>>> overlap = max(0, delta)
>>> overlap
52

1
+1 बहुत अच्छा समाधान। हालांकि, यह उन तारीखों पर काफी काम नहीं करता है जो पूरी तरह से दूसरे में निहित हैं। पूर्णांक में सादगी के लिए: रेंज (1,4) और रेंज (2,3) रिटर्न 1
अंधेरा

3
@ डर्कलेस दरअसल, यह 2 रिटर्न करता है जो सही है । इन इनपुट्स को आज़माएं r1 = Range(start=datetime(2012, 1, 1), end=datetime(2012, 1, 4)); r2 = Range(start=datetime(2012, 1, 2), end=datetime(2012, 1, 3))। मुझे लगता है कि आप +1ओवरलैप गणना में चूक गए (आवश्यक है क्योंकि अंतराल दोनों छोर पर बंद है)।
रेमंड हेटिंगर

ओह, आप बिलकुल सही हैं, ऐसा लगता है कि मैं चूक गया हूं।
साभार

1
यदि आप 2 तारीखों के बजाय 2 बार गणना करना चाहते हैं तो क्या होगा?
एरिक

यदि आप दिन के लेखन के बजाय कई बार डेटाइम ऑब्जेक्ट का उपयोग करते हैं। .total_seconds () लिखें।
ErikXIII

10

फ़ंक्शन कॉल अंकगणितीय संचालन की तुलना में अधिक महंगे हैं।

ऐसा करने का सबसे तेज़ तरीका 2 घटाव और 1 मिनट () है:

min(r1.end - r2.start, r2.end - r1.start).days + 1

अगले सर्वश्रेष्ठ के साथ तुलना की जा रही है जिसमें 1 घटाव, 1 मिनट () और एक अधिकतम ():

(min(r1.end, r2.end) - max(r1.start, r2.start)).days + 1

बेशक दोनों अभिव्यक्तियों के साथ आपको अभी भी एक सकारात्मक ओवरलैप के लिए जांचना होगा।


1
यह विधि हमेशा सही उत्तर नहीं देगी। उदाहरण के लिए Range = namedtuple('Range', ['start', 'end']) r1 = Range(start=datetime(2016, 6, 15), end=datetime(2016, 6, 15)) r2 = Range(start=datetime(2016, 6, 11), end=datetime(2016, 6, 18)) print min(r1.end - r2.start, r2.end - r1.start).days + 14 प्रिंट होगा जहां इसे 1
tkyass

मुझे पहले समीकरण का उपयोग करके एक अस्पष्ट श्रृंखला त्रुटि मिलती है। क्या मुझे किसी विशेष पुस्तकालय की आवश्यकता है?
आर्थर डी। हाउलैंड

6

जैसा कि आप नीचे देख सकते हैं, मैंने TimeRange क्लास लागू की।

Get_overlapped_range पहले एक साधारण स्थिति द्वारा सभी गैर-अतिव्यापी विकल्पों की उपेक्षा करता है, और फिर सभी संभावित विकल्पों पर विचार करके अतिव्यापी सीमा की गणना करता है।

दिनों की राशि प्राप्त करने के लिए आपको TimeRange मान लेना होगा जो get_overlapped_range से लौटाया गया था और अवधि को 60 * 60 * 24 से विभाजित किया गया था।

class TimeRange(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.duration = self.end - self.start

    def is_overlapped(self, time_range):
        if max(self.start, time_range.start) < min(self.end, time_range.end):
            return True
        else:
            return False

    def get_overlapped_range(self, time_range):
        if not self.is_overlapped(time_range):
            return

        if time_range.start >= self.start:
            if self.end >= time_range.end:
                return TimeRange(time_range.start, time_range.end)
            else:
                return TimeRange(time_range.start, self.end)
        elif time_range.start < self.start:
            if time_range.end >= self.end:
                return TimeRange(self.start, self.end)
            else:
                return TimeRange(self.start, time_range.end)

    def __repr__(self):
        return '{0} ------> {1}'.format(*[time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(d))
                                          for d in [self.start, self.end]])

@ L.Guthardt सहमत हैं, लेकिन इस समाधान का आयोजन किया गया है, और अधिक कार्यक्षमता के साथ आ रहा है
Elad Sofer

1
ठीक है ... यह और अधिक कार्यक्षमता है, लेकिन वास्तव में StackOverflow पर एक जवाब सिर्फ ओपी की निर्दिष्ट आवश्यकताओं के अनुरूप होना चाहिए। तो कोई ज्यादा और कोई कम। :)
एल। गुटहार्ड

5

आप datetimerange पैकेज का उपयोग कर सकते हैं: https://pypi.org/project/DateTimeRange/

from datetimerange import DateTimeRange
time_range1 = DateTimeRange("2015-01-01T00:00:00+0900", "2015-01-04T00:20:00+0900") 
time_range2 = DateTimeRange("2015-01-01T00:00:10+0900", "2015-01-04T00:20:00+0900")
tem3 = time_range1.intersection(time_range2)
if tem3.NOT_A_TIME_STR == 'NaT':  # No overlap
    S_Time = 0
else: # Output the overlap seconds
    S_Time = tem3.timedelta.total_seconds()

DateTimeRange () के अंदर "2015-01-01T00: 00: 00 + 0900" भी टाइमस्टैम्प ('2017-08-30 20:36:25') की तरह डेटाइम फॉर्मेट हो सकता है।


1
धन्यवाद, बस DateTimeRangeपैकेज के लिए दस्तावेज़ीकरण पर एक नज़र थी और ऐसा लगता है कि वे समर्थन करते हैं is_intersectionजो मूल रूप से एक बूलियन मान लौटाता है (सही या गलत) इस बात पर निर्भर करता है कि दो तिथि सीमाओं के बीच एक चौराहा है या नहीं। इसलिए, आपके उदाहरण के लिए: यदि वे किसी और जगह पर time_range1.is_intersection(time_range2)लौट आएंगेTrueFalse
दीप


0
def get_overlap(r1,r2):
    latest_start=max(r1[0],r2[0])
    earliest_end=min(r1[1],r2[1])
    delta=(earliest_end-latest_start).days
    if delta>0:
        return delta+1
    else:
        return 0

0

ठीक है मेरा समाधान थोड़ा विस्की है क्योंकि मेरे डीएफ सभी श्रृंखलाओं का उपयोग करते हैं - लेकिन हम आपको निम्नलिखित कॉलम देते हैं, जिनमें से 2 निश्चित हैं जो आपका "फिस्कल ईयर" है। PoP "प्रदर्शन की अवधि" है जो आपका परिवर्तनशील डेटा है:

df['PoP_Start']
df['PoP_End']
df['FY19_Start'] = '10/1/2018'
df['FY19_End'] = '09/30/2019'

मान लें कि सभी डेटा डेटाइम फॉर्मेट में हैं -

df['FY19_Start'] = pd.to_datetime(df['FY19_Start'])
df['FY19_End'] = pd.to_datetime(df['FY19_End'])

ओवरलैप होने वाले दिनों की संख्या को खोजने के लिए निम्नलिखित समीकरणों को आज़माएं:

min1 = np.minimum(df['POP_End'], df['FY19_End'])
max2 = np.maximum(df['POP_Start'], df['FY19_Start'])

df['Overlap_2019'] = (min1 - max2) / np.timedelta64(1, 'D')
df['Overlap_2019'] = np.maximum(df['Overlap_2019']+1,0)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.