День рождения 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 способа компенсировать это:

  1. сделайте расширение CNContact и создайте свой собственный атрибут
      extension CNContact {
    var birthDayCurrentTimeZone: DateComponents?  {
        if var bdayDC = birthday {
            bdayDC.timeZone = TimeZone.current
            return bdayDC
        } else {return self.birthday}
    }
}

и используйте его вместо дня рождения.

  1. вычислить дату перед использованием средства форматирования даты
      let bdayWithTimeZone = Calendar.current.date(byAdding: .hour, value: TimeZone.current.secondsFromGMT() / 3600 * -1, to: contact.birthday.date)!)

еще раз спасибо

Пэт

Другие вопросы по тегам