Календарь: получить компоненты даты, странный случай
Я пытаюсь выяснить, почему этот кусок кода работает так странно. Вы можете найти детали ниже:
let nowDate = Date()
let threeDayBeforeNowDate_t1 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 3)
let oneDayAfterNowDate = Date(timeIntervalSinceNow: 60 * 60 * 24 * 1)
let threeDayBeforeNowDate_t2 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 3)
let threeDayBeforeNowDate = nowDate.addingTimeInterval(-60 * 60 * 24 * 3)
let diff_1 = threeDayBeforeNowDate_t1.timeIntervalSince(nowDate) - threeDayBeforeNowDate.timeIntervalSince(nowDate) // about 0.009357
let diff_2 = threeDayBeforeNowDate_t2.timeIntervalSince(nowDate) - threeDayBeforeNowDate.timeIntervalSince(nowDate) // about 0.010063
let diff_3 = threeDayBeforeNowDate_t2.timeIntervalSince(nowDate) - threeDayBeforeNowDate_t1.timeIntervalSince(nowDate) // about 0.000416
let calendar = Calendar.current
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate, to: oneDayAfterNowDate) // result = "day: 4 isLeapMonth: false"
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate_t1, to: oneDayAfterNowDate) // day: 4 isLeapMonth: false
calendar.dateComponents(Set([Calendar.Component.day]), from: threeDayBeforeNowDate_t2, to: oneDayAfterNowDate) // day: 3 isLeapMonth: false
Я не понимаю, почему я получаю такие разные результаты, в то время как даты (threeDayBeforeNow...) отличаются менее чем на секунду.
2 ответа
Как уже объяснил Давид, проблема в том, что различные даты рассчитываются в разные моменты времени, поэтому разница не составляет ровно 4 дня. В частности, разница междуthreeDayBeforeNowDate_t2
а также oneDayAfterNowDate
менее 4 дней, и поэтому .day
Компонент разницы 3
,
Вот упрощенный пример, демонстрирующий проблему (на игровой площадке):
let nowDate = Date()
let date1 = Date(timeIntervalSinceNow: -60 * 60 * 24 * 4)
let date2 = nowDate.addingTimeInterval(-60 * 60 * 24 * 4)
let calendar = Calendar.current
calendar.dateComponents([.day, .hour, .minute, .second, .nanosecond], from: date1, to: nowDate)
// day: 3 hour: 23 minute: 59 second: 59 nanosecond: 994143066 isLeapMonth: false
calendar.dateComponents([.day, .hour, .minute, .second, .nanosecond], from: date2, to: nowDate)
// day: 4 hour: 0 minute: 0 second: 0 nanosecond: 0 isLeapMonth: false
date2
а также nowDate
отличаются ровно на 4 дня, но date1
а также nowDate
Разница будет немного меньше, чем 4 дня (при условии, что в этот промежуток времени переход на летнее время отсутствует).
Проблема в том, что между созданием nowDate
и ваши другие переменные, где вы используете Date(timeIntervalSinceNow:)
инициализатор.
И то и другое Date()
а также Date(timeIntervalSinceNow:)
используйте системное время, чтобы получить текущее время, когда выполнение достигает этой конкретной переменной. Независимо от того, насколько малым, всегда будет небольшая задержка между различными вызовами системного времени и, следовательно, даже если вы создадите два Date
объекты, использующие Date()
в двух последовательных строках кода они не будут представлять один и тот же момент времени.
Работая на игровой площадке, следующий фрагмент кода демонстрирует это поведение:
let now1 = Date()
let now2 = Date()
now1.timeIntervalSince(now2) //-0.0002049803733825684
Если вы хотите последовательный Date
объекты, создать единственную переменную, в которой вы храните дату создания, используя Date()
как вы делаете в данный момент для nowDate
затем используйте эту же переменную для создания другого Date
объекты, использующие nowDate.addingTimeInterval()
как вы в настоящее время делаете для threeDayBeforeNowDate
,