#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. Дело в том, в каком часовом поясе я передаю форматировщик, чтобы не изменять передаваемые значения.