Метод NSDateComponentsFormatter stringFromDate:ToDate: каждую секунду возвращает другое значение
Я пытаюсь получить количество дней между сегодняшней датой и будущей датой. Я вызываю следующее каждую секунду:
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:2025];
[components setMonth:1];
[components setDay:1];
NSDate *currentDate = [NSDate date];
NSDate *futureDate = [[NSCalendar currentCalendar] dateFromComponents:components];
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorNone;
formatter.allowedUnits = NSCalendarUnitDay;
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleAbbreviated;
NSString *remainingDaysAsString = [formatter stringFromDate:currentDate toDate:futureDate];
Я печатаю переменную Остаток DaysAsString каждую секунду, и она всегда отличается на день.
3,551d
3,551d
3,550d
3,550d
3,551d
3,550d
3,551d
Кто-нибудь испытывал нечто подобное? Это похоже на ошибку в классе?
3 ответа
Это странно и похоже на ошибку. Результат NSDateComponentsFormatter
правильно (в моем тесте), если вы указываете все единицы с точностью до секунд:
formatter.allowedUnits = NSCalendarUnitDay + NSCalendarUnitHour + NSCalendarUnitMinute + NSCalendarUnitSecond;
Более простой и надежный способ получить количество дней между двумя датами
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitDay
fromDate:currentDate
toDate:futureDate
options:0];
NSInteger days = comp.day;
У меня та же проблема:
let fmt1 = NSDateComponentsFormatter()
fmt1.allowedUnits = .CalendarUnitYear |
.CalendarUnitMonth |
.CalendarUnitDay
let dc1 = NSDateComponents()
dc1.month = 1
dc1.day = 15
// This occasionally outputs "1 month, 14 days" instead of
// "1 month, 15 days" when the formatter is constrained to
// years, months and days. If formatter is allowed to use
// all units, the output is "1 month, 14 days, 23 hours,
// 59 minutes, 59 seconds".
fmt1.stringFromDateComponents(dc1)
Это можно исправить, указав положительное количество секунд и объединив его с ограничением разрешенных единиц и / или настройкой maximumUnitCount
параметр formatter для фиксированного значения:
let fmt2 = NSDateComponentsFormatter()
fmt2.allowedUnits = .CalendarUnitYear |
.CalendarUnitMonth |
.CalendarUnitDay
fmt2.maximumUnitCount = 2
fmt2.collapsesLargestUnit = true
let dc2 = NSDateComponents()
dc2.month = 1
dc2.day = 15
dc2.second = 10
// This always outputs "1 month, 15 days"
fmt2.stringFromDateComponents(dc2)
Так что, в вашем случае, просто назначьте некоторое положительное количество секунд для NSDateComponents
:
[components setYear:2025];
[components setMonth:1];
[components setDay:1];
[components setSecond:10];
Это предотвратит ошибки округления.
Я не знаю о проблеме, которую вы описываете, просто хочу, чтобы вы знали альтернативный метод.
NSDate * date1;
NSDate * date2;
//assuming both vars contain a date
NSTimeInterval duration = [date2 timeIntervalSince1970] - [date1 timeIntervalSince1970];
NSLog("@days between %@ and %@: %f", date1, date2, duration / (24 * 60 * 60));