Comment puis-je déterminer le nombre de jours entre deux valeurs NSDate
(en prenant également en compte le temps)?
Les valeurs NSDate
sont sous la forme que prend [NSDate date]
.
Plus précisément, lorsqu'un utilisateur entre dans l'état inactif de mon application iPhone, je stocke la valeur suivante:
exitDate = [NSDate date];
Et quand ils ouvrent l'application, je reçois l'heure actuelle:
NSDate *now = [NSDate date];
J'aimerais maintenant implémenter ce qui suit:
-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now
Voici une implémentation que j'ai utilisée pour déterminer le nombre de jours calendaires entre deux dates:
+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSCalendarUnitDay
fromDate:fromDate toDate:toDate options:0];
return [difference day];
}
MODIFIER:
Solution fantastique ci-dessus, voici la version de Swift ci-dessous en tant qu'extension sur NSDate
:
extension NSDate {
func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
let calendar = NSCalendar.currentCalendar()
if let timeZone = timeZone {
calendar.timeZone = timeZone
}
var fromDate: NSDate?, toDate: NSDate?
calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)
let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
return difference.day
}
}
Un peu de force se déroulant que vous voudrez peut-être supprimer en fonction de votre cas d'utilisation.
La solution ci-dessus fonctionne également pour les fuseaux horaires autres que le fuseau horaire actuel, ce qui est idéal pour une application qui affiche des informations sur des lieux du monde entier.
Voici la meilleure solution que j'ai trouvée. Semble utiliser la méthode approuvée par Apple pour déterminer toute quantité d'unités entre NSDates.
- (int)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
NSUInteger unitFlags = NSDayCalendarUnit;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
return [components day]+1;
}
Par exemple. si vous voulez aussi des mois, vous pouvez alors inclure «NSMonthCalendarUnit» en tant que unitFlag.
Pour créditer le blogueur original, j'ai trouvé cette information ici (bien qu'il y ait une légère erreur que j'ai corrigée ci-dessus): http://cocoamatic.blogspot.com/2010/09/nsdate-number- de-jours-entre-deux-dates.html? showComment = 1306198273659 # c6501446329564880344
Mise à jour Swift 3.0
extension Date {
func differenceInDaysWithDate(date: Date) -> Int {
let calendar = Calendar.current
let date1 = calendar.startOfDay(for: self)
let date2 = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: date1, to: date2)
return components.day ?? 0
}
}
Mise à jour Swift 2.0
extension NSDate {
func differenceInDaysWithDate(date: NSDate) -> Int {
let calendar: NSCalendar = NSCalendar.currentCalendar()
let date1 = calendar.startOfDayForDate(self)
let date2 = calendar.startOfDayForDate(date)
let components = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
return components.day
}
}
Solution d'origine
Une autre solution à Swift.
Si votre objectif est d’obtenir le nombre exact de jours entre deux dates, vous pouvez résoudre ce problème comme suit:
// Assuming that firstDate and secondDate are defined
// ...
var calendar: NSCalendar = NSCalendar.currentCalendar()
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)
let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)
components.day // This will return the number of day(s) between dates
J'utilise ceci comme méthode de catégorie pour la classe NSDate
// returns number of days (absolute value) from another date (as number of midnights beween these dates)
- (int)daysFromDate:(NSDate *)pDate {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSInteger startDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitEra
forDate:[NSDate date]];
NSInteger endDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitEra
forDate:pDate];
return abs(endDay-startDay);
}
J'avais besoin du nombre de jours entre deux dates, y compris le jour du début. par exemple. les jours compris entre le 14-2-2012 et le 16-2-2012 donneraient un résultat de 3.
+ (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
NSUInteger unitFlags = NSDayCalendarUnit;
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
NSInteger daysBetween = abs([components day]);
return daysBetween+1;
}
Notez que l'ordre dans lequel vous fournissez les dates n'a pas d'importance. Il retournera toujours un nombre positif.
NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;
dateDiff sera alors le nombre de secondes entre les deux dates. Divisez simplement par le nombre de secondes dans une journée.
@ Brian
La réponse de Brian, si elle est satisfaisante, ne calcule que la différence en jours en termes de morceaux de 24 heures, mais pas de différences en jours calendaires. Par exemple, 23h59 le 24 décembre est à seulement 1 minute du jour de Noël, aux fins de nombreuses applications considérées comme un jour de plus. La fonction daysBetween de Brian renverrait 0.
Empruntant à la mise en œuvre initiale de Brian et au début/à la fin de la journée, j’utilise les éléments suivants dans mon programme: ( NSDate début de la journée et fin de la journée )
- (NSDate *)beginningOfDay:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
return [cal dateFromComponents:components];
}
- (NSDate *)endOfDay:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
[components setHour:23];
[components setMinute:59];
[components setSecond:59];
return [cal dateFromComponents:components];
}
- (int)daysBetween:(NSDate *)date1 and:(NSDate *)date2 {
NSDate *beginningOfDate1 = [self beginningOfDay:date1];
NSDate *endOfDate1 = [self endOfDay:date1];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *beginningDayDiff = [calendar components:NSDayCalendarUnit fromDate:beginningOfDate1 toDate:date2 options:0];
NSDateComponents *endDayDiff = [calendar components:NSDayCalendarUnit fromDate:endOfDate1 toDate:date2 options:0];
if (beginningDayDiff.day > 0)
return beginningDayDiff.day;
else if (endDayDiff.day < 0)
return endDayDiff.day;
else {
return 0;
}
}
Voici une implémentation de la fonction de Brian dans Swift:
class func daysBetweenThisDate(fromDateTime:NSDate, andThisDate toDateTime:NSDate)->Int?{
var fromDate:NSDate? = nil
var toDate:NSDate? = nil
let calendar = NSCalendar.currentCalendar()
calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &fromDate, interval: nil, forDate: fromDateTime)
calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &toDate, interval: nil, forDate: toDateTime)
if let from = fromDate {
if let to = toDate {
let difference = calendar.components(NSCalendarUnit.DayCalendarUnit, fromDate: from, toDate: to, options: NSCalendarOptions.allZeros)
return difference.day
}
}
return nil
}
Il suffit d'ajouter une réponse pour ceux qui visitent cette page essayant de le faire dans Swift. L'approche est à peu près la même.
private class func getDaysBetweenDates(startDate:NSDate, endDate:NSDate) -> NSInteger {
var gregorian: NSCalendar = NSCalendar.currentCalendar();
let flags = NSCalendarUnit.DayCalendarUnit
let components = gregorian.components(flags, fromDate: startDate, toDate: endDate, options: nil)
return components.day
}
Cette réponse a été trouvée ici , dans la section discussion de la méthode suivante:
components(_:fromDate:toDate:options:)
Une autre approche:
NSDateFormatter* dayFmt = [[NSDateFormatter alloc] init];
[dayFmt setTimeZone:<whatever time zone you want>];
[dayFmt setDateFormat:@"g"];
NSInteger firstDay = [[dayFmt stringFromDate:firstDate] integerValue];
NSInteger secondDay = [[dayFmt stringFromDate:secondDate] integerValue];
NSInteger difference = secondDay - firstDay;
L'avantage par rapport au schéma timeIntervalSince...
est que le fuseau horaire peut être pris en compte, et il n'y a aucune ambiguïté avec des intervalles de quelques secondes à court ou à long d'une journée.
Et un peu plus compact et moins déroutant que les approches NSDateComponents.
J'en ai un, je ne suis pas sûr que c'est exactement ce que vous voulez, mais cela pourrait aider certains d'entre vous (m'a aidé!)
Mon objectif était de savoir si, entre deux rendez-vous (moins de 24 heures de différence), je passais un "jour de congé"
j'ai fait ce qui suit (un peu archaïque, je l'avoue)
NSDate *startDate = ...
NSDate *endDate = ...
NSDate déjà formaté par un autre NSDateFormatter (celui-ci est juste pour cela :)
NSDateFormatter *dayFormater = [[NSDateFormatter alloc]init];
[dayFormater setDateFormat:@"dd"];
int startDateDay = [[dayFormater stringFromDate:startDate]intValue];
int endDateDay = [[dayFormater stringFromDate:dateOn]intValue];
if (endDateDay > startDateDay) {
NSLog(@"day+1");
} else {
NSLog(@"same day");
}
peut-être que quelque chose comme cela existe déjà, mais ne l'a pas trouvé
Tim
Voulez-vous dire jours calendaires ou périodes de 24 heures? c’est-à-dire mardi à 21 heures un jour avant mercredi à 6 heures ou moins d’un jour?
Si vous parlez de l'ancien, c'est un peu compliqué et vous devrez recourir à des manipulations via NSCalendar
et NSDateComponent
, ce dont je ne me souviens pas très bien.
Si vous voulez parler de ce dernier, obtenez simplement les intervalles de temps des dates depuis la date de référence, soustrayez les uns des autres et divisez par 24 heures (24 * 60 * 60
) pour obtenir l'intervalle approximatif, secondes intercalaires non incluses.
La solution que j'ai trouvée était:
+(NSInteger)getDaysDifferenceBetween:(NSDate *)dateA and:(NSDate *)dateB {
if ([dateA isEqualToDate:dateB])
return 0;
NSCalendar * gregorian =
[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate * dateToRound = [dateA earlierDate:dateB];
int flags = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
NSDateComponents * dateComponents =
[gregorian components:flags fromDate:dateToRound];
NSDate * roundedDate = [gregorian dateFromComponents:dateComponents];
NSDate * otherDate = (dateToRound == dateA) ? dateB : dateA ;
NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);
NSInteger daysDifference = floor(diff/(24 * 60 * 60));
return daysDifference;
}
Ici, j’arrive effectivement à la première date pour commencer au début de la journée, puis je calcule la différence comme Jonathan le suggère ci-dessus ...
J'ai publié une classe/bibliothèque open-source pour ce faire.
Regardez RelativeDateDescriptor , qui peut être utilisé pour obtenir la différence de temps comme suit ...
RelativeDateDescriptor *descriptor = [[RelativeDateDescriptor alloc] initWithPriorDateDescriptionFormat:@"%@ ago" postDateDescriptionFormat:@"in %@"];
// date1: 1st January 2000, 00:00:00
// date2: 6th January 2000, 00:00:00
[descriptor describeDate:date2 relativeTo:date1]; // Returns '5 days ago'
[descriptor describeDate:date1 relativeTo:date2]; // Returns 'in 5 days'
Pourquoi pas simplement:
int days = [date1 timeIntervalSinceDate:date2]/24/60/60;