2009-04-20 15 views
18

मैं डेटटाइम को निकटतम 5 सेकंड में गोल करना चाहता हूं। इस तरह मैं वर्तमान में यह कर रहा हूं लेकिन मैं सोच रहा था कि क्या कोई बेहतर या अधिक संक्षिप्त तरीका था?क्या सी # में डेटटाइम को निकटतम 5 सेकंड तक बढ़ाने का कोई बेहतर तरीका है?

DateTime now = DateTime.Now; 
int second = 0; 

// round to nearest 5 second mark 
if (now.Second % 5 > 2.5) 
{ 
    // round up 
    second = now.Second + (5 - (now.Second % 5)); 
} 
else 
{ 
    // round down 
    second = now.Second - (now.Second % 5); 
} 

DateTime rounded = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, second); 

कृपया ध्यान दें कि मैं thesetwo पिछले प्रश्न मिल गया है, लेकिन वे बल्कि से दौर समय काटना।

उत्तर

29

दिनांक समय की Ticks गिनती 100-nanosecond अंतराल का प्रतिनिधित्व करता है, तो आप इस तरह निकटतम 50000000 टिक अंतराल को गोलाई द्वारा दौर निकटतम 5 सेकंड के लिए कर सकते हैं:

DateTime now = DateTime.Now; 
    DateTime rounded = new DateTime(((now.Ticks + 25000000)/50000000) * 50000000); 

कि अधिक संक्षिप्त है, लेकिन नहीं जरूरी है कि बेहतर। यह इस बात पर निर्भर करता है कि आप कोड स्पष्टता पर ब्रेवटी और गति पसंद करते हैं या नहीं। आपका समझने के लिए तर्कसंगत रूप से आसान है।

+4

यह अच्छी तरह से काम करता है क्योंकि निकटतम 5 के लिए गोलाकार 59 सेकंड 60 उत्पन्न करेगा, जिसे आप डेटटाइम कन्स्ट्रक्टर को 'सेकेंड' पैरामीटर के रूप में पास नहीं कर सकते हैं। इस तरह आप उस गड़बड़ी से बचें। –

+0

हाँ, यह एक अच्छा मुद्दा है - मुझे अपने कोड में उस समस्या को याद आया ... – Damovisa

+1

मेरे अपने उत्तर की आलोचना करने के लिए एक संभावित गड़बड़ी यह है कि मुझे यकीन नहीं है कि डेटटाइम लीप-सेकेंड के लिए कैसे खाता है। टिक गणना 12:00:00 आधी रात, 1 जनवरी, 0001 से मापा जाता है। तो तब से लीप सेकंड की संख्या के आधार पर और क्या डेटटाइम उनके लिए खाता है, तो आप पाएंगे कि परिणामी सेकेंड मान 5 का एक बहु नहीं है। – JayMcClellan

2

जैसा आपने बताया है, यह छोटा करना आसान है। तो, बस 2.5 सेकंड जोड़ें, फिर नीचे छोटा करें।

+0

मैं 2.5 सेकंड जोड़ दें, तो निकटतम 5 सेकंड के लिए काट-छांट और 2.5 सेकंड घटाना, मैं साथ 2.5sec, 7.5sec, 12.5sec आदि ... – Damovisa

+0

तो, अंतिम चरण के बाहर छोड़ने के (2.5 जोड़ने पहुंच जाएंगे सेकंड) काम करना चाहिए ... – Damovisa

1

मैं एक बेहतर तरीका के बारे में सोच सकते हैं नहीं है, हालांकि मैं शायद दौर विधि को अलग होगा:

static int Round(int n, int r) 
{ 
    if ((n % r) <= r/2) 
    { 
     return n - (n % r); 
    } 
    return n + (r - (n % r)); 
} 

इसके अलावा,% एक पूर्णांक देता है, तो एक छोटे से अजीब के रूप में 2.5 मुझे हमलों के साथ उसकी तुलना, भले ही यह सही है। मैं उपयोग करता हूं> = 3.

+0

हाँ का उपयोग करके पठनीयता में सुधार कर सकते हैं हाँ, मुझे पता है कि इसका मतलब 2.5 के साथ तुलना करने के साथ क्या है - यह थोड़ा असहज महसूस किया। जैसा कि आप कहते हैं, यह सही है हालांकि, और यह स्पष्ट करता है कि इरादा क्या है। 2.5 स्पष्ट रूप से 5 में से आधा है जबकि 3 फिट नहीं लगता है। – Damovisa

+0

मैं इस तरह के पूर्णांक को गोल करना पसंद करता हूं: '((एन + (आर >> 1))/आर) * आर' (गोल मध्यबिंदु ऊपर) या' ((एन + आर >> 1 - 1)/आर) * आर '(नीचे midpoints नीचे)। अगर मुझे पता है कि 'आर' अजीब है तो मैं केवल पहले का उपयोग करता हूं क्योंकि वे अजीब 'आर' के लिए भी काम करते हैं। यह दृष्टिकोण केवल एक विभाजन (बनाम 3) का उपयोग करता है और आपके फ़ंक्शन की तुलना में कोई शाखा नहीं है। –

1

मैं सी # और साबुन के एक बार के बीच के अंतर को पहचान नहीं पाया (ठीक है, जब मैं मूल रूप से यह उत्तर लिखा था, तो मैं वर्षों में काफी कुछ बदल गया था,) लेकिन, आप एक अधिक संक्षिप्त समाधान के लिए देख रहे हैं, मैं तो बस पूरी बात एक समारोह में डाल होगा - बहुत कम है कि एक साधारण कॉल कहा करने के लिए समारोह से अपने कोड में अधिक संक्षिप्त होगा:

DateTime rounded = roundTo5Secs (DateTime.Now); 

फिर आप फ़ंक्शन में जो कुछ भी चाहते हैं उसे डाल सकते हैं और यह दस्तावेज करते हैं कि यह कैसे काम करता है, जैसे कि (ये मानते हैं कि ये सभी पूर्णांक ऑपरेशंस हैं):

secBase = now.Second/5; 
secExtra = now.Second % 5; 
if (secExtra > 2) { 
    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 
     secBase + 5); 
} 
return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 
    secBase); 

यदि सेकबेज 60 तक जाता है तो आपको कुछ अतिरिक्त चेक की भी आवश्यकता हो सकती है (जब तक सी # डेटटाइम ऑब्जेक्ट्स मिनट को टक्कर देने के लिए पर्याप्त स्मार्ट नहीं होते हैं (और यदि मिनट 60 मिनट तक चलता है, और इसी तरह)।

+0

हाँ, उचित बिंदु। मैं यह करूँगा - मैंने अभी इस सवाल में स्पष्ट नहीं किया है। – Damovisa

+0

आपके लिए स्नान समय मुश्किल होना चाहिए ;-) –

+0

अच्छा एक, @ गॉर्डन, मैं सी # आजकल के बारे में थोड़ा और जानता हूं लेकिन स्नानघर _is_ बहुत मुश्किल है। यद्यपि मेरे हिस्से पर समन्वय की कमी के बजाए युवा बच्चों के साथ ऐसा करना अधिक है :-) – paxdiablo

1

इस बारे में कैसे (कुछ उत्तरों को एक साथ मिलाकर)? मुझे लगता है कि यह अर्थ अच्छी तरह से व्यक्त करता है और AddSeconds के कारण किनारे के मामलों (अगले मिनट तक घूमना) को संभालना चाहिए।

// truncate to multiple of 5 
int second = 5 * (int) (now.Second/5); 
DateTime dt = new DateTime(..., second); 

// round-up if necessary 
if (now.Second % 5 > 2.5) 
{ 
    dt = dt.AddSeconds(5); 
} 

Ticks दृष्टिकोण के रूप में जे के द्वारा दिखाया अधिक संक्षिप्त है, लेकिन थोड़ा कम पठनीय हो सकता है। यदि आप उस दृष्टिकोण का उपयोग करते हैं, कम से कम TimeSpan.TicksPerSecond संदर्भ।

+0

-1: मूल समय में एक सेकंड के अंश होने पर काम नहीं करता है। – Joe

+0

आप सही हैं। मैं पिछले संपादन में वापस आ गया था कि उस मामले को संभालने में अधिक स्पष्ट था –

+0

फिर हटाया गया -1! – Joe

46

(जी उठने के लिए क्षमा करें, मैं पहचान यह एक पुरानी है और सवाल का जवाब है - बस Google की खातिर के लिए कुछ अतिरिक्त कोड जोड़ने।)

मैं JayMcClellan's answer साथ शुरू किया था, लेकिन फिर मैं यह करने के लिए गोलाई, अधिक सामान्य बनना चाहता था मनमाने ढंग से अंतराल (केवल 5 सेकंड नहीं)। इसलिए मैंने जय की विधि को छोड़ दिया जो Math.Round का उपयोग टिकों पर करता है और इसे एक विस्तार विधि में डाल देता है जो मनमाने ढंग से अंतराल ले सकता है और राउंडिंग लॉजिक (बैंकर के गोलाकार बनाम दूर-शून्य) को बदलने का विकल्प भी प्रदान करता है।मैं मामले में यहाँ पोस्टिंग कर रहा हूँ इस किसी और रूप में अच्छी तरह करने के लिए उपयोगी है:

public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval, MidpointRounding roundingType) { 
     return new TimeSpan(
      Convert.ToInt64(Math.Round(
       time.Ticks/(decimal)roundingInterval.Ticks, 
       roundingType 
      )) * roundingInterval.Ticks 
     ); 
    } 

    public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval) { 
     return Round(time, roundingInterval, MidpointRounding.ToEven); 
    } 

    public static DateTime Round(this DateTime datetime, TimeSpan roundingInterval) { 
     return new DateTime((datetime - DateTime.MinValue).Round(roundingInterval).Ticks); 
    } 

यह नंगे दक्षता के लिए किसी भी पुरस्कार जीतने नहीं होगा, लेकिन मैं इसे पढ़ने के लिए आसान है और उपयोग करने के लिए अच्छा संकेत मिले। उदाहरण उपयोग:

new DateTime(2010, 11, 4, 10, 28, 27).Round(TimeSpan.FromMinutes(1)); // rounds to 2010.11.04 10:28:00 
new DateTime(2010, 11, 4, 13, 28, 27).Round(TimeSpan.FromDays(1)); // rounds to 2010.11.05 00:00 
new TimeSpan(0, 2, 26).Round(TimeSpan.FromSeconds(5)); // rounds to 00:02:25 
new TimeSpan(3, 34, 0).Round(TimeSpan.FromMinutes(37); // rounds to 03:42:00...for all your round-to-37-minute needs 
+0

शानदार, धन्यवाद - बस मैं जो खोज रहा था! – chris

+0

यह अच्छा कोड है * निकटतम * 'डेटटाइम 'के लिए घूमने के लिए, लेकिन मैं' राउंडिंग इंटरवल 'के एक से अधिक * को * ऊपर * करने की क्षमता भी चाहता हूं। मैंने' मिडपॉइंट राउंडिंग 'लेने के लिए' डेटटाइम 'ओवरलोड को संशोधित करने की कोशिश की और फिर इसे पास कर दिया अन्य अधिभार। लेकिन उसने वांछित क्षमता नहीं जोड़ा। – HappyNomad

+0

@HappyNomad 'MidpointRounding' केवल वास्तविक मध्य बिंदु पर होने पर ही खेल में आता है। यदि आप हमेशा गोल करना चाहते हैं, तो आपको एक अधिभार या परिवर्तन जोड़ना होगा 'Math.Round' के बजाय 'Math.Ceiling' का उपयोग करने के लिए पहला फ़ंक्शन, और' roundingType' को पूरी तरह से अनदेखा करें। –

0

तकनीकी तौर पर, आप कभी नहीं सही ढंग से एक अजीब अंतराल के दौर केवल सेकंड दिए सकते हैं।

2, 4, 6, 8, 10 < - कोई समस्या नहीं

आप अंतराल में कई बार 'वितरण' और अगर घबराना कम है, काट-छांट एक बहुत अधिक विनयशील है रहे हैं, तो कर रहे हैं।

यदि आप मिलीसेकंड पास कर सकते हैं और 500 एमएस चिह्न पर गोल कर सकते हैं, तो आप सेकेंड को अजीब करने में सक्षम होंगे और जिटर के तरीके को पूरी तरह खत्म कर देंगे या इसे पूरी तरह खत्म कर देंगे।

संबंधित मुद्दे