পাইথনে দক্ষ তারিখের পরিসীমা ওভারল্যাপ গণনা?


85

আমার দুটি তারিখের ব্যাপ্তি রয়েছে যেখানে প্রতিটি ব্যাপ্তি একটি শুরু এবং শেষের তারিখ (স্পষ্টতই ডেটটাইম.ডেট () উদাহরণ) দ্বারা নির্ধারিত হয়। দুটি রেঞ্জ ওভারল্যাপ করতে পারে বা না পারে। আমার ওভারল্যাপের দিনগুলির সংখ্যা প্রয়োজন। অবশ্যই আমি উভয় ব্যাপ্তির মধ্যে সমস্ত তারিখের সাথে দুটি সেট প্রি-ফিল করতে পারি এবং একটি সেট ছেদটি সম্পাদন করতে পারি তবে এটি সম্ভবত অদক্ষ ... ... দীর্ঘ ক্ষেত্রে যদি এলিফ অংশটি সমস্ত ক্ষেত্রে আবৃত করে তবে অন্য সমাধান ছাড়া আরও ভাল উপায় আছে কি?

উত্তর:


175
  • দুটি শুরুর তারিখের সর্বশেষতম এবং দুটি শেষের তারিখের প্রথমতম নির্ধারণ করুন।
  • টাইমডেল্টাকে বিয়োগ করে গণনা করুন।
  • যদি ব-দ্বীপটি ইতিবাচক হয়, তবে এটি ওভারল্যাপের দিনগুলির সংখ্যা।

এখানে একটি উদাহরণ গণনা:

>>> 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

4
+1 খুব সুন্দর সমাধান। যদিও, এটি সম্পূর্ণরূপে অন্যটিতে থাকা তারিখগুলিতে কার্যকরভাবে কাজ করে না। পূর্ণসংখ্যার সরলতার জন্য: ব্যাপ্তি (1,4) এবং ব্যাপ্তি (2,3) 1
অন্ধকার

4
@ ডার্কলেস আসলে, এটি 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ওভারল্যাপের গণনায় মিস করেছেন (প্রয়োজনীয় কারণ বিরতি দুটি প্রান্তে বন্ধ রয়েছে)।
রেমন্ড হেটেঞ্জার

ওহ, আপনি একেবারে ঠিক বলেছেন, মনে হচ্ছে আমি এটি মিস করেছি। আপনাকে ধন্যবাদ :)
অন্ধকার

4
আপনি যদি 2 তারিখের পরিবর্তে 2 বার গণনা করতে চান? @ রেমন্ড হিট্টিংগার
এরিক

4
আপনি যদি ডেটটাইম অবজেক্টগুলি সময়ের সাথে ব্যবহার করেন তবে .days পরিবর্তে লিখতে পারেন।
এরিক XIII

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

অবশ্যই উভয় এক্সপ্রেশন সহ আপনার এখনও একটি ইতিবাচক ওভারল্যাপ পরীক্ষা করা দরকার।


4
এই পদ্ধতিটি সর্বদা সঠিক উত্তর দেয় না। উদাহরণস্বরূপ 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
টিওয়াইয়াস

আমি প্রথম সমীকরণটি ব্যবহার করে একটি অস্পষ্ট সিরিজের ত্রুটি পেয়েছি। আমার কি বিশেষ গ্রন্থাগার দরকার?
আর্থার ডি হাওল্যান্ড

6

আপনি নীচে দেখতে পারেন হিসাবে আমি একটি টাইমঞ্জের শ্রেণি প্রয়োগ করেছি।

Get_overlaped_range প্রথমে একটি সাধারণ শর্ত দ্বারা সমস্ত অ ওভারল্যাপযুক্ত বিকল্পগুলিকে অগ্রাহ্য করে এবং তারপরে সমস্ত সম্ভাব্য বিকল্প বিবেচনা করে ওভারল্যাপযুক্ত পরিসীমা গণনা করে।

দিনের পরিমাণ পাওয়ার জন্য আপনাকে get_overlaped_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]])

@ এল। গুথার্ট सहमत হয়েছে, তবে এই সমাধানটি সংগঠিত হয়েছে এবং আরও কার্যকারিতা নিয়ে আসছে
এলাদ সোফার

4
ঠিক আছে ... এটি আরও কার্যকারিতা সুন্দর, তবে আসলে স্ট্যাকওভারফ্লোতে একটি উত্তর কেবল ওপি'র নির্দিষ্ট প্রয়োজনীয়তার সাথে মাপসই করা উচিত। তাই আর কম না। :)
এল গথার্ট

5

আপনি ডেটটাইমেনজ প্যাকেজটি ব্যবহার করতে পারেন: 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()

"2015-01-01T00: 00: 00 + 0900" ডেটটাইমরেঞ্জের অভ্যন্তরে () টাইমস্ট্যাম্পের মতো ডেটটাইম ফর্ম্যাটও হতে পারে ('2017-08-30 20:36:25')।


4
ধন্যবাদ, 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 টি স্থির হয়েছে যা আপনার "আর্থিক বছর"। পিওপি হ'ল "পারফরম্যান্স পিরিয়ড" যা আপনার পরিবর্তনশীল ডেটা:

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)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.