Календарь.nextDate() ведет себя очень странно при использовании.назад для направления. Только на последний день месяца.
В моем приложении мне нужно получить предыдущие 4 утра, а не 4 утра текущей даты.
Например:
- если это
March 05, 10:00 am
, то я должен ожидать, что вернусь:March 05, 4:00 am
- если это
March 05, 02:00 am
, то я должен ожидать, что вернусь:March 04, 4:00 am
Для достижения этого я использую Calendar.nextDate
. Он хорошо работает для каждого дня месяца, за исключением последнего дня каждого месяца.
let components = DateComponents(hour: 4, minute: 0, second: 0)
let date = Calendar.current.date(from: DateComponents(year: 2018,
month: 03,
day: 05,
hour: 13,
minute: 25,
second: 0))!
let result = Calendar.current.nextDate(after: date,
matching: components,
matchingPolicy: .nextTime,
direction: .backward)
Вывод:
date = "Mar 5, 2018 at 1:25 PM"
result = "Mar 5, 2018 at 4:00 AM"
Это пример темного печального пути, где он не действует так, как ожидалось:
let components = DateComponents(hour: 4, minute: 0, second: 0)
let date = Calendar.current.date(from: DateComponents(year: 2018,
month: 03,
day: 31,
hour: 13,
minute: 25,
second: 0))!
let result = Calendar.current.nextDate(after: date,
matching: components,
matchingPolicy: .nextTime,
direction: .backward)
Вывод:
date = "Mar 31, 2018 at 1:25 PM"
result = "Mar 30, 2018 at 4:00 AM"
// it should give me this instead: "Mar 31, 2018 at 4:00 AM"
Любые идеи, почему это происходит? это ошибка в коде Apple, должен ли я сообщить об этом? или я использую это неправильно?
Если это ошибка Apple, есть ли другой способ достичь того, что мне нужно в то же время?
Обновление:
Просмотрев исходный код Swift, я заметил, что проблема не в функции Calendar.nextDate()
конкретно. nextDate()
использует Calendar.enumerateDates()
и вот где настоящая проблема. Однако я не смог найти исходный код для этой функции.
Это та же ошибка с использованием Calendar.enumerateDates()
:
let components = DateComponents(hour: 4, minute: 0, second: 0)
let date = Calendar.current.date(from: DateComponents(year: 2018,
month: 03,
day: 31,
hour: 13,
minute: 25,
second: 0))!
Calendar.current.enumerateDates(startingAfter: inputDate,
matching: components,
matchingPolicy: .nextTime,
direction: .backward) { (date, exactMatch, stop) in
let result = date
// result = "Mar 30, 2018 at 4:00 AM"
stop = true
}
Кроме того, это похожий вопрос: календарь Свифта.enumerateDates дает неверный результат, начиная с февраля
1 ответ:
Похоже, что это ошибка, о которой следует сообщить Apple. Убедитесь, что вы включили запускаемое тестовое приложение, демонстрирующее проблему. Обратите внимание, что эта ошибка появляется только в iOS. В macOS (по крайней мере, на игровой площадке macOS) код работает, как и ожидалось.
В то же время существует довольно простой обходной путь.
Измените код, чтобы использовать
.forward
вместо.backward
. Это даст следующую дату вместо предыдущей даты. Там, кажется, нет никаких ошибок, идущих в этом направлении. Затем используйте:Calendar.current.date(byAdding: .day, value: -1, date: result)
Чтобы получить желаемый результат, вернитесь на один день назад.