Проблема в том, что вы смешиваете часовые пояса.
Использование Z
в форматах даты и анализируемых вами строк даты означает, что эти строки даты рассматриваются как находящиеся в часовом поясе UTC. Это может или не может быть то, что вы хотите.
Использование Calendar.current.isDate
означает, что две даты сравниваются с использованием вашего текущего часового пояса, а не часового пояса UTC. Таким образом, в зависимости от того, где вы живете и как далеко даты полуночи даны от полуночи, две даты могут быть в один и тот же день в одном часовом поясе, но в два разных дня в другом часовом поясе.
Ваш код может быть совершенно правильным, как только вы поймете, что "странные" результаты на самом деле верны в зависимости от заданных часовых поясов.
Вам необходимо определить, какой часовой пояс представляют строки даты / времени. Затем вам нужно определить, в каком часовом поясе вы хотите их сравнить.
Пример (для кого-то, живущего в восточной части США, где сейчас UTC-5)
Вы анализируете строку 2017-08-28 13:06:54Z
. Это время в часовом поясе UTC. Вы можете видеть это в вашем выводе 2017-08-28 13:06:54 +0000
.
Вы также разбираете 2017-08-28Z
. Это рассматривается как полуночное время UTC. Печать этого Date
покажет 2017-08-28 00:00:00 +0000
.
В UTC время эти две даты совпадают.
Однако, когда вы используете Calendar.current
, он смотрит на даты по вашему местному времени (UTC-5 в этом примере).
Это означает, что первая дата по местному времени - 2017-08-28 08:06:54 -0500
, а вторая дата по местному времени - 2017-08-27 19:00:00 -0500
.
По местному времени эти две даты не совпадают.
Решение:
Если вы хотите, чтобы все даты рассматривались как даты UTC, и вы хотите сравнить каждый набор дат в часовом поясе UTC, то вы должны обновить свой код примерно так:
let utc = TimeZone(secondsFromGMT: 0)!
let dfCandidate = DateFormatter()
dfCandidate.timeZone = utc
dfCandidate.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dfMatching = DateFormatter()
dfMatching.timeZone = utc
dfMatching.dateFormat = "yyyy-MM-dd"
guard let matchingDate = dfMatching.date(from: "2017-08-28") else {
preconditionFailure()
}
let dates1 = [
"2017-08-28 13:06:54",
"2017-08-28 04:22:42"
]
let dates2 = [
"2017-08-28 00:00:01",
"2017-08-28 20:24:00"
]
var utcCalendar = Calendar.current
utcCalendar.timeZone = utc
let matchingDates: [Date] = dates1
.map { candidateDate in
guard let date = dfCandidate.date(from: candidateDate) else {
return nil
}
let isInDate = utcCalendar.isDate(date, equalTo: matchingDate, toGranularity: Calendar.Component.day)
print("\(isInDate) comparing \(String(describing: date)) to matching \(String(describing: matchingDate))")
return isInDate ? date : nil
}
.appending(contentsOf: dates2.map { candidateDate in
guard let date = dfCandidate.date(from: candidateDate + "Z") else {
return nil
}
let isInDate = utcCalendar.isDate(date, equalTo: matchingDate, toGranularity: Calendar.Component.day)
print("\(isInDate) comparing \(String(describing: date)) to matching \(String(describing: matchingDate))")
return isInDate ? date : nil
})
.compactMap { $0 }
print(matchingDates)
Это создает часовой пояс UTC и использует его с обоими форматерами даты, а также создает календарь, установленный в часовом поясе UTC для сравнения дат.