मैं समय को निकटतम एक्स मिनटों तक कैसे गोल कर सकता हूं?


160

वहाँ गोलाई के लिए एक सरल कार्य है उत्तर प्रदेश एक DateTimeनिकटतम 15 मिनट के लिए?

उदाहरण के लिए

2011-08-11 16:59 हो जाता है 2011-08-11 17:00

2011-08-11 17:00 के रूप में रहता है 2011-08-11 17:00

2011-08-11 17:01 हो जाता है 2011-08-11 17:15

जवाबों:


287
DateTime RoundUp(DateTime dt, TimeSpan d)
{
    return new DateTime((dt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, dt.Kind);
}

उदाहरण:

var dt1 = RoundUp(DateTime.Parse("2011-08-11 16:59"), TimeSpan.FromMinutes(15));
// dt1 == {11/08/2011 17:00:00}

var dt2 = RoundUp(DateTime.Parse("2011-08-11 17:00"), TimeSpan.FromMinutes(15));
// dt2 == {11/08/2011 17:00:00}

var dt3 = RoundUp(DateTime.Parse("2011-08-11 17:01"), TimeSpan.FromMinutes(15));
// dt3 == {11/08/2011 17:15:00}

13
इस समाधान ने इसे विस्तार विधि के रूप में सिर्फ मेरी उपयोगिता पुस्तकालय में बनाया।
येल्टन

1
गोलाई के समय के लिए बाहर देखें जो ऊपरी चरम के पास हैं। यदि आपके द्वारा परिकलित Ticks DateTime.MaxValue.Ticks से अधिक है, तो यह एक अपवाद हो सकता है। सुरक्षित रहें और अपने परिकलित मूल्य और DateTime.MaxValue.Ticks का न्यूनतम उपयोग करें।
पॉल रफ़

4
क्या आप इस विधि से DateTime ऑब्जेक्ट से जानकारी नहीं खो रहे हैं? तरह और समय क्षेत्र की तरह, अगर वहाँ सेट कर रहे हैं?
एवरेन कुज़ुचोग्लू

11
@ user14 .. The (+ d.Ticks - 1) यह सुनिश्चित करता है कि यदि आवश्यक हो तो यह गोल हो जाएगा। / और * चक्कर लगा रहे हैं। उदाहरण के अगले 12 से अगले 5: (12 + 5 - 1) = 16,
16/5

12
@dtb एक छोटा सा जोड़, अन्यथा यह शायद थोड़ा खराब है: आपको DateTime RoundUp(DateTime dt, TimeSpan d) { return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks, dt.Kind); }
डेटाइम

107

एक ऐसे समाधान के साथ आया जिसमें संख्याओं को गुणा और विभाजित करना शामिल नहीं है long

public static DateTime RoundUp(this DateTime dt, TimeSpan d)
{
    var modTicks = dt.Ticks % d.Ticks;
    var delta = modTicks != 0 ? d.Ticks - modTicks : 0;
    return new DateTime(dt.Ticks + delta, dt.Kind);
}

public static DateTime RoundDown(this DateTime dt, TimeSpan d)
{
    var delta = dt.Ticks % d.Ticks;
    return new DateTime(dt.Ticks - delta, dt.Kind);
}

public static DateTime RoundToNearest(this DateTime dt, TimeSpan d)
{
    var delta = dt.Ticks % d.Ticks;
    bool roundUp = delta > d.Ticks / 2;
    var offset = roundUp ? d.Ticks : 0;

    return new DateTime(dt.Ticks + offset - delta, dt.Kind);
}

उपयोग:

