#ios #swift #date #nsdatecomponents
#iOS #swift #Дата #компоненты nsdatecomponents
Вопрос:
Дата окончания месяца указывает другую дату для часового пояса Оттавы, Канада (переход на летнее время).
Я пытаюсь получить дату окончания месяца в любом часовом поясе.
Примечание: Вы можете помочь мне, изменив настройки часового пояса (Mac или iphone) в Оттаве, Канада. и вставьте код в playground
extension Date {
public func setTime(day: Int, month: Int,year:Int, timeZoneAbbrev: String = "UTC") -> Date {
let x: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
let cal = Calendar.current
var components = cal.dateComponents(x, from: self)
components.timeZone = TimeZone(abbreviation: timeZoneAbbrev)
components.hour = 0
components.minute = 0
components.second = 0
components.day = day
components.month = month
components.year = year
return cal.date(from: components) ?? self
}
func getMonthGapDate(month: Int) -> Date {
return Calendar.current.date(byAdding: .month, value: month, to: self)!
}
func startOfMonth() -> Date {
return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
}
func endOfMonth() -> Date {
return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
}
}
let firstDayDate = Date().setTime(day: 1, month: 4, year: 2019)
let startDate = firstDayDate.getMonthGapDate(month: -1)
let endDate = firstDayDate.endOfMonth()
print(firstDayDate)
print(startDate)//Prints 2019-03-01 01:00:00 0000(Ottawa - Canada time zone) Day light zone
print(endDate)// (This is issue)Prints 2019-03-31 04:00:00 0000(Ottawa - Canada time zone) Day light zone//It should 2019 - 04 - 30
Комментарии:
1. Какой результат вы ожидаете? Летнее время в Оттаве — GMT-4, поэтому полночь в Оттаве равна 04:00:00 по UTC, что и показано.
2. Помогло бы, если бы другие функции вашего расширения использовали тот же часовой пояс, что и
setTime
?3. Во всяком случае, ваша дата начала выглядит неправильно. 1 марта летнее время не действовало, поэтому оно должно быть 05:00:00, поскольку в Оттаве обычно UTC-5
4. Вы, вероятно, хотите использовать
components.timeZone=TimeZone.autoupdatingCurrent
вместо UTC. Это даст вам даты, которые имеют локальную полночь в первый и последний дни месяца.5. Если я использую
autoupdatingCurrent
и устанавливаю свой часовой пояс на Оттаву, я получаю2019-04-01 04:00:00 0000 2019-03-01 05:00:00 0000 2019-04-30 04:00:00 0000
то, чего я ожидал
Ответ №1:
Использование сокращений часовых поясов может быть проблематичным, хотя «UTC» довольно безопасен.
Однако я подозреваю, что вам следует использовать TimeZone.autoupdatingCurrent
, чтобы убедиться, что вы получаете даты с местной полуночью.
extension Date {
public func setTime(day: Int, month: Int,year:Int) -> Date {
let x: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
let cal = Calendar.current
var components = cal.dateComponents(x, from: self)
components.timeZone = TimeZone.autoupdatingCurrent
components.hour = 0
components.minute = 0
components.second = 0
components.day = day
components.month = month
components.year = year
return cal.date(from: components) ?? self
}
func getMonthGapDate(month: Int) -> Date {
return Calendar.current.date(byAdding: .month, value: month, to: self)!
}
func startOfMonth() -> Date {
return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
}
func endOfMonth() -> Date {
return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
}
}
Это дает мне следующий результат:
2019-04-01 04:00:00 0000
2019-03-01 05:00:00 0000
2019-04-30 04:00:00 0000
Обратите внимание на 0000 — Даты указаны в UTC, но представляют собой местную полночь.
- В начале марта Оттава не использует летнее время, поэтому сейчас UTC-5
- В конце марта Оттава использует летнее время, поэтому сейчас UTC-4
Комментарии:
1. можете ли вы сказать, в зоне каких стран происходят изменения (например, в марте в Канаде)?
2. У каждой страны свои правила летнего времени, и они могут даже меняться из года в год и от штата к штату (например, в Австралии летнее время в Новом Южном Уэльсе, Виктории, Аделаиде и Тасмании, но не в Квинсленде или Западной Австралии. Иногда состояния с переходом на летнее время меняются на разные даты). Как правило, iOS обновляется новыми правилами по мере внесения изменений, и
Calendar
класс обрабатывает их за вас.3. Вы также можете использовать
daylightSavingTimeOffset()
функциюTimeZone
, чтобы определить, действует ли переход на летнее время для данного часового пояса на данную дату