Как я могу игнорировать часовые пояса в быстрых датах?

#swift #datetime #timezone

#swift #дата и время #Часовой пояс

Вопрос:

Я хочу использовать Swift 5 для создания объекта Date с указанием дня, месяца и года, которые я передаю. Проблема в том, что DateFormatter имеет свои собственные идеи и, похоже, обрабатывает мои объекты Date так, как если бы они были UTC, даже независимо от того, что я установил <formatter>.timeZone = ... .

Допустим, мне нужен объект t date с датой первого апреля.

 private func firstOfApril() -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    return "(formatter.date(from: "2021-04-01")!)"
}

 

Если я сделаю это в AM here (GMT 13), я получу 2021-03-31 11:00:00 0000 . Я ожидаю: 2021-04-01 00:00:00

Что я пробовал:

 enum TZType{
    case None
    case Current
    case Auto
    case Nil
    case Default
}
private func firstOfApril(none_current:TZType) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    switch none_current {
    case .None:
        formatter.timeZone = .none
    case .Current:
        formatter.timeZone = .current
    case .Nil:
        formatter.timeZone = nil
    case .Auto:
        formatter.timeZone = .autoupdatingCurrent
    case .Default:
        break
    }
    return "(formatter.date(from: "2021-04-01")!)"
}
 
         print(firstOfApril(none_current: .None))
        print(firstOfApril(none_current: .Current))
        print(firstOfApril(none_current: .Auto))
        print(firstOfApril(none_current: .Nil))
        print(firstOfApril(none_current: .Default))
 

Выводит

 2021-03-31 11:00:00  0000
2021-03-31 11:00:00  0000
2021-03-31 11:00:00  0000
2021-03-31 11:00:00  0000
 

В моем приложении нет понятия часовых поясов. Я думаю, что должно быть, но я отклонен. Все время — это «местное время», как в настенных часах, а не в местном часовом поясе.

Комментарии:

1. Проблема в том, что вам также необходимо использовать форматирование даты при преобразовании даты в строку. Когда вы печатаете (или используете интерполяцию строк) свою дату, она всегда будет выводить часовой пояс UTC ( 0000)

2. private func firstOfApril() -> String { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" let date = formatter.date(from: "2021-04-01")! return formatter.string(from: date) } // «2021-04-01»

Ответ №1:

Лео понял это.

Последние строки этой функции должны быть:

     let retDate = formatter.date(from: "2021-04-01")!
    return formatter.string(from: retDate)
 

Всего:

 private func firstOfApril(none_current:TZType) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    switch none_current {
    case .None:
        formatter.timeZone = .none
    case .Current:
        formatter.timeZone = .current
    case .Nil:
        formatter.timeZone = nil
    case .Auto:
        formatter.timeZone = .autoupdatingCurrent
    case .Default:
        break
    }
    let retDate = formatter.date(from: "2021-04-01")!
    return formatter.string(from: retDate)
}
 

Ответ №2:

Вы получили некоторую хорошую, но неполную информацию.

Объект даты фиксирует момент времени в любой точке планеты. Он лишен часового пояса. (Внутренне оно записывается на несколько секунд с момента ввода «даты эпохи» в iOS / macOS или «нулевой даты». Эта нулевая дата находится в UTC.)

Объекты даты не имеют часового пояса, но у них также нет фиксированного времени или даты. Один и тот же момент времени будет в разное время суток в разных часовых поясах и может даже быть разными датами (например, около 7 часов вечера в понедельник, 29 марта, здесь, в часовом поясе Восточного дневного времени США. Во вторник, 30 марта, в Лондоне около полуночи.)

Если вы создадите средство форматирования даты и введете в него месяц / день / год, по умолчанию будет создан объект Date с использованием вашего местного часового пояса. Часовой пояс имеет не объект Date, а средство форматирования даты.

Вы можете либо использовать форматировщик даты, который вы уже создали, чтобы преобразовать даты обратно в строки (используя функцию string(from:) DateFormatter , или вы можете использовать вызываемую функцию класса localizedString(from:dateStyle:timeStyle: DateFormatter . Эта функция принимает дату и отображает ее в вашем местном часовом поясе, используя условные обозначения вашего региона, и позволяет вам указывать даты в коротком, среднем или длинном формате.

Если вы напишете

 let date = Date()
print(DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .medium))
 

Вы получите что-то вроде этого:

 Mar 29, 2021 at 7:07:13 PM
 

Это выражается в моем местном часовом поясе с использованием американских форматов даты и времени.

(Но с указанием даты и времени, в которые вы его запускаете, и с использованием соглашений о форматировании даты и времени для вашего региона.)

Далее, это то, как вы отображаете дату. Если вы напишете код

 print(Date())
 

То, что вы увидите, — это дата на момент запуска кода, но выраженная в UTC. Для меня это будет на 4 часа раньше моего текущего времени, так что он будет утверждать, что сейчас около 23:00 30 января.

 2021-03-29 23:00:48  0000
 

Если вы находитесь в Китае, а я в США, и часы наших телефонов точно синхронизированы, и мы фиксируем текущую дату, используя Date() в одно и то же мгновение, мы получим точно такое же значение даты. Если бы мы оба выражали это в UTC, он показывал бы одну и ту же дату и время. (У объекта Date нет времени

Комментарии:

1. Дело в том, в каком часовом поясе я передаю форматировщик, чтобы не изменять передаваемые значения.