একটি ডেটটাইম অবজেক্টের মিনিটটি কীভাবে গোল করবেন


104

আমি datetimeব্যবহার করে উত্পাদিত একটি বস্তু আছে strptime()

>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)

আমার যা করতে হবে তা হ'ল মিনিটের কাছাকাছি দশম মিনিটের দিকে। আমি এখন পর্যন্ত যা করছি তা হ'ল মিনিট মান নিয়ে এবং এটিতে গোল () ব্যবহার করা।

min = round(tm.minute, -1)

তবে উপরের উদাহরণের মতো এটি যখন একটি মিনিটের মান ৫ 56 এর বেশি হয় তখন এটি একটি অবৈধ সময় দেয় ie যেমন: ৩:60০

এটি করার একটি ভাল উপায় কি? এটি কি datetimeসমর্থন করে?

উত্তর:


137

এটি এর datetimeআগে 10 মিনিটের চিহ্ন পর্যন্ত টিএম-এ সঞ্চিত কোনও বস্তুর 'তল' পাবে tm

tm = tm - datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)

আপনি যদি নিকটতম 10 মিনিটের চিহ্নটিতে ক্লাসিক রাউন্ডিং চান তবে এটি করুন:

discard = datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)
tm -= discard
if discard >= datetime.timedelta(minutes=5):
    tm += datetime.timedelta(minutes=10)

অথবা এটা:

tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
                         seconds=tm.second,
                         microseconds=tm.microsecond)

97

সেকেন্ডের মধ্যে যে কোনও সময় শেষ হওয়ার পরে ডেটটাইম গোল করতে সাধারণ ফাংশন:

def roundTime(dt=None, roundTo=60):
   """Round a datetime object to any time lapse in seconds
   dt : datetime.datetime object, default now.
   roundTo : Closest number of seconds to round to, default 1 minute.
   Author: Thierry Husson 2012 - Use it as you want but don't blame me.
   """
   if dt == None : dt = datetime.datetime.now()
   seconds = (dt.replace(tzinfo=None) - dt.min).seconds
   rounding = (seconds+roundTo/2) // roundTo * roundTo
   return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

1 ঘন্টা বৃত্তাকার এবং 30 মিনিটের বৃত্তাকার সহ নমুনাগুলি:

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60)
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60)
2012-12-31 23:30:00

11
দুর্ভাগ্যক্রমে এটি tz- সচেতন তারিখের সাথে কাজ করে না। dt.replace(hour=0, minute=0, second=0)পরিবর্তে এক ব্যবহার করা উচিত dt.min
skoval00

4
@ স্কোভাল 100 + ড্রুসকা টিজে-সচেতন ডেটটাইম সমর্থন করার জন্য আপনার পরামর্শ অনুসরণ করে সম্পাদিত। ধন্যবাদ!
লে ড্রয়েড

ধন্যবাদ @ স্কোভাল 100 - ফাংশনটি কেন আমার ডেটা নিয়ে কাজ করছে না তা বুঝতে সময় লাগল
মিশেল মেসকুইটা

4
এটি দীর্ঘকাল আমার পক্ষে মোটেও কাজ করে না। যেমন roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60*24*7)বনামroundTime(datetime.datetime(2012,12,30,23,44,59,1234),roundTo=60*60*24*7)
সিপিবিএল

সমস্যাটি বোঝার জন্য এটি দেখুন:datetime.timedelta(100,1,2,3).seconds == 1
সিপিবিএল

16

আমি স্টিজন নেভেনস কোডটি ব্যবহার করেছি (ধন্যবাদ স্টিজন) এবং ভাগ করার জন্য কিছুটা অ্যাড-অন রয়েছে। গোলাকার, নীচে এবং কাছাকাছি গোলাকার।

আপডেট 2019-03-09 = মন্তব্য স্পিনিক্স অন্তর্ভুক্ত; ধন্যবাদ.

আপডেট 2019-12-27 = মন্তব্য বার্ট অন্তর্ভুক্ত; ধন্যবাদ.

"এক্স ঘন্টা" বা "এক্স মিনিট" বা "এক্স সেকেন্ড" এর তারিখ_ডেলটার জন্য পরীক্ষিত।

import datetime

def round_time(dt=None, date_delta=datetime.timedelta(minutes=1), to='average'):
    """
    Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    from:  http://stackoverflow.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python
    """
    round_to = date_delta.total_seconds()
    if dt is None:
        dt = datetime.now()
    seconds = (dt - dt.min).seconds

    if seconds % round_to == 0 and dt.microsecond == 0:
        rounding = (seconds + round_to / 2) // round_to * round_to
    else:
        if to == 'up':
            # // is a floor division, not a comment on following line (like in javascript):
            rounding = (seconds + dt.microsecond/1000000 + round_to) // round_to * round_to
        elif to == 'down':
            rounding = seconds // round_to * round_to
        else:
            rounding = (seconds + round_to / 2) // round_to * round_to

    return dt + datetime.timedelta(0, rounding - seconds, - dt.microsecond)

