डेटाइम ऑब्जेक्ट के मिनट को गोल कैसे करें


102

I have a datetime object produced using strptime ()।

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

मुझे जो करना है वह मिनट को निकटतम 10 वें मिनट में करना है। जो मैं इस बिंदु पर कर रहा हूं वह मिनट मूल्य ले रहा था और उस पर गोल () का उपयोग कर रहा था।

min = round(tm.minute, -1)

हालाँकि, उपरोक्त उदाहरण के साथ, यह अमान्य समय देता है जब मिनट का मूल्य 56 से अधिक होता है। यानी: 3:60

ऐसा करने का एक बेहतर तरीका क्या है? क्या datetimeयह समर्थन करता है ?

जवाबों:


134

इससे datetimetm में संग्रहित किसी वस्तु का 'तल' पहले 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)

94

सेकंड में किसी भी समय एक डेटाइम को गोल करने के लिए सामान्य कार्य:

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

10
दुर्भाग्य से यह tz- अवगत डेटाटाइम के साथ काम नहीं करता है। एक का उपयोग करना चाहिए dt.replace(hour=0, minute=0, second=0)बजाय dt.min
skoval00

2
@ skoval00 + druska tz- अवगत डेटाटाइम का समर्थन करने के लिए आपकी सलाह के बाद संपादित। धन्यवाद!
Le Droid

धन्यवाद @ skoval00 - मुझे यह पता लगाने में थोड़ा समय लगा कि फ़ंक्शन मेरे डेटा के साथ काम क्यों नहीं कर रहा है
माइक सैंटोस

1
यह मेरे लिए लंबे समय तक काम नहीं करता है। जैसे 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)
CPBL

समस्या को समझने के लिए इसे देखें:datetime.timedelta(100,1,2,3).seconds == 1
CPBL

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

1
इसके अलावा कोई अच्छा नहीं है: 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
CPBL

3
अनुवर्ती ऊपर: बस यह इंगित करते हुए कि यह मनमाने समय के लिए काम नहीं करता है, जैसे कि 1 दिन से अधिक। यह प्रश्न राउंडिंग मिनट के बारे में है, इसलिए यह एक उपयुक्त प्रतिबंध है, लेकिन यह कोड लिखे जाने के तरीके में स्पष्ट हो सकता है।
CPBL

15

मैंने Stijn Nevens कोड का उपयोग किया (धन्यवाद Stijn) और साझा करने के लिए थोड़ा ऐड-ऑन किया। ऊपर, नीचे और पास की ओर गोल।

अपडेट 2019-03-09 = टिप्पणी शामिल करें स्पिनक्सज़ शामिल; धन्यवाद।

अद्यतन 2019-12-27 = टिप्पणी शामिल बार; धन्यवाद।

"X घंटे" या "X मिनट" या "X सेकंड" की date_delta के लिए परीक्षण किया गया।

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

इससे मुझे मदद मिली। मैं इसे जोड़ना चाहता हूं कि यदि इसका उपयोग PySpark में किया जाता है, तो दिनांक समय ऑब्जेक्ट के बजाय स्ट्रिंग के रूप में दिनांक समय को पार्स करने के लिए।
मैक्स

4
'अप' राउंडिंग शायद वह नहीं कर रहा है जिसकी ज्यादातर लोग उम्मीद करते हैं। आपको अगली तारीख_ तक का समय लगेगा, भले ही dt को गोलाई की आवश्यकता नहीं होगी: जैसे 15: 30: 00.000 राउंड_ के साथ = 60 बन जाएगा 15: 31: 00.000
spinxz

upराउंडिंग इस समारोह के साथ किसी भी तरह गलत है; 2019-11-07 14:39:00.776980साथ date_deltaबराबर 30 सेकंड और जैसे करने के लिए to='up'में परिणाम 2019-11-07 14:39:00
बार्ट

1
बहुत बहुत धन्यवाद!! हालांकि upगोलाई एक आम उपयोग नहीं हो सकता है, यह आवश्यक है जब आप अनुप्रयोग जो मिनट सीमा पर शुरू होता है के साथ काम कर रहे हैं
राहुल भारद्वाज

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

.. अगर आप स्ट्रिंग के रूप में परिणाम चाहते हैं। डेटाइम परिणाम प्राप्त करने के लिए, टाइमडेल्टा का उपयोग करना बेहतर है - अन्य प्रतिक्रियाएं देखें;)


आह, लेकिन फिर यहाँ समस्या यह है कि घंटे के रूप में अच्छी तरह से बढ़ना चाहिए
Lucas Manco

1
@ लुकास मानको - मेरा समाधान भी ठीक काम करता है और मुझे लगता है कि अधिक समझ में आता है।
सर्वव्यापी

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

def time_mod(time, delta, epoch=None):
    if epoch is None:
        epoch = dt.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, dt.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)

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

सबसे छोटा रास्ता मुझे पता है

मिनट = tm.minute // 10 * 10



0

एक सीधा दृष्टिकोण:

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

हां, यदि आपका डेटा किसी पांडा श्रृंखला में डेटटाइम कॉलम से संबंधित है, तो आप इसे अंतर्निहित pandas.Series.dt.round फ़ंक्शन का उपयोग करके गोल कर सकते हैं। यहाँ देखें दस्तावेज़ों को pandas.Series.dt.round पर । आपके 10min की राउंडिंग के मामले में यह Series.dt.round ('10min') या Series.dt.round ('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
जॉर्जी

हाँ, मुझे ये बताने के लिए धन्यवाद। यह मेरी गलती है कि मेरी प्रतिक्रिया में नमूने कोड शामिल नहीं हैं, और अन्य सभी लोगों की प्रतिक्रियाओं की भी जांच नहीं कर रहे हैं। मैं इस पहलू पर सुधार करने की कोशिश करूंगा।
गुयेन ब्रायन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.