Accéder au contenu principal

Parcourir des dates avec NSDate

Pour utiliser NSDate nous avons besoin de dire de quoi nous parlons... En effet une date n'a de sens que par rapport à un calendrier (Arabe, Hébreux, Japonais, etc...).
Notre calendrier (à nous français) est le calendrier grégorien. Nous avons donc besoin d'une variable NSCalendar initialisée en grégorien.

NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifierNSCalendarIdentifierGregorian];

Ensuite si nous avons besoin de récupérer un élément de la date, nous avons besoin d'une variable NSDateComponent

NSDateComponents* components = [calendar components: NSCalendarUnitYear | NSCalendarUnitMonthNSCalendarUnitDay fromDate:[NSDate new]];

Le [NSDate new] fournit la date du jour.
Vous devez définir quelles parties de la date vous intéresse, quels composants. Ici, par exemple nous coulons récupérer :
- L'année : NSCalendarUnitYear
- Le mois : NSCalendarUnitMonth
- Le jour dans le mois : NSCalendarUnitDay

Après, nous pouvons récupérer les données dans l'objet composants, par exemple : composants.day, ou composants.weekday. Mais nous pouvons aussi les changer... Ainsi le voici la fonction pour extraire le premier jour du mois :


-(NSDate*)firstDayOfCurrentMonth {
    NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifierNSCalendarIdentifierGregorian];
    NSDateComponents* components = [calendar components: NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];
    components.day = 1;
    return [calendar dateFromComponents:components];
}

Mais, aujourd'hui, ce qui m'intéresse c'est d'avoir le mois précédent... Donc :


- (NSDate*)previousMonthFrom:(NSDate*)date  {
    NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifierNSCalendarIdentifierGregorian];

    NSDateComponents* components = [calendar componentsNSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];

    components.day = 1;
    if(components.month==1) {
        components.month = 12;
        components.year--;
    } else {
        components.month--;
    }

    return [calendar dateFromComponents:components];
}

Ensuite c'est d'avoir la date en chaine de caractères. Là, j'utilise NSDateFormater. Même si nous sommes en grégorien, la date au format texte peut-être en anglais, en français, ou en allemand, etc...


-(NSString*)monthYearOfDate:(NSDate*)date {
    NSDateFormatter *dateFormatter = [NSDateFormatter new];
    dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:[[NSLocale preferredLanguages] firstObject]];
    dateFormatter.dateFormat = @"MMMM yyyy";
    return [dateFormatter stringFromDate:date];
}

Le preferredLanguage va regarder dans les réglages de l'appareil et mettre "Janvier", "January", "Januar" ou encore "enero" selon la première langue définit dans les réglages de l'appareil. Le "MMMM" veut dire le nom du mois au format long. Regardez la documentation de NSDateFormatter pour voir toutes les possibilités.










Commentaires

Posts les plus consultés de ce blog

Adapter l'interface à la taille des caractères pour malvoyants.

Depuis quelques temps, je fais attention aux réglages de la taille des caractères systèmes. Les malvoyant peuvent décider dans les Réglages de l'iPad, Accessibilité de changer la taille des textes par défaut : Mais dans ce cas, les interfaces sont souvent trop petites, et les texte ne rentre pas dedans. Si vous avez besoin d'une valeur en pixel, en proportion du niveau de zoom des caractères, vous devez utilisez UIFontMetrics. if ( @available (iOS 11.0 , *)) {    larg = [ UIFontMetrics . defaultMetrics scaledValueForValue :larg]; } Ici, vous ne verrez aucune différence à moins de changer les réglages d'accessibilité. Mais, si vous touchez aux réglages, votre valeur en pixels correspondra au niveau de zoom. Cette fonctionnalité n'existe que depuis IOS 11, il faut donc mettre un available si vous compilez comme moi des apps pour IOS9. Je me sers de cette fonctionnalité, par exemple, dans : - ( CGSize ) collectionView :( UICollectionView *)collectionView             layo

archivedDataWithRootObject

archivedDataWithRootObject: est deprecated depuis IOS12.   NSData *data = [ NSKeyedArchiver archivedDataWithRootObject : @{} ]; // deprecated ISO12 Cela va avec l'avancée de SWIFT qui ne permet pas facilement de faire des tableaux de "trucs" non définis. C'est la nouvelle option requiringSecureCoding qui indique si le tableaux (NSDictionnary ou NSArray) peut contenir n'importe quoi ou uniquement des objets bien définis.   NSData  *data  = [ NSKeyedArchiver   archivedDataWithRootObject : @{}   requiringSecureCoding : NO   error :&error]; Le problème est que la fonction pour dés-archiver n'est pas deprecated, mais plante ! NSDictionary *dico = [ NSKeyedUnarchiver unarchivedObjectOfClass : NSDictionary . class                                                          fromData :data error :&error];  // plante Si l'on désire faire comme avant, il faut un requiresSecureCoding:NO, mais il n'y a pas le pendant du archivedDataWithRootObject ! Il n&#

UISceneSession is only available on iOS 13

Lorsque vous faites une nouvelle application, celle-ci est par défaut pour le dernier IOS.  Mais si vos clients, comme les miens, ont de vieux appareils, vous pourriez vouloir que votre application fonctionne avec IOS9 (pour le moment on peut encore faire des apps IOS9, mais je crois que la limite sera IOS12 dans pas longtemps). Dans les infos de déploiement, vous changez donc le IOS 14  en IOS 9. Mais, le lancement de l'app vous donne un écran noir ! Pour régler le problème, il faut ajouter une propriété "window" dans l'interface du appDelegate. @interface AppDelegate : UIResponder < UIApplicationDelegate > @property ( strong , nonatomic ) UIWindow * window ; @end Reste les warnings... Le plus simple est de faire confiance à Xcode, tapez sur les warnings et un menu vous proposera un "fix" qui ajoutera un API_AVAILABLE à la définition de la fonction. - ( void ) scene :( UIScene *)scene willConnectToSession :( UISceneSession *)session options :(