2つのNSDate
値の間の日数を決定するにはどうすればよいですか(時間も考慮に入れて)。
NSDate
値は、[NSDate date]
がとる形式になります。
具体的には、ユーザーがiPhoneアプリで非アクティブ状態になると、次の値を保存します。
exitDate = [NSDate date];
そして、彼らがアプリをバックアップして開くと、現在の時刻を取得します。
NSDate *now = [NSDate date];
次に、以下を実装したいと思います。
-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now
以下は、2つの日付間の暦日数を決定するために使用した実装です。
+ (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];
}
編集:
上記の素晴らしい解決策は、以下のSwiftバージョンが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
}
}
ユースケースに応じて、削除する必要がある可能性のある、多少の強制的なアンラッピング。
上記のソリューションは、現在のタイムゾーン以外のタイムゾーンでも機能し、世界中の場所に関する情報を表示するアプリに最適です。
これが私が見つけた最良の解決策です。 NSDates間の単位数を決定するためにApple承認された方法を利用するようです。
- (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;
}
例えば。月も必要な場合は、「NSMonthCalendarUnit」をunitFlagとして含めることができます。
元のブロガーを称賛するために、私はここでこの情報を見つけました(上で修正したわずかな間違いはありましたが): http://cocoamatic.blogspot.com/2010/09/nsdate-number-of- days-between-two-dates.html?showComment = 1306198273659#c6501446329564880344
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
}
}
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
}
}
元のソリューション
Swiftの別のソリューション。
2つの日付の間に正確な日番号を取得することが目的の場合、次のようにこの問題を回避できます。
// 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
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);
}
開始日を含む2つの日付の間の日数が必要でした。例えば2012年12月14日から2012年2月16日までの日数は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;
}
日付を指定する順序は関係ありません。常に正の数を返します。
NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;
dateDiffは、2つの日付間の秒数になります。 1日の秒数で割るだけです。
@ブライアン
ブライアンの答えは良好ですが、24時間単位で日数の差を計算するだけで、暦日の差は計算しません。たとえば、12月24日の23:59は、まだ1日と見なされる多くのアプリケーションの目的のために、クリスマスからわずか1分です。 BrianのdaysBetween関数は0を返します。
ブライアンの元の実装と一日の始まり/終わりから借りて、私は私のプログラムで次を使用します:( NSDate一日の始まりと一日の終わり )
- (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;
}
}
SwiftでのBrianの関数の実装は次のとおりです。
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
}
Swiftでこれを行おうとしてこのページにアクセスした人に答えを追加するだけです。アプローチはほとんど同じです。
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
}
この答えは、次の方法のディスカッションセクションで here で見つかりました。
components(_:fromDate:toDate:options:)
別のアプローチ:
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;
タイムゾーンを考慮できるというtimeIntervalSince...
スキームよりも利点があり、1日の数秒の短い間隔または長い間隔であいまいさはありません。
また、NSDateComponentsアプローチよりも少しコンパクトで混乱が少ないです。
手に入れた、それが正確にあなたが望むものであるかどうかわからないが、それはあなたの何人かを助けるかもしれない、(私を助けた!!)
私の目標は、2つの日付(24時間以内の差)の間に「終日」day + 1があったかどうかを知ることでした:
私は次のことをしました(少し古風な私は認めます)
NSDate *startDate = ...
NSDate *endDate = ...
NSDateはすでに別のNSDateFormatterによってフォーマットされています(これはこの目的のためだけです:)
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");
}
このようなものはすでに存在しているかもしれませんが、見つけられませんでした
ティム
暦日ですか、それとも24時間ですか。つまり、火曜日は水曜日の午前6時の前日の午後9時ですか、それとも1日未満ですか?
前者の場合は少し複雑であり、NSCalendar
およびNSDateComponent
を介した操作に頼らなければなりません。
後者を意味する場合は、基準日から日付の時間間隔を取得し、一方から他方を減算し、24時間(24 * 60 * 60
)で割って、うるう秒を含まないおおよその間隔を取得します。
なぜだけではありません:
int days = [date1 timeIntervalSinceDate:date2]/24/60/60;
私が見つけた解決策は:
+(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;
}
ここでは、1日の始まりから開始する最初の日付を効果的に丸めて、ジョナサンが上で示唆しているように差を計算しています...
これを行うために、オープンソースのクラス/ライブラリを公開しました。
RelativeDateDescriptor をご覧ください。これは、次のように時差を取得するために使用できます。
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'