# test data
print(round_time(datetime.datetime(2019,11,1,14,39,00), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,2,14,39,00,1), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,3,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,4,14,39,29,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2018,11,5,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2018,11,6,14,38,59,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2017,11,7,14,39,15), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2017,11,8,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2019,11,9,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2012,12,10,23,44,59,7769),to='average'))
print(round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up'))
print(round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2012,12,14,23,44,59),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,15,23,44,59),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,16,23,44,59),date_delta=datetime.timedelta(hours=1)))
print(round_time(datetime.datetime(2012,12,17,23,00,00),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,18,23,00,00),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,19,23,00,00),date_delta=datetime.timedelta(hours=1)))

এটি আমাকে সাহায্য করেছিল। আমি এটি যুক্ত করতে চাই যদি এটি পিএসপার্কে ব্যবহার করে থাকে তবে তারিখের সময়কে বস্তুর পরিবর্তে তারিখের সময়টিকে স্ট্রিং হিসাবে পার্স করতে।
সর্বোচ্চ

4
'আপ' রাউন্ডিং সম্ভবত বেশিরভাগ লোকেরা প্রত্যাশা মতো করছে না। আপনি পরবর্তী তারিখ_দেল্টা পর্যন্ত গোল করবেন এমনকি ডিটি রাউন্ডিংয়ের দরকার পড়েনি: যেমন 15: 30: 00.000 = গোল_তো = 60 দিয়ে 15 হবে: 31: 00.000
স্পিনেক্সz

upরাউন্ডইং এই ফাংশন সঙ্গে কোন উপায়ে বেঠিক হয়; 2019-11-07 14:39:00.776980সঙ্গে date_deltaসমান 30 সেকেন্ড এবং যেমন করতে to='up'ফলাফল 2019-11-07 14:39:00
বার্ট

4
অনেক ধন্যবাদ!! যদিও uprounding একটি সাধারণ ব্যবহারের ক্ষেত্রে নাও হতে পারে, এটা প্রয়োজন হয় যখন আপনি অ্যাপ্লিকেশান যা মিনিট সীমানা শুরু হয় সাথে ডিল করা হয়
রাহুল ভরদ্বাজ

15

কেবলমাত্র ডেটটাইম অবজেক্ট ব্যবহার করে সেরা উত্তর থেকে আমি একটি অভিযোজিত সংস্করণে সংশোধন করেছি, এটি সেকেন্ডে রূপান্তরটি করা এড়িয়ে যায় এবং কলিং কোডটি আরও পঠনযোগ্য করে তোলে:

def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)):
    """Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    Author: Thierry Husson 2012 - Use it as you want but don't blame me.
            Stijn Nevens 2014 - Changed to use only datetime objects as variables
    """
    roundTo = dateDelta.total_seconds()

    if dt == None : dt = datetime.datetime.now()
    seconds = (dt - dt.min).seconds
    # // is a floor division, not a comment on following line:
    rounding = (seconds+roundTo/2) // roundTo * roundTo
    return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

1 ঘন্টা বৃত্তাকার এবং 15 মিনিটের বৃত্তাকার সহ নমুনাগুলি:

print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1))
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15))
2012-12-31 23:30:00

4
এছাড়াও কোনও ভাল নয়: print roundTime(datetime.datetime(2012,12,20,23,44,49),datetime.timedelta(days=15)) 2012-12-20 00:00:00যখনprint roundTime(datetime.datetime(2012,12,21,23,44,49),datetime.timedelta(days=15)) 2012-12-21 00:00:00
সিপিবিএল

4
উপরের দিকে অনুসরণ করুন: কেবল ইঙ্গিত করে যে এটি নির্বিচারে সময় ডেল্টাসের জন্য কাজ করে না, যেমন 1 দিনের বেশি। এই প্রশ্নটি গোল করার মিনিট সম্পর্কে, সুতরাং এটি একটি উপযুক্ত বিধিনিষেধ, তবে কোডটি কীভাবে রচিত হয়েছে তা আরও পরিষ্কার হতে পারে।
সিপিবিল

5

পান্ডসের একটি ডেটটাইম রাউন্ড বৈশিষ্ট্য রয়েছে তবে পান্ডসের বেশিরভাগ জিনিসের মতো এটি সিরিজের ফর্ম্যাটে থাকা দরকার।

