2010-01-16 6 views
5

Comment puis-je calculer le nombre de jours dans une année pour un calendrier, pas seulement grégorien. Je l'ai essayéComment puis-je calculer le nombre de jours de cette année dans l'objectif C

NSUInteger *days = [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]];

mais qui me donne le nombre de jours dans le mois en cours au lieu du nombre de jours dans l'année en cours.

+2

Il ne fait que vous donner le nombre de jours le mois en cours. Il vous donne en fait la plage de valeurs possibles pour les jours dans l'année avec 1 à 31. Il n'y a pas de date qui pourrait avoir un nombre de jour de 32. –

Répondre

10

J'ai finalement trouvé une solution qui fonctionne. Ce que je fais est d'abord calculer le nombre de mois dans l'année et puis pour chaque mois, calculer le nombre de jours pour ce mois.

Le code ressemble à ceci:

NSUInteger days = 0; 
NSCalendar *calendar = [NSCalendar currentCalendar]; 
NSDate *today = [NSDate date]; 
NSDateComponents *components = [calendar components:NSYearCalendarUnit fromDate:today]; 
NSUInteger months = [calendar rangeOfUnit:NSMonthCalendarUnit 
            inUnit:NSYearCalendarUnit 
            forDate:today].length; 
for (int i = 1; i <= months; i++) { 
    components.month = i; 
    NSDate *month = [calendar dateFromComponents:components]; 
    days += [calendar rangeOfUnit:NSDayCalendarUnit 
          inUnit:NSMonthCalendarUnit 
          forDate:month].length; 
} 

return days; 

Il est pas aussi propre que je l'aurais espéré, mais cela fonctionnera pour tout calendrier tel que le grégorienne ordinaire ou celui islamic.

3

Je ne connais pas l'objectif-c mais c'est un algorithme simple pour déterminer s'il s'agit d'une année bissextile.

if (year % 400 == 0) 
    then 366 // Leap Year 
else if (year % 100 == 0) 
    then 365 // Non-Leap Year 
else if (year % 4 == 0) 
    then 366 // Leap Year 
else 
    365 // Non-Leap Year 

Ou si vous voulez une version peu moins bavard

if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) 
    then 366 // Leap Year 
else 
    365 // Non-Leap Year 
+5

Veuillez noter que cet algorithme se cassera pendant des années avant 1582, avant le saut années où introduit ;-) – notnoop

+0

Ceci est vrai. Vous devez ajouter un chèque pour vous assurer que l'année est après 1582. Si vous devez en tenir compte. –

+5

Ce n'est pas vraiment ce que je demandais, car cela ne marchera que pour le calendrier grégorien. – Godisemo

1

Peut-être que vous pouvez utiliser le sélecteur components:fromDate:toDate:options: qui est destiné à (et je cite official Apple docs): retour, comme un NSDateComponents objet en utilisant spécifié composants, la différence entre deux dates fournies.?

Également lu this post qui clarifie le comportement que vous voyez.

+0

Cela pourrait faire, mais comment dois-je décrire la date "dernier jour de l'année" – Godisemo

+0

http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/DatesAndTimes/Articles/dtCalendars.html Découvrez le exemple en bas de cette page, si vous travaillez avec NSDateComponents qui pourrait fonctionner pour tous les calendriers. –

+0

J'ai réfléchi à cela et je ne pense pas que ça marchera car cela me ramènera à la case départ et j'aurai à nouveau le même problème. – Godisemo

1

Afin de faire ce que vous voulez, vous devez trouver la gamme de jours dans un mois et des mois dans une année pour un calendrier spécifique. Cette fonction fera ce que vous avez besoin pour un calendrier qui utilise des unités jour/mois/année (ou a un équivalent cartographié):

NSInteger getDaysInYear(NSDate* date) 
{ 
    // Get the current calendar 
    NSCalendar* c = [NSCalendar currentCalendar]; 

    // Find the range for days and months in this calendar 
    NSRange dayRange = [c rangeOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:date]; 
    NSRange monthRange = [c rangeOfUnit:NSMonthCalendarUnit inUnit:NSYearCalendarUnit forDate:date]; 

    // Get the year from the suppled date 
    NSDateComponents* yearComps = [c components:NSYearCalendarUnit fromDate:date]; 
    NSInteger thisYear = [yearComps year]; 

    // Create the first day of the year in the current calendar 
    NSUInteger firstDay = dayRange.location; 
    NSUInteger firstMonth = monthRange.location; 
    NSDateComponents* firstDayComps = [[[NSDateComponents alloc] init] autorelease]; 
    [firstDayComps setDay:firstDay]; 
    [firstDayComps setMonth:firstMonth]; 
    [firstDayComps setYear:thisYear]; 
    NSDate* firstDayDate = [c dateFromComponents:firstDayComps]; 

    // Create the last day of the year in the current calendar 
    NSUInteger lastDay = dayRange.length; 
    NSUInteger lastMonth = monthRange.length; 
    NSDateComponents* lastDayComps = [[[NSDateComponents alloc] init] autorelease]; 
    [lastDayComps setDay:lastDay]; 
    [lastDayComps setMonth:lastMonth]; 
    [lastDayComps setYear:thisYear]; 
    NSDate* lastDayDate = [c dateFromComponents:lastDayComps]; 

    // Find the difference in days between the first and last days of the year 
    NSDateComponents* diffComps = [c components:NSDayCalendarUnit 
             fromDate:firstDayDate 
             toDate:lastDayDate 
             options:0]; 

    // We have to add one since this was subtraction but we really want to 
    // give the total days in the year 
    return [diffComps day] + 1; 
} 

Si vous souhaitez spécifier cette année, vous pouvez l'appeler simplement comme getDaysInYear([NSDate date]);, ou vous pouvez créer une date à partir d'une année spécifique/d'autres composants et la transmettre. Vous pouvez également très facilement le ré-implémenter en tant qu'appel de méthode.

-2
[[NSCalendar currentCalendar] ordinalityOfUnit:NSYearCalendarUnit 
             inUnit:NSEraCalendarUnit forDate:date]; 
-1

Voici la réponse fournie par William Clemens, mais dans l'objectif C:

    int year; 
        int yearCode; 

        if (year % 400 == 0) 
         {yearCode = 366;} // Leap Year 
        else if (year % 100 == 0) 
        { 
         {yearCode = 365;} // Non Leap Year 
        } 
        else if (year % 4 == 0) 
        { 
         {yearCode = 366;} // Leap Year 
        } 
        else 
        {yearCode = 365;} // Non-Leap Year 
8

En général, vous pouvez utiliser le nombre de jours entre le 1er jour de l'année et le 1er jour de l'année suivante. Voici le code qui illustre cette approche

- (NSDate *)firstDateOfYear:(NSInteger)year 
{ 
    NSDateComponents *dc = [[NSDateComponents alloc] init]; 
    dc.year = year; 
    dc.month = 1; 
    dc.day = 1; 
    return [[NSCalendar currentCalendar] dateFromComponents:dc]; 
} 

- (NSUInteger)numberOfDaysInYear:(NSInteger)year 
{ 
    NSDate *firstDateOfYear = [self firstDateOfYear:year]; 
    NSDate *firstDateOfNextYear = [self firstDateOfYear:year + 1]; 
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:firstDateOfYear toDate:firstDateOfNextYear options:0]; 
    return [components day]; 
} 
2

Je ne sais pas si quelqu'un est toujours intéressé par ce fil, mais une autre solution possible:

NSCalendar *calendar = [NSCalendar currentCalendar]; 
NSDate *startOfYear; 
NSTimeInterval lengthOfYear; 
[calendar rangeOfUnit:NSYearCalendarUnit 
      startDate:&startOfYear 
      interval:&lengthOfYear 
       forDate:[NSDate date]]; 
NSDate *endOfYear = [startOfYear dateByAddingTimeInterval:lengthOfYear]; 
NSDateComponents *comp = [calendar components:NSDayCalendarUnit 
            fromDate:startOfYear 
             toDate:endOfYear 
             options:0]; 
NSUInteger numberOfDaysInThisYear = [comp day]; 

en utilisant seulement deux appels à NSCalendar.

+0

hey. Cela pourrait-il rendre votre solution encore meilleure si nous divisons simplement la longueur de l'année par le nombre de secondes d'une journée? – Olex

+0

@Olex: Comment calculeriez-vous la "durée de l'année"? Le nombre ou les secondes d'un jour ne sont pas non plus des valeurs fixes. Dans les régions avec l'heure d'été, un jour peut avoir 23 ou 25 heures, lorsque l'heure d'été commence ou se termine. De plus, la question demande le numéro de jour dans * tout * calendrier, pas seulement le grégorien. Donc, le nombre de jours dans une année peut être différent de 365. –

+0

Martin, vous calculez déjà la longueur de l'année (qui est en secondes). Et le nombre de secondes dans un jour est 24 * 60 * 60. DST n'affectera pas cette approche comme 23 + 25 = 48 = 24 + 24. D'autres calendriers devraient fonctionner aussi parce que vous calculez la longueur de l'année dans un calendrier spécifique . Un arrondi à l'entier le plus proche peut être nécessaire cependant. – Olex

0

Wow, ce sont des solutions impliquées. Il suffit de créer une date du 29 février de l'année en cours et de voir si elle est convertie en mars en premier ou non.

-(BOOL)isLeapYear { 
    NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 
    components.month = 2; 
    components.day = 29; 

    NSDate *date = [[NSDate currentCalendar] dateFromComponents:components]; 
    return (date.month == 2 && date.day == 29); 
} 

** Note, certains de ces éléments comme date.month et date.day relais sur d'autres méthodes non représentées, mais vous aurez l'idée.

+0

Cela serait spécifique au calendrier grégorien. –

0

Un autre exemple à Swift 3:

let calendar = Calendar.current 
let date = Date() // use any date in this year 
if let yearInterval = calendar.dateInterval(of: Calendar.Component.year, for: date), 
    let daysInYear = calendar.dateComponents([Calendar.Component.day], from: yearInterval.start, to: yearInterval.end).day 
{ 
    print(daysInYear) 
} 

En Objective-C:

NSCalendar *calendar = [NSCalendar currentCalendar]; 
NSDate* date = [NSDate date]; 
NSDate* startOfYear = nil; 
NSTimeInterval yearDuration = 0; 
if ([calendar rangeOfUnit:NSCalendarUnitYear startDate:&startOfYear interval:&yearDuration forDate:d 
]) { 
    NSDateComponents *daysComponents = [calendar components:NSCalendarUnitDay fromDate:startOfYear toDate:[startOfYear dateByAddingTimeInterval:yearDuration] options:0]; 
    NSInteger daysInYear = daysComponents.day; 
    NSLog(@"Days in year: %ld", daysInYear); 
} 
0

Swift 3 extension:

extension Date { 
    public func isLeapYear() -> Bool { 
     let components = Calendar.current.dateComponents([.year], from: self) 

     guard let year = components.year else { return false } 

     return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 
    } 
} 
Questions connexes