var date = new DateTime(2010, 02, 05, 10, 35, 25, 450); // 2010/02/05 10:35:25
var roundedUp = date.RoundUp(TimeSpan.FromMinutes(15)); // 2010/02/05 10:45:00
var roundedDown = date.RoundDown(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
var roundedToNearest = date.RoundToNearest(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00

8
मैंने यह सुनिश्चित करने के लिए सोचा कि यह गुणा और भाग का उपयोग करने से अधिक तेज़ होगा, लेकिन मेरा परीक्षण दिखाता है कि यह नहीं है। 10000000 से अधिक पुनरावृत्तियों में, मापांक पद्धति ने मेरी मशीन पर ~ 610ms लिया, जबकि बहु / div विधि ने ~ 500ms लिया। मुझे लगता है कि FPUs पुराने के मुद्दों को गैर-मुद्दा बनाते हैं। यहाँ मेरा टेस्ट कोड है: pastie.org/8610460
viggity

1
एक्सटेंशन का शानदार उपयोग। धन्यवाद!
ट्रैविसडब्लड

1
@Alovchin धन्यवाद। मैंने जवाब अपडेट कर दिया है। मैंने अंतर दिखाने के लिए आपके कोड के साथ यह विचारधारा बनाई: ideone.com/EVKFp5
redent84

1
यह सुंदर पुराना है, लेकिन पिछले है %d.Ticksमें RoundUpआवश्यक? d.Ticks - (dt.Ticks % d.Ticks))जरूरी से कम होगा d.Ticks, इसलिए उत्तर एक ही सही होना चाहिए?
नैट डायमंड

1
बस इंगित करते हुए, मापांक सीपीयू पर एक विभाजन ऑपरेशन की आवश्यकता है। लेकिन मैं मानता हूं कि यह अधिक सुरुचिपूर्ण है कि पूर्णांक डिवीजनों की संपत्ति का उपयोग करना।
एलेक्स

19

यदि आपको एक निकटतम समय अंतराल (ऊपर नहीं) पर गोल करने की आवश्यकता है, तो मैं निम्नलिखित का उपयोग करने का सुझाव देता हूं

    static DateTime RoundToNearestInterval(DateTime dt, TimeSpan d)
    {
        int f=0;
        double m = (double)(dt.Ticks % d.Ticks) / d.Ticks;
        if (m >= 0.5)
            f=1;            
        return new DateTime(((dt.Ticks/ d.Ticks)+f) * d.Ticks);
    }

यह उत्तर ठीक से गोल नहीं है। user1978424 में एकमात्र पोस्ट है जो सही तरीके से दिखाता है कि नीचे दिए गए निकटतम अंतराल पर कैसे गोल किया जा सकता है: (विडंबना से नीचे-मतदान क्योंकि सवाल यूपी को गोल करने के लिए किया गया था)
stitty

8
void Main()
{
    var date1 = new DateTime(2011, 8, 11, 16, 59, 00);
    date1.Round15().Dump();

    var date2 = new DateTime(2011, 8, 11, 17, 00, 02);
    date2.Round15().Dump();

    var date3 = new DateTime(2011, 8, 11, 17, 01, 23);
    date3.Round15().Dump();

    var date4 = new DateTime(2011, 8, 11, 17, 00, 00);
    date4.Round15().Dump();
}

public static class Extentions
{
    public static DateTime Round15(this DateTime value)
    {   
        var ticksIn15Mins = TimeSpan.FromMinutes(15).Ticks;

        return (value.Ticks % ticksIn15Mins == 0) ? value : new DateTime((value.Ticks / ticksIn15Mins + 1) * ticksIn15Mins);
    }
}

परिणाम:

8/11/2011 5:00:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:00:00 PM

3
2011-08-11 17:00:01हो जाता है2011-08-11 17:00:00
Jyelton

1
@ येल्टन: +1 को इंगित करने के लिए धन्यवाद। मैंने उसे समायोजित करने के लिए अपना कोड बदल दिया।
व्लाद बेजेन 17

आसान सत्यापन के लिए अपना कोड Linqpad प्रारूप प्रदान करना एक महान समय बचाने वाला है। उपयोग करने के लिए बहुत आसान है।
एडम गार्नर

6

चूँकि मैं पहिए को फिर से लगाने से घृणा करता हूँ, मैं शायद इस एल्गोरिथ्म का पालन करने के लिए समय की एक निश्चित वृद्धि के लिए डेटटाइम मान को गोल करूँगा (टाइमपेन:

  • DateTimeएक फ़्लोटिंग फ़्लोर-पॉइंट मान पर गोल करने के लिए मान को TimeSpanइकाइयों की पूरी और आंशिक संख्या में बदलें ।
  • एक पूर्णांक के लिए गोल, का उपयोग कर Math.Round()
  • TimeSpanयूनिट में टिक्स की संख्या से गोल पूर्णांक को गुणा करके टिकों को वापस स्केल करें ।
  • टिक्कों DateTimeकी गोल संख्या से एक नया मान तुरंत प्राप्त करें और इसे कॉलर पर लौटाएं।

यहाँ कोड है:

public static class DateTimeExtensions
{

    public static DateTime Round( this DateTime value , TimeSpan unit )
    {
        return Round( value , unit , default(MidpointRounding) ) ;
    }

    public static DateTime Round( this DateTime value , TimeSpan unit , MidpointRounding style )
    {
        if ( unit <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("unit" , "value must be positive") ;

        Decimal  units        = (decimal) value.Ticks / (decimal) unit.Ticks ;
        Decimal  roundedUnits = Math.Round( units , style ) ;
        long     roundedTicks = (long) roundedUnits * unit.Ticks ;
        DateTime instance     = new DateTime( roundedTicks ) ;

        return instance ;
    }

}

यह करने के लिए गोलाई के लिए अच्छा कोड है निकटतम DateTime , लेकिन मैं यह भी दौर की क्षमता चाहते हैं अप की एक बहु के लिए unit । में पासिंग MidpointRounding.AwayFromZeroके लिए Roundवांछित प्रभाव नहीं है। क्या किसी MidpointRoundingतर्क को स्वीकार करने से आपके मन में कुछ और होता है ?
HappyNomad

2

मेरा संस्करण

DateTime newDateTimeObject = oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);

एक विधि के रूप में यह इस तरह लॉक होगा

public static DateTime GetNextQuarterHour(DateTime oldDateTimeObject)
{
    return oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);
}

और ऐसा ही कहा जाता है

DateTime thisIsNow = DateTime.Now;
DateTime nextQuarterHour = GetNextQuarterHour(thisIsNow);

यह सेकंड के लिए हिसाब नहीं करता है
एलेक्स नोरक्लिफ

1

सुरुचिपूर्ण?

dt.AddSeconds(900 - (x.Minute * 60 + x.Second) % 900)

1
एक और सही संस्करण होगा: x.AddSeconds (900 - (x.AddSeconds (-1) .Minute * 60 + x.AddSeconds (-1) .Second)% 900) .AddSeconds (-1), जो ध्यान रखता है। "रहता है" स्थिति।
ओलाफ

1

सावधानी: उपरोक्त सूत्र गलत है, अर्थात निम्नलिखित:

DateTime RoundUp(DateTime dt, TimeSpan d)
{
    return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks);
}

के रूप में फिर से लिखा जाना चाहिए:

DateTime RoundUp(DateTime dt, TimeSpan d)
{
    return new DateTime(((dt.Ticks + d.Ticks/2) / d.Ticks) * d.Ticks);
}

1
मैं असहमत हूं। चूंकि पूर्णांक विभाजन / d.Ticksनिकटतम 15-मिनट के अंतराल (चलो इन "ब्लॉक" को कॉल करता है) के लिए गोल हो जाता है, केवल आधा ब्लॉक जोड़ने से राउंडिंग की गारंटी नहीं होती है। विचार करें कि आपके पास 4.25 ब्लॉक कब हैं। यदि आप 0.5 ब्लॉक जोड़ते हैं, तो परीक्षण करें कि आपके पास कितने पूर्णांक ब्लॉक हैं, आपके पास अभी भी केवल 4. एक पूर्ण ब्लॉक से कम एक टिक जोड़ना सही कार्रवाई है। यह सुनिश्चित करता है कि आप हमेशा अगली ब्लॉक रेंज (नीचे चक्कर लगाने से पहले) तक बढ़ें, लेकिन आपको सटीक ब्लॉक के बीच जाने से रोकता है। (IE, यदि आपने 4.0 ब्लॉक में पूर्ण ब्लॉक जोड़ा है, तो 5.0 5 से गोल हो जाएगा, जब आप चाहते हैं 4. 4.99 4. होगा।)
ब्रेंडन मूर

1

एक अधिक वर्बोज़ समाधान, जो मोडुलो का उपयोग करता है और अनावश्यक गणना से बचता है।

public static class DateTimeExtensions
{
    public static DateTime RoundUp(this DateTime dt, TimeSpan ts)
    {
        return Round(dt, ts, true);
    }

    public static DateTime RoundDown(this DateTime dt, TimeSpan ts)
    {
        return Round(dt, ts, false);
    }

    private static DateTime Round(DateTime dt, TimeSpan ts, bool up)
    {
        var remainder = dt.Ticks % ts.Ticks;
        if (remainder == 0)
        {
            return dt;
        }

        long delta;
        if (up)
        {
            delta = ts.Ticks - remainder;
        }
        else
        {
            delta = -remainder;
        }

        return dt.AddTicks(delta);
    }
}

0

यह निकटतम 1 मिनट तक गोल करने के लिए एक सरल उपाय है। यह TimeZone और DateTime की तरह की जानकारी को संरक्षित करता है। इसे आगे अपनी आवश्यकताओं के अनुरूप संशोधित किया जा सकता है (यदि आपको निकटतम 5 मिनट, आदि के लिए गोल करने की आवश्यकता है)।

DateTime dbNowExact = DateTime.Now;
DateTime dbNowRound1 = (dbNowExact.Millisecond == 0 ? dbNowExact : dbNowExact.AddMilliseconds(1000 - dbNowExact.Millisecond));
DateTime dbNowRound2 = (dbNowRound1.Second == 0 ? dbNowRound1 : dbNowRound1.AddSeconds(60 - dbNowRound1.Second));
DateTime dbNow = dbNowRound2;

0

आप इस पद्धति का उपयोग कर सकते हैं, यह निर्दिष्ट तिथि का उपयोग करता है यह सुनिश्चित करने के लिए कि यह वैश्वीकरण और डेटाटाइम प्रकार में पहले से निर्दिष्ट डेटाइम ऑब्जेक्ट में से किसी को बनाए रखता है।

const long LNG_OneMinuteInTicks = 600000000;
/// <summary>
/// Round the datetime to the nearest minute
/// </summary>
/// <param name = "dateTime"></param>
/// <param name = "numberMinutes">The number minute use to round the time to</param>
/// <returns></returns>        
public static DateTime Round(DateTime dateTime, int numberMinutes = 1)
{
    long roundedMinutesInTicks = LNG_OneMinuteInTicks * numberMinutes;
    long remainderTicks = dateTime.Ticks % roundedMinutesInTicks;
    if (remainderTicks < roundedMinutesInTicks / 2)
    {
        // round down
        return dateTime.AddTicks(-remainderTicks);
    }

    // round up
    return dateTime.AddTicks(roundedMinutesInTicks - remainderTicks);
}

.नेट फिडेल टेस्ट

यदि आप TimeSpan को गोल करने के लिए उपयोग करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं।

/// <summary>
/// Round the datetime
/// </summary>
/// <example>Round(dt, TimeSpan.FromMinutes(5)); => round the time to the nearest 5 minutes.</example>
/// <param name = "dateTime"></param>
/// <param name = "roundBy">The time use to round the time to</param>
/// <returns></returns>        
public static DateTime Round(DateTime dateTime, TimeSpan roundBy)
{            
    long remainderTicks = dateTime.Ticks % roundBy.Ticks;
    if (remainderTicks < roundBy.Ticks / 2)
    {
        // round down
        return dateTime.AddTicks(-remainderTicks);
    }

    // round up
    return dateTime.AddTicks(roundBy.Ticks - remainderTicks);
}

टाइमस्पैन फिडल


क्या होगा यदि आप निकटतम 7 वें मिनट में गोल करना चाहते हैं var d = new DateTime(2019, 04, 15, 9, 40, 0, 0);// 9:42 होना चाहिए, लेकिन इनमें से कोई भी तरीका ऐसा काम नहीं करता है?
DotnetShadow

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