>>> ts = pd.Series(pd.date_range(Dt(2019,1,1,1,1),Dt(2019,1,1,1,4),periods=8))
>>> print(ts)
0   2019-01-01 01:01:00.000000000
1   2019-01-01 01:01:25.714285714
2   2019-01-01 01:01:51.428571428
3   2019-01-01 01:02:17.142857142
4   2019-01-01 01:02:42.857142857
5   2019-01-01 01:03:08.571428571
6   2019-01-01 01:03:34.285714285
7   2019-01-01 01:04:00.000000000
dtype: datetime64[ns]

>>> ts.dt.round('1min')
0   2019-01-01 01:01:00
1   2019-01-01 01:01:00
2   2019-01-01 01:02:00
3   2019-01-01 01:02:00
4   2019-01-01 01:03:00
5   2019-01-01 01:03:00
6   2019-01-01 01:04:00
7   2019-01-01 01:04:00
dtype: datetime64[ns]

ডক্স - প্রয়োজনীয়তা হিসাবে ফ্রিকোয়েন্সি স্ট্রিং পরিবর্তন করুন।


রেফারেন্সের জন্য, Timestampরয়েছে floorএবং ceilপাশাপাশি
poulter7

3

আপনি যদি শর্তটি ব্যবহার করতে না চান তবে আপনি moduloঅপারেটরটি ব্যবহার করতে পারেন :

minutes = int(round(tm.minute, -1)) % 60

হালনাগাদ

তুমি কি এরকম কিছু চাও?

def timeround10(dt):
    a, b = divmod(round(dt.minute, -1), 60)
    return '%i:%02i' % ((dt.hour + a) % 24, b)

timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56
# -> 1:00

timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56
# -> 0:00

.. আপনি যদি স্ট্রিং হিসাবে ফলাফল চান। ডেটটাইম ফলাফল পাওয়ার জন্য, টাইমডেল্টা ব্যবহার করা আরও ভাল - অন্যান্য প্রতিক্রিয়াগুলি দেখুন;)


আহ তবে তারপরে এখানে সমস্যাটি হ'ল
সময়টি

4
@ লুকাস ম্যানকো - আমার সমাধানটিও ভাল কাজ করে এবং আমি মনে করি এটি আরও বুদ্ধিমান।
সর্বজনীন

2

আমি এটি ব্যবহার করছি tz সচেতন তারিখের সময় নিয়ে কাজ করার সুবিধা রয়েছে।

def round_minutes(some_datetime: datetime, step: int):
    """ round up to nearest step-minutes """
    if step > 60:
        raise AttrbuteError("step must be less than 60")

    change = timedelta(
        minutes= some_datetime.minute % step,
        seconds=some_datetime.second,
        microseconds=some_datetime.microsecond
    )

    if change > timedelta():
        change -= timedelta(minutes=step)

    return some_datetime - change

এটির জন্য শুধুমাত্র এক ঘণ্টারও বেশি সময়সীমার জন্য কাজ করার অসুবিধা রয়েছে।


2

এখানে ভাসমান পয়েন্ট যথার্থ সমস্যা এবং বাহ্যিক গ্রন্থাগার নির্ভরতা ছাড়াই একটি সাধারণ সাধারণ সমাধান:

import datetime

def time_mod(time, delta, epoch=None):
    if epoch is None:
        epoch = datetime.datetime(1970, 1, 1, tzinfo=time.tzinfo)
    return (time - epoch) % delta

def time_round(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod < (delta / 2):
       return time - mod
    return time + (delta - mod)

আপনার ক্ষেত্রে:

>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)

1

একটি সরল পদ্ধতি:

def round_time(dt, round_to_seconds=60):
    """Round a datetime object to any number of seconds
    dt: datetime.datetime object
    round_to_seconds: closest number of seconds for rounding, Default 1 minute.
    """
    rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
    rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
    return rounded_dt

0
def get_rounded_datetime(self, dt, freq, nearest_type='inf'):

    if freq.lower() == '1h':
        round_to = 3600
    elif freq.lower() == '3h':
        round_to = 3 * 3600
    elif freq.lower() == '6h':
        round_to = 6 * 3600
    else:
        raise NotImplementedError("Freq %s is not handled yet" % freq)

    # // is a floor division, not a comment on following line:
    seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second
    if nearest_type == 'inf':
        rounded_sec = int(seconds_from_midnight / round_to) * round_to
    elif nearest_type == 'sup':
        rounded_sec = (int(seconds_from_midnight / round_to) + 1) * round_to
    else:
        raise IllegalArgumentException("nearest_type should be  'inf' or 'sup'")

    dt_midnight = datetime.datetime(dt.year, dt.month, dt.day)

    return dt_midnight + datetime.timedelta(0, rounded_sec)

0

স্টিজন নেভেনসের উপর ভিত্তি করে এবং জ্যাঙ্গো ব্যবহারের জন্য সংশোধিত বর্তমান সময়টি নিকটতম 15 মিনিটের দিকে চালিত করে।

from datetime import date, timedelta, datetime, time

    def roundTime(dt=None, dateDelta=timedelta(minutes=1)):

        roundTo = dateDelta.total_seconds()

        if dt == None : dt = datetime.now()
        seconds = (dt - dt.min).seconds
        # // is a floor division, not a comment on following line:
        rounding = (seconds+roundTo/2) // roundTo * roundTo
        return dt + timedelta(0,rounding-seconds,-dt.microsecond)

    dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S')

 dt = 11:45:00

আপনার যদি পূর্ণ তারিখ এবং সময় প্রয়োজন হয় কেবল এটিকে সরিয়ে দিন .strftime('%H:%M:%S')


0

ব্যতিক্রম ধরা পড়লে গতির পক্ষে সেরা নয় তবে এটি কাজ করবে।

def _minute10(dt=datetime.utcnow()):
    try:
        return dt.replace(minute=round(dt.minute, -1))
    except ValueError:
        return dt.replace(minute=0) + timedelta(hours=1)

সময়

%timeit _minute10(datetime(2016, 12, 31, 23, 55))
100000 loops, best of 3: 5.12 µs per loop

%timeit _minute10(datetime(2016, 12, 31, 23, 31))
100000 loops, best of 3: 2.21 µs per loop

0

একটি datetimeঅবজেক্টের জন্য একটি সেকেন্ডে এখানে নির্দিষ্ট সময় ইউনিটে গোল করার জন্য একটি দুটি লাইন স্বজ্ঞাত সমাধান t:

format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)

আপনি যদি কোনও ভিন্ন ইউনিটে গোল করতে চান তবে কেবল পরিবর্তন করুন format_str

এই পদ্ধতির উপরোক্ত পদ্ধতিগুলির মতো নির্বিচারে সময়ের পরিমাণের সাথে গোল হয় না তবে এটি একটি নির্দিষ্ট ঘন্টা, মিনিট বা সেকেন্ডে গোল করার এক দুর্দান্ত পাইথোনিক উপায়।


0

অন্যান্য সমাধান:

def round_time(timestamp=None, lapse=0):
    """
    Round a timestamp to a lapse according to specified minutes

    Usage:

    >>> import datetime, math
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
    datetime.datetime(2010, 6, 10, 3, 56)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
    datetime.datetime(2010, 6, 10, 3, 57)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
    datetime.datetime(2010, 6, 10, 3, 55)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
    datetime.datetime(2019, 3, 11, 9, 24)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
    datetime.datetime(2019, 3, 11, 12, 0)
    >>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
    datetime.datetime(2019, 3, 11, 10, 0)

    :param timestamp: Timestamp to round (default: now)
    :param lapse: Lapse to round in minutes (default: 0)
    """
    t = timestamp or datetime.datetime.now()  # type: Union[datetime, Any]
    surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
    t -= surplus
    try:
        mod = t.minute % lapse
    except ZeroDivisionError:
        return t
    if mod:  # minutes % lapse != 0
        t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
    elif surplus != datetime.timedelta() or lapse < 0:
        t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
    return t

আশাকরি এটা সাহায্য করবে!




0

হ্যাঁ, যদি আপনার ডেটা কোনও পান্ডাস সিরিজের কোনও ডেটটাইম কলামের অন্তর্ভুক্ত থাকে তবে আপনি অন্তর্নির্মিত পান্ডাস.সারিজ.ডট.উইন্ড ফাংশনটি ব্যবহার করে এটিকে গোল করে নিতে পারেন। পান্ডাস.সুরি.ডট.উইন্ডে এখানে ডকুমেন্টেশন দেখুন । আপনার 10 মিনিটে রাউন্ডিংয়ের ক্ষেত্রে এটি সিরিজ.ডেট.উন্ড ("10 মিনিট") বা সিরিজ.ডেট.াউন্ড ('600s') এর মতো হবে:

pandas.Series(tm).dt.round('10min')

উদাহরণ কোড যুক্ত করতে সম্পাদনা করুন:

import datetime
import pandas

tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)

>>> 0   2010-06-10 04:00:00
dtype: datetime64[ns]

আমি নিশ্চিত নই যে এই উত্তরটি নতুন বা দরকারী কিছু যুক্ত করেছে। ইতিমধ্যে একটি উত্তর ছিল যা একই জিনিসটি ব্যাখ্যা করেছিল: stackoverflow.com/a/56010357/7851470
জর্জি

হ্যাঁ, এগুলি আমার দিকে নির্দেশ করার জন্য আপনাকে ধন্যবাদ। আমার প্রতিক্রিয়াতে নমুনা কোডটি অন্তর্ভুক্ত না করা এবং অন্য সমস্ত লোকের প্রতিক্রিয়া যাচাই না করার জন্য এটি আমার ভুল। আমি এই দিকটি উন্নত করার চেষ্টা করব।
এনগুইন ব্রায়ান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.