День рождения CNContact отображается с разницей в часовом поясе
Я пытаюсь узнать день рождения человека, которого я получаю в приложении «Контакты», с помощью ContactsCN Framework.
День рождения человека в приложениях «Контакты» — 22 июня 1980 года .
В моем приложении фактический результат — 21 июня 1980 года . Желаемый результат — 22 июня 1980 года, как и день рождения в приложении «Контакты».
Разница заключается в часовом поясе -4 часа. Я пытался поиграть с часовыми поясами и другими опциями в своих форматтерах, но безуспешно. Содержимое атрибута даты .description отображает правильную информацию « 1980-06-22 00:00:00 +0000 ». Как я могу получить правильную дату для отображения в моем приложении?
Я пробовал разные сценарии:
- без форматирования (но в конце мне нужно отформатировать дату)
- формат без часового пояса
- форматировать с помощью TimeZone.current
- форматировать с помощью TimeZone.gmt
- формат с помощью TimeZone.init(секундыFromGMT: 14000)
- формат с помощью TimeZone.init(секундыFromGMT: -14000)
Примечание. 14000 — это разница во времени между EST и GMT.
Я сделал тот же тест с текущей датой для сравнения.
Это код моего теста
import SwiftUI
import ContactsUI
struct TestWithCNContactView: View {
let contactStore = CNContactStore()
@State private var searchName:String = "apple"
@State private var contacts = [CNContact]()
var body: some View {
Text("locale : \(Locale.preferredLanguages[0]), timezone : \(TimeZone.current)").padding()
TextField("Enter the name to find in Contacts", text: $searchName, onCommit: fetchContacts).padding()
Divider()
if contacts.count > 0 {
ScrollView {
VStack (alignment: .leading) {
ForEach(contacts, id: \.self) { contact in
if let date1 = contact.birthday?.date {
HStack {Text(contact.givenName)
Text(contact.familyName)}.font(.title).padding(.top)
testDisplayDate(title: "contact bday",date: date1)
}
}
Divider()
testDisplayDate(title: "Date()",date: Date())
}.padding()
}
}
}
func fetchContacts() {
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactBirthdayKey] as [CNKeyDescriptor]
let predicate = CNContact.predicateForContacts(matchingName: searchName)
contacts = try! contactStore.unifiedContacts(matching: predicate, keysToFetch: keysToFetch )
}
}
struct testDisplayDate: View {
var title: String
var date: Date?
var body: some View {
Text(title).font(.title2).padding(.top)
if let date = date {
Text("date (no formatting) : \(date)")
Text(".description : \(date.description)")
Text("dateFormatter : \(date, formatter: dateFormatter)")
Text("dateFormatterGMT : \(date, formatter: dateFormatterGTM)")
Text("dateFormatterFull : \(date, formatter: dateFormatterFull)")
Text("dateFormatterFullGMT : \(date, formatter: dateFormatterFullGMT)")
} else {
Text("no date")
}
}
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "d MMMM"
formatter.timeZone = TimeZone.current
return formatter
}
var dateFormatterGTM: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "d MMMM"
formatter.timeZone = TimeZone.gmt
return formatter
}
var dateFormatterFull: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
formatter.timeZone = TimeZone.current
return formatter
}
var dateFormatterFullGMT: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
formatter.timeZone = TimeZone.gmt
return formatter
}
}
Я включил изображение с информацией о человеке в приложения «Контакты» и результат моего тестового кода.
Любой вклад будет оценен по достоинству.
Спасибо
2 ответа
Струнаinit(_:formatter:)
кажется, игнорирует информацию о часовом поясе. Вместо этого используйте DateFormatter.string(from: Date)
параметр.
...
var body: some View {
Text(title).font(.title2).padding(.top)
if let date = date {
Text("date (no formatting) : \(date)")
Text(".description : \(date.description)")
Text("dateFormatter : \(dateFormatter.string(from: date))")
Text("dateFormatterGMT : \(dateFormatterGTM.string(from: date))")
Text("dateFormatterFull : \(dateFormatterFull.string(from: date))")
Text("dateFormatterFullGMT : \(dateFormatterFullGMT.string(from: date))")
} else {
Text("no date")
}
}
...
В приведенном выше коде результат соответствует ожиданиям.
Я продолжил свое расследование. Я обнаружил, что для атрибута «День рождения» типа DateComponents поле timeZone равно нулю , и это влияет на результат. Итак, есть 2 способа компенсировать это:
- сделайте расширение CNContact и создайте свой собственный атрибут
extension CNContact {
var birthDayCurrentTimeZone: DateComponents? {
if var bdayDC = birthday {
bdayDC.timeZone = TimeZone.current
return bdayDC
} else {return self.birthday}
}
}
и используйте его вместо дня рождения.
- вычислить дату перед использованием средства форматирования даты
let bdayWithTimeZone = Calendar.current.date(byAdding: .hour, value: TimeZone.current.secondsFromGMT() / 3600 * -1, to: contact.birthday.date)!)
еще раз спасибо
Пэт