2010-06-19 20 views
5

मैं आईफोन के लिए एक जीटीडी ऐप लिख रहा हूं। उचित कार्यों के लिए, मैं "कल कल" या "कल कल" या "18 जुलाई के कारण" जैसे कुछ प्रदर्शित करना चाहता हूं। जाहिर है, मुझे "कल" ​​प्रदर्शित करने की ज़रूरत है, भले ही कार्य 24 घंटे से कम हो (उदाहरण के लिए उपयोगकर्ता शनिवार को 11 बजे चेक करता है और देखता है कि रविवार को 8 बजे एक कार्य है)। इसलिए, मैंने दो तिथियों के बीच दिनों की संख्या प्राप्त करने के लिए एक विधि लिखी। यहाँ कोड है ...आईफोन - दो तिथियों के बीच दिनों की संख्या प्राप्त करें

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
[dateFormatter setDateFormat:@"yyyy-MM-dd-HH-mm"]; 

NSDate *nowDate = [dateFormatter dateFromString:@"2010-01-01-15-00"]; 
NSDate *dueDate = [dateFormatter dateFromString:@"2010-01-02-14-00"]; 

NSLog(@"NSDate *nowDate = %@", nowDate); 
NSLog(@"NSDate *dueDate = %@", dueDate); 

NSCalendar *calendar = [NSCalendar currentCalendar]; 

NSDateComponents *differenceComponents = [calendar components:(NSDayCalendarUnit) 
                fromDate:nowDate 
                 toDate:dueDate 
                 options:0]; 

NSLog(@"Days between dates: %d", [differenceComponents day]); 

... और यहां उत्पादन है:

NSDate *nowDate = 2010-01-01 15:00:00 -0700 
NSDate *dueDate = 2010-01-02 14:00:00 -0700 
Days between dates: 0 

आप देख सकते हैं, विधि गलत परिणाम देता है। इसे दो दिनों के बीच दिनों की संख्या के रूप में 1 वापस करना चाहिए था। मुझसे यहां क्या गलत हो रहा है?

संपादित करें: मैंने एक और तरीका लिखा है। मैं व्यापक इकाई परीक्षण नहीं किया है, लेकिन अभी तक यह काम करने लगता है:

+ (NSInteger)daysFromDate:(NSDate *)fromDate inTimeZone:(NSTimeZone *)fromTimeZone untilDate:(NSDate *)toDate inTimeZone:(NSTimeZone *)toTimeZone { 

    NSCalendar *calendar = [NSCalendar currentCalendar]; 
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; 

    [calendar setTimeZone:fromTimeZone]; 
    NSDateComponents *fromDateComponents = [calendar components:unitFlags fromDate:fromDate]; 

    [calendar setTimeZone:toTimeZone]; 
    NSDateComponents *toDateComponents = [calendar components:unitFlags fromDate:toDate]; 

    [calendar setTimeZone:[NSTimeZone defaultTimeZone]]; 
    NSDate *adjustedFromDate = [calendar dateFromComponents:fromDateComponents]; 
    NSDate *adjustedToDate = [calendar dateFromComponents:toDateComponents]; 

    NSTimeInterval timeIntervalBetweenDates = [adjustedToDate timeIntervalSinceDate:adjustedFromDate]; 
    NSInteger daysBetweenDates = (NSInteger)(timeIntervalBetweenDates/(60.0 * 60.0 * 24.0)); 

    NSDateComponents *midnightBeforeFromDateComponents = [[NSDateComponents alloc] init]; 
    [midnightBeforeFromDateComponents setYear:[fromDateComponents year]]; 
    [midnightBeforeFromDateComponents setMonth:[fromDateComponents month]]; 
    [midnightBeforeFromDateComponents setDay:[fromDateComponents day]]; 

    NSDate *midnightBeforeFromDate = [calendar dateFromComponents:midnightBeforeFromDateComponents]; 
    [midnightBeforeFromDateComponents release]; 

    NSDate *midnightAfterFromDate = [[NSDate alloc] initWithTimeInterval:(60.0 * 60.0 * 24.0) 
                   sinceDate:midnightBeforeFromDate]; 

    NSTimeInterval timeIntervalBetweenToDateAndMidnightBeforeFromDate = [adjustedToDate timeIntervalSinceDate:midnightBeforeFromDate]; 
    NSTimeInterval timeIntervalBetweenToDateAndMidnightAfterFromDate = [adjustedToDate timeIntervalSinceDate:midnightAfterFromDate]; 

    if (timeIntervalBetweenToDateAndMidnightBeforeFromDate < 0.0) { 

     // toDate is before the midnight before fromDate 

     timeIntervalBetweenToDateAndMidnightBeforeFromDate -= daysBetweenDates * 60.0 * 60.0 * 24.0; 

     if (timeIntervalBetweenToDateAndMidnightBeforeFromDate < 0.0) 
      daysBetweenDates -= 1; 
    } 
    else if (timeIntervalBetweenToDateAndMidnightAfterFromDate >= 0.0) { 

     // toDate is after the midnight after fromDate 

     timeIntervalBetweenToDateAndMidnightAfterFromDate -= daysBetweenDates * 60.0 * 60.0 * 24.0; 

     if (timeIntervalBetweenToDateAndMidnightAfterFromDate >= 0.0) 
      daysBetweenDates += 1; 
    } 

    [midnightAfterFromDate release]; 

    return daysBetweenDates; 
} 

उत्तर

3

डॉक्स से components:fromDate:toDate:options: के लिए:

परिणाम हानिपूर्ण है अगर वहाँ एक छोटा सा पर्याप्त इकाई करने का अनुरोध नहीं है अंतर की पूरी परिशुद्धता पकड़ो।

चूंकि अंतर पूरे दिन से कम है, यह सही ढंग से 0 दिनों का परिणाम देता है।

+0

ठीक है, शब्द के लिए मेरे सवाल का अलग तरह से, मैं कैसे जांच कर सकते हैं कि कितने midnights मेरे दो तिथियों के बीच कर रहे थे? – Tim

2

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

ऐसा करने के लिए, तारीखों की तुलना करें जो पहले है और जो बाद में है (और यदि वे बराबर तुलना करते हैं, तो उस परिणाम के साथ जमानत की तुलना करें), फिर परीक्षण करें कि पहले की तारीख के 1 दिन उसी वर्ष के साथ एक तिथि उत्पन्न करती है या नहीं , महीने, और दिन की तारीख बाद की तारीख के रूप में।

  1. कैलेंडर एक components:fromDate: संदेश भेजें वर्ष, माह, और दिन पाने के लिए:


    तुम सच में जानना कि उनकी संख्या कितनी कैलेंडर दिनों वहाँ एक तारीख से दूसरे के लिए कर रहे हैं चाहते हैं, तो पहली तारीख के महीने के।

  2. # 1 के समान, लेकिन दूसरी तारीख के लिए।
  3. यदि दो तिथियां एक ही वर्ष और महीने में हैं, तो दूसरे से एक दिन का महीना घटाएं और पूर्ण मूल्य लेने के लिए abs (abs(3) देखें) पर जाएं।
  4. यदि वे एक ही वर्ष और महीने में नहीं हैं, तो जांच करें कि वे आसन्न महीनों में हैं (उदाहरण के लिए, दिसंबर 2010 से जनवरी 2011, या जून 2010 से जुलाई 2010 तक)। यदि वे हैं, तो पहले की तारीख के दिनों में दिनों की संख्या जोड़ें (जिसे आप कैलेंडर को rangeOfUnit:inUnit:forDate: संदेश भेजकर NSDayCalendarUnit और NSMonthCalendarUnit क्रमशः पास कर सकते हैं), बाद की तारीख के दिन के महीने में, फिर उस परिणाम की तुलना करें पहले की तारीख के महीने के लिए।

    उदाहरण के लिए, 2010-12-31 से 2011-01-01 की तुलना करते समय, आप पहले यह निर्धारित करेंगे कि ये निकटवर्ती महीनों में हैं, फिर 31 (2010-12 में दिनों की संख्या) को 1 में जोड़ें (दिन का 2011-01-01 की माहौल), फिर उस राशि से 31 (2010-12-31 का दिन) घटाएं। चूंकि अंतर 1 है, इसलिए पहले की तारीख बाद की तारीख से एक दिन पहले है।

    जब 2010-12- की तुलना 2011-01- लिए, आप यह निर्धारित होता है कि वे आसन्न महीनों में कर रहे हैं, तो 2 के लिए (2010-12 में दिन) 31 जोड़ने (दिन के अनुसार महीने 2011-01-02 का), फिर उस राशि से 30 (2010-12-30 का दिन) घटाएं। 33 शून्य 30 है 3, इसलिए ये तिथियां तीन कैलेंडर दिन अलग हैं।


किसी भी तरह से, मैं दृढ़ता से इस कोड के लिए कम से कम इकाई परीक्षण लेखन सुझाव देते हैं। मैंने पाया है कि डेट-हैंडलिंग कोड सूक्ष्म बग्स होने की सबसे अधिक संभावना है, जो साल में दो बार प्रकट होता है।

+0

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

+0

टिम: मेरे दोनों सुझाव आपके प्रश्न में जो लिखा है उससे कम जटिल हैं-खासकर पहला सुझाव, जो एक दर्जन से अधिक बयान नहीं होना चाहिए। –

2

एक चीज जो आप कोशिश कर सकते हैं rangeOfUnit: का उपयोग शुरू करने और समाप्ति तिथियों से घंटे, मिनट और सेकंड शून्य से करने के लिए कर रहा है।

NSCalendar *calendar = [NSCalendar currentCalendar]; 
NSCalendarUnit range = NSDayCalendarUnit; 
NSDateComponents *comps = [[NSDateComponents alloc] init]; 
NSDate *start = [NSDate date]; 
NSDate *end; 

[comps setDay:1]; 
[calendar rangeOfUnit:range startDate:&start interval:nil forDate:start]; 

end = [calendar dateByAddingComponents:comps toDate:start options:0]; 

इस उदाहरण शुरुआत में 2010-06-19 00:00:00 -0400 हो जाएगा, अंत 2010-06-20 00:00:00 -0400 हो जाएगा। मुझे लगता है कि यह एनएससीएंडेंडर की तुलना विधियों के साथ बेहतर काम करेगा, हालांकि मैंने इसे स्वयं परीक्षण नहीं किया है।

0

यहाँ समारोह मैं पिछले अपने NSDate पर एक वर्ग में परिभाषित में उपयोग किया है है

- (int) daysToDate:(NSDate*) endDate 
{ 
    //dates needed to be reset to represent only yyyy-mm-dd to get correct number of days between two days. 
    NSDateFormatter *temp = [[NSDateFormatter alloc] init]; 
    [temp setDateFormat:@"yyyy-MM-dd"]; 
    NSDate *stDt = [temp dateFromString:[temp stringFromDate:self]]; 
    NSDate *endDt = [temp dateFromString:[temp stringFromDate:endDate]]; 
    [temp release]; 
    unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit; 
    NSCalendar *gregorian = [[NSCalendar alloc] 
          initWithCalendarIdentifier:NSGregorianCalendar]; 
    NSDateComponents *comps = [gregorian components:unitFlags fromDate:stDt toDate:endDt options:0]; 
    int days = [comps day]; 
    [gregorian release]; 
    return days; 
} 
0
-(NSInteger)daysBetweenTwoDates:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime 
करने के लिए बहुत अच्छा जवाब का उपयोग कर काम कर सकते हैं

{

NSDate *fromDate; 
NSDate *toDate; 

NSCalendar *calendar = [NSCalendar currentCalendar]; 

[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate 
      interval:NULL forDate:fromDateTime]; 
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate 
      interval:NULL forDate:toDateTime]; 

NSDateComponents *difference = [calendar components:NSDayCalendarUnit 
              fromDate:fromDate toDate:toDate options:0]; 

return [difference day]; 

}

1

मैं कोड के इस टुकड़े का उपयोग कर रहा है, यह बहुत अच्छी तरह से काम कर रहा है:

- (NSInteger)daysToDate:(NSDate*)date 
{ 
    if(date == nil) { 
     return NSNotFound; 
    } 
    NSUInteger otherDay = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date]; 
    NSUInteger currentDay = [[NSCalendar currentCalendar] ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:self]; 
    return (otherDay-currentDay); 
} 
संबंधित मुद्दे

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