Plusieurs classes sont associées à la manipulation des objets date et heure dans Objective-C :
NSDate,
NSCalendar,
NSTimeZone,
NSDateComponents,
NSDateFormatter. Pour mieux appréhender ces différentes classes, rien de tel qu'un peu de code.
Affichage de la date courante
Ces quelques lignes de code affichent la date courante au format américain (en_US) et français (fr_FR) :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | /* ---Définition de l'objet date et de sa mise en forme--- */
// Aujourd'hui
NSDate *date = [NSDate date];
NSDateFormatter *miseEnForme = [[NSDateFormatter alloc] init];
// Aucun affichage de l'heure
[miseEnForme setTimeStyle:NSDateFormatterNoStyle];
// Affichage de la date au format semi-abrégé
[miseEnForme setDateStyle:NSDateFormatterMediumStyle];
/* ---Affichage de la date au format US--- */
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[miseEnForme setLocale:usLocale];
NSLog(@"Date au format %@: %@", [[miseEnForme locale] localeIdentifier], [miseEnForme stringFromDate:date]);
/* ---Affichage de la date au format FR--- */
NSLocale *frLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"];
[miseEnForme setLocale:frLocale];
NSLog(@"Date au format %@: %@", [[miseEnForme locale] localeIdentifier], [miseEnForme stringFromDate:date]);
|
Et voici ce que ça donne dans la console :
Code : Console | [...] test[1527:207] Date au format en_US: Jun 7, 2011
[...] test[1527:207] Date for locale fr_FR: 7 juin 2011 |
Cette syntaxe est vraiment incroyable et j'ai peur d'être dépassé ! Est-ce que j'aurais raté un chapitre ?
Examinons le premier bloc d'instructions. La ligne 4 définit l'objet
NSDate date (
NSDate *date) et lui affecte la date courante (
[NSDate date]).
Code : Objective-C | NSDate *date = [NSDate date];
|
La ligne 5 définit l'objet
miseEnForme de type
NSDateFormatter. C'est par l'intermédiaire de cet objet que l'on définira un format d'affichage pour la date.
Code : Objective-C | NSDateFormatter *miseEnForme = [[NSDateFormatter alloc] init];
|
La ligne 8 indique que l'heure ne doit pas être affichée. La méthode
setTimeStyle est donc appliquée à l'objet
miseEnForme en lui transmettant un paramètre :
Code : Objective-C | [miseEnForme setTimeStyle:NSDateFormatterNoStyle];
|
Enfin, la quatrième instruction donne le format d'affichage de la date. Les messages autorisés pour la méthode
setDateStyle sont :
- NSDateFormatterNoStyle
- NSDateFormatterShortStyle
- NSDateFormatterMediumStyle
- NSDateFormatterLongStyle
- NSDateFormatterFullStyle
Je vous invite à modifier l'instruction en question afin d'observer les différents comportements de ces méthodes.
Code : Objective-C | [miseEnForme setDateStyle:NSDateFormatterMediumStyle];
|
Examinons maintenant le deuxième bloc d'instructions.
La ligne 14 définit l'objet
NSLocale usLocale et l'initialise au format
en_US, c'est-à-dire anglais américain :
Code : Objective-C | NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
|
La ligne suivante utilise la classe
setLocale pour indiquer à l'objet
NSDateFormatter miseEnForme que l'affichage devra se faire au format anglais américain :
Code : Objective-C | [miseEnForme setLocale:usLocale];
|
Enfin, la ligne 16 affiche la date courante dans ce format. Le premier message entre crochets récupère l'identificateur de langue (
en_US) et le deuxième la date au format
miseEnForme :
Code : Objective-C | NSLog(@"Date au format %@: %@", [[miseEnForme locale] localeIdentifier], [miseEnForme stringFromDate:date]);
|
Le troisième bloc d'instructions est très proche du deuxième, à ceci près qu'il demande l'affichage de la date au format français.
Création d'une date relative à la date système
La méthode
initWithTimeIntervalSinceNow permet de créer un objet
NSDate en lui appliquant un décalage par rapport à la date système. Le décalage peut être positif (pour définir une date postérieure à la date système) ou négatif (pour définir une date antérieure à la date système).
Examinez le code suivant :
Code : Objective-C | NSDate *dateCourante = [NSDate date]; //Aujourd'hui
NSTimeInterval secondesParJour = 24 * 60 * 60;
NSDate *demain = [[NSDate alloc] initWithTimeIntervalSinceNow:secondesParJour];
NSDate *hier = [[NSDate alloc] initWithTimeIntervalSinceNow:-secondesParJour];
|
La première ligne définit l'objet
NSDate dateCourante et y mémorise la date système.
La deuxième ligne définit l'objet
NSTimeInterval secondesParJour et y mémorise le nombre de secondes contenues dans une journée.
La troisième ligne définit l'objet
NSDate demain et y stocke la date système plus un jour. Pour cela, la méthode
initWithTimeIntervalSinceNow lui est appliquée en lui transmettant la valeur
secondesParJour. L'objet
demain est donc initialisé avec la date qui suit le jour courant.
La quatrième ligne est très proche de la troisième, mais ici, le paramètre passé à la méthode
initWithTimeIntervalSinceNow est égal à
-secondesParJour. L'objet
hier est donc initialisé avec la date qui précède le jour courant.
Définition d'une date autre que la date système
Pour définir une date différente de la date système, vous devez :
- définir et initialiser un objet NSDateComponents ;
- l'affecter à un objet NSDate via un objet NSCalendar.
Tout ceci a l'air bien compliqué, mais vous allez voir qu'il n'en est rien en examinant le code suivant :
Code : Objective-C | // Définition d'un objet NSDateComponents
NSDateComponents *nsDatePerso = [[NSDateComponents alloc] init];
[nsDatePerso setYear:2065];
[nsDatePerso setMonth:8];
[nsDatePerso setDay:12];
// Création d'un objet NSDate et affectation de l'objet nsDatePerso défini précédemment
NSDate *datePerso = [[NSCalendar currentCalendar] dateFromComponents:nsDatePerso];
NSLog(@"Date utilisateur : %@", datePerso);
|
Voici le résultat affiché dans la console :
Code : Console | [...] test[1680:207] Date utilisateur : 2065-08-11 22:00:00 +0000 |
Comme vous le voyez, aucune mise en forme
NSFormatter n'a été appliquée à l'objet
datePerso.
Examinons les instructions qui composent ce code.
La première instruction définit l'objet
NSDateComponents nsDatePerso et réserve son emplacement en mémoire :
Code : Objective-C | NSDateComponents *nsDatePerso = [[NSDateComponents alloc] init];
|
Les trois instructions suivantes initialisent les composants
année,
mois et
jour de cet objet.
Code : Objective-C | [nsDatePerso setYear:2065];
[nsDatePerso setMonth:8];
[nsDatePerso setDay:12];
|
Le deuxième bloc d'instructions définit un objet
NSDate de nom
datePerso (
NSDate *datePerso). Cet objet est initialisé avec la date définie dans l'objet
nsDatePerso (
dateFromComponents:nsDatePerso) en passant par un objet
NSCalendar (
[NSCalendar currentCalendar]) :
Code : Objective-C | NSDate *datePerso = [[NSCalendar currentCalendar] dateFromComponents:nsDatePerso];
|
Une variante pour définir une date autre que la date système
Pour définir et initialiser un objet
NSDate avec une date différente de la date système, il est également possible d'utiliser une chaîne de caractères. Cette technique est plus simple que la précédente. Elle consiste à passer en paramètre la chaîne qui contient la date à la méthode
dateFromString, qui elle-même est appliquée à un objet
NSDateFormatter :
Code : Objective-C | NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:@"dd-MM-yyyy"];
NSDate *uneDate = [df dateFromString:@"12-08-2011"];
|
La première instruction définit l'objet
NSDateFormatter df et lui réserve un emplacement en mémoire :
Code : Objective-C | NSDateFormatter* df = [[NSDateFormatter alloc]init];
|
La deuxième instruction définit le format utilisé dans l'objet
NSDateFormatter :
Code : Objective-C | [df setDateFormat:@"dd-MM-yyyy"];
|
Enfin, la troisième instruction affecte une date à l'objet
NSDate uneDate en transmettant une chaîne à la méthode
dateFromString de l'objet
NSDateFormlatter df :
Code : Objective-C | NSDate *uneDate = [df dateFromString:@"12-08-2011"];
|
Extraction des composants d'un objet NSDate
Pour accéder aux composants (jour, mois, année, heure, minute et seconde) d'une date au format
NSDate, vous devez utiliser la méthode
components: fromDate: d'un objet
NSCalendar dans lequel vous aurez stocké la date.
À titre d'exemple, le code ci-dessous extrait le jour, le mois, l'année, l'heure, les minutes et les secondes de la date système et les affiche dans la console :
Code : Objective-C | NSDate *date = [NSDate date]; //Aujourd'hui
NSCalendar *calendrier = [NSCalendar currentCalendar];
NSDateComponents *composants = [calendrier components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:date];
NSLog(@"Nous sommes le %i / %i / %i", [composants day], [composants month], [composants year]);
NSLog(@"Il est %i : %i : %i", [composants hour], [composants minute], [composants second]);
|
La première instruction crée l'objet
NSDate date et y stocke la date système :
Code : Objective-C | NSDate *date = [NSDate date]; //Aujourd'hui
|
La deuxième instruction crée l'objet
NSCalendar calendrier :
Code : Objective-C | NSCalendar *calendrier = [NSCalendar currentCalendar];
|
La troisième instruction crée l'objet
NSDateComponents composants et lui affecte les composants suivants de l'objet
NSDate date :
- année : NSYearCalendarUnit
- mois : NSMonthCalendarUnit
- jour : NSDayCalendarUnit
- heure : NSHourCalendarUnit
- minutes : NSMinuteCalendarUnit
- secondes : NSSecondCalendarUnit
Les deux dernières instructions affichent les composants de la date système dans la console, ce qui donne le résultat suivant :
Code : Console | [...] test[1897:207] Nous sommes le 7 / 6 / 2011
[...] test[1897:207] Il est 16 : 39 : 6 |
Ajouter ou soustraire des dates
Pour ajouter ou soustraire un certain nombre d'années, de mois et de jours à une date, vous devez créer un objet
dateComponents, y stocker la valeur à ajouter ou soustraire et ensuite utiliser la méthode
dateByAddingComponents:toDate pour ajuster la date d'origine.
À titre d'exemple, nous allons ajouter 1 an, 3 mois et 10 jours à la date système et afficher le résultat dans la console. Voici le code utilisé :
Code : Objective-C | NSDate *date = [NSDate date]; //Aujourd'hui
NSDateComponents *leGap = [[NSDateComponents alloc] init];
[leGap setYear:1];
[leGap setMonth:3];
[leGap setDay:10];
NSDate *nouvelleDate = [[NSCalendar currentCalendar] dateByAddingComponents:leGap toDate:date options:0];
NSLog(@"Date système : %@", date);
NSLog(@"Nouvelle date : %@", nouvelleDate);
|
La date système puis la nouvelle date sont affichées dans la console :
Code : Console | [...] test[1995:207] Date système : 2011-06-07 14:59:53 +0000
[...] test[1995:207] Nouvelle date : 2012-09-17 14:59:53 +0000 |
Examinons les instructions utilisées.
La première ligne définit l'objet
NSDate date et y stocke la date système :
Code : Objective-C | NSDate *date = [NSDate date];
|
La deuxième ligne définit l'objet
NSDateComponents leGap et réserve son emplacement en mémoire :
Code : Objective-C | NSDateComponents *leGap = [[NSDateComponents alloc] init];
|
Les trois lignes suivantes initialisent le décalage souhaité dans l'objet
leGap :
Code : Objective-C | [leGap setYear:1];
[leGap setMonth:3];
[leGap setDay:10];
|
La nouvelle date est calculée dans l'objet
NSDate nouvelleDate. Les composants définis dans l'objet
leGap sont ajoutés (
dateByAddingComponents:leGap) à l'objet
NSDate date (
toDate: date) :
Code : Objective-C | NSDate *nouvelleDate = [[NSCalendar currentCalendar] dateByAddingComponents:leGap toDate:date options:0];
|
Calculer la différence entre deux dates
Il est parfois nécessaire de calculer la différence entre deux dates. En Objective-C, cela se fait en appliquant les méthodes
fromDate et
toDate à un objet
NSCalendar. Voici le code :
Code : Objective-C | NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:@"yyyy-MM-dd"];
NSDate *dateA = [NSDate date]; //Aujourd'hui
NSDate* dateB = [df dateFromString:@"2011-01-01"];
NSCalendarUnit calendrier = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *difference = [[NSCalendar currentCalendar] components:calendrier fromDate:dateA toDate:dateB options:0];
NSInteger mois = [difference month];
NSInteger jours = [difference day];
NSLog(@"Différence entre les deux dates : %i mois et %i jours.", mois,jours);
|
Examinons ce code.
Les deux premières instructions définissent et initialisent l'objet
NSDateFormatter df :
Code : Objective-C | NSDateFormatter* df = [[NSDateFormatter alloc]init];
[df setDateFormat:@"yyyy-MM-dd"];
|
Les deux instructions suivantes stockent la date courante ainsi qu'une autre date (celle du 01/01/2011) dans les objets
NSDate dateA et
dateB :
Code : Objective-C | NSDate *dateA = [NSDate date]; //Aujourd'hui
NSDate* dateB = [df dateFromString:@"2011-01-01"];
|
L'instruction suivante définit les composants qui seront utilisés pour calculer la différence entre les deux dates (ici les années, les mois et les jours) :
Code : Objective-C | NSCalendarUnit calendrier = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
|
L'instruction suivante calcule la différence entre les deux dates. L'instruction est assez conséquente, alors prenez le temps de bien la comprendre. Dans la section « Extraction des composants d'un objet NSDate », vous avez appris à utiliser la méthode
components: fromDate pour extraire les composants (année, mois, jour, heures, minutes, …) d'une date. Ici, nous allons utiliser la méthode
components: fromDate: toDate: pour effectuer une soustraction entre deux dates et en extraire les composants.
Dans un premier temps, un objet
NSCalendar est obtenu avec le message
[NSCalendar currentCalendar].
La méthode
components: fromDate: toDate: est alors exécutée. La différence entre les dates
dateA et
dateB est calculée (
fromDate:dateA toDate:dateB), et seuls les composants définis dans l'objet
NSCalendatUnit calendrier sont retournés. Le résultat est stocké dans l'objet
NSDateComponents difference :
Code : Objective-C | NSDateComponents *difference = [[NSCalendar currentCalendar] components:calendrier fromDate:dateA toDate:dateB options:0];
|
Il ne reste plus qu'à extraire les composants
ans,
mois et
jour du résultat et à les stocker dans des objets
NSInteger :
Code : Objective-C | NSInteger ans = [difference year];
NSInteger mois = [difference month];
NSInteger jours = [difference day];
|
Il ne reste plus qu'à les afficher dans la console :
Code : Objective-C | NSLog(@"Différence entre les deux dates : % ans %i mois et %i jours.", ans,mois,jours);
|
Temps nécessaire pour exécuter un bloc d'instructions
Pendant la mise au point d'une application, il peut être utile de calculer le temps nécessaire à l'exécution d'un bloc de code. Voici comment procéder :
- définissez un objet NSDate et initialisez-le avec la date courante juste avant le bloc de code dont vous voulez tester le temps d'exécution ;
- exécutez le bloc de code ;
- appliquez la méthode timeIntervalSinceNow à l'objet NSDate initialisé à l'étape 1 et mémorisez le résultat dans un objet NSTimeInterval.
Voici un exemple de code qui teste le temps nécessaire à l'affichage de 100 lignes dans la console :
Code : Objective-C | NSDate *debut = [NSDate date]; //Date courante
//On affiche 100 lignes dans la console grâce à une boucle
int compteur;
for (compteur=1; compteur<100; compteur++)
{
NSLog(@"abc");
}
NSTimeInterval intervalle = [debut timeIntervalSinceNow]; //On calcule le temps d'exécution...
NSLog(@"Temps écoulé : %f", intervalle); //Et on l'affiche
|
La figure suivante représente les dernières informations affichées dans la console.