Alk*_*Alk 12 timezone nsdate gmt ios swift
我有一个存储在我的在线服务器数据库中的日期GMT.我使用以下代码加载日期并将其转换为用户的时区:
if let messagedate = oneitem["timestamp"] as? String {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = dateFormatter.dateFromString(messagedate)
let source_timezone = NSTimeZone(abbreviation: "GMT")
let local_timezone = NSTimeZone.systemTimeZone()
let source_EDT_offset = source_timezone?.secondsFromGMTForDate(date!)
let destination_EDT_offset = local_timezone.secondsFromGMTForDate(date!)
let time_interval : NSTimeInterval = Double(destination_EDT_offset - source_EDT_offset!)
let final_date = NSDate(timeInterval: time_interval, sinceDate: date!)
curr_item.date = final_date
}
Run Code Online (Sandbox Code Playgroud)
现在我需要将日期转换回来GMT以便将它传递给服务器,但是我不知道如何将其转换回来GMT.
Aml*_*xer 14
难道你不能再使用不同时区的数据格式化器并进行转换吗?如
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
let gmtDate = dateFormatter.dateFromString(string: "your old date as string here")
Run Code Online (Sandbox Code Playgroud)
由于NSDate始终采用 GMT/UTC,因此时区仅在向用户显示或从用户处获取时才变得相关。只要始终在内部假设它是 UTC,根据需要为用户转换(通过在 上设置NSDateFormatter),您就不必再担心这个问题了。
效率提高约50倍
extension Date {
func convertToLocalTime(fromTimeZone timeZoneAbbreviation: String) -> Date? {
if let timeZone = TimeZone(abbreviation: timeZoneAbbreviation) {
let targetOffset = TimeInterval(timeZone.secondsFromGMT(for: self))
let localOffeset = TimeInterval(TimeZone.autoupdatingCurrent.secondsFromGMT(for: self))
return self.addingTimeInterval(targetOffset - localOffeset)
}
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
基于mukaissi 的回答,但已更正表达式中的免赔额顺序。
extension Date {
func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
let delta = TimeInterval(initTimeZone.secondsFromGMT() - targetTimeZone.secondsFromGMT())
return addingTimeInterval(delta)
}
}
Run Code Online (Sandbox Code Playgroud)
dbplunkett 的答案是完全正确的,即使用 不能有效地处理夏令时secondsFromGMT(for: date),但是他们的扩展示例适用于Calendar. 以下扩展实现date了相同的目标:
extension Date {
func convert(from timeZone: TimeZone, to destinationTimeZone: TimeZone) -> Date {
let calendar = Calendar.current
var components = calendar.dateComponents(in: timeZone, from: self)
components.timeZone = destinationTimeZone
return calendar.date(from: components)!
}
}
Run Code Online (Sandbox Code Playgroud)
更简单的版本:
extension Date {
func convertToTimeZone(initTimeZone: TimeZone, timeZone: TimeZone) -> Date {
let delta = TimeInterval(timeZone.secondsFromGMT() - initTimeZone.secondsFromGMT())
return addingTimeInterval(delta)
}
}
Run Code Online (Sandbox Code Playgroud)
在撰写本文时,大多数答案都包含 DST 切换时间附近的边缘案例错误(请参阅我关于下面其他答案的注释)。如果你只是想一个日期转换字符串与没有时间偏移到Date在特定的时间段,Amloelxer的回答是最好的,但对于那些以“如何转换的问题的利益Date时区之间”,有两种情况:
将 a 转换Date为另一个时区,同时保留初始时区的日期和时间。
例如 GMT 到 EST:2020-03-08T10:00:00Z到2020-03-08T10:00:00-04:00
将 a 转换为Date另一个时区的日期和时间,同时保留初始时区。
例如对于 EST 到 GMT:2020-03-08T06:00:00-04:00到2020-03-08T10:00:00-04:00(因为初始时间Date是格林威治标准时间的上午 10 点)
这两种情况实际上是相同的(示例 start 和 endDate是相同的),只是它们的措辞不同以交换哪个时区是“初始”,哪个是“目标”。因此,如果您在它们之间交换时区,则下面的两种解决方案是等效的,因此您可以选择在概念上更适合您的用例的一种。
extension Calendar {
// case 1
func dateBySetting(timeZone: TimeZone, of date: Date) -> Date? {
var components = dateComponents(in: self.timeZone, from: date)
components.timeZone = timeZone
return self.date(from: components)
}
// case 2
func dateBySettingTimeFrom(timeZone: TimeZone, of date: Date) -> Date? {
var components = dateComponents(in: timeZone, from: date)
components.timeZone = self.timeZone
return self.date(from: components)
}
}
// example values
let initTz = TimeZone(abbreviation: "GMT")!
let targetTz = TimeZone(abbreviation: "EST")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 4))!
// usage
var calendar = Calendar.current
calendar.timeZone = initTz
let case1TargetDate = calendar.dateBySetting(timeZone: targetTz, of: initDate)!
let case2TargetDate = calendar.dateBySettingTimeFrom(timeZone: targetTz, of: initDate)!
// print results
let formatter = ISO8601DateFormatter()
formatter.timeZone = targetTz // case 1 is concerned with what the `Date` looks like in the target time zone
print(formatter.string(from: case1TargetDate)) // 2020-03-08T04:00:00-04:00
// for case 2, find the initial `Date`'s time in the target time zone
print(formatter.string(from: initDate)) // 2020-03-07T23:00:00-05:00 (the target date should have this same time)
formatter.timeZone = initTz // case 2 is concerned with what the `Date` looks like in the initial time zone
print(formatter.string(from: case2TargetDate)) // 2020-03-07T23:00:00Z
Run Code Online (Sandbox Code Playgroud)
在撰写本文时,大多数其他答案都假设上述两种情况之一,但更重要的是,它们共享一个错误 - 他们尝试计算时区之间的时差,其中差异的符号决定了这种情况:
情况1:
initialTz.secondsFromGMT(for: initialDate) - targetTz.secondsFromGMT(for: initialDate)
Run Code Online (Sandbox Code Playgroud)
案例2:
targetTz.secondsFromGMT(for: initialDate) - initialTz.secondsFromGMT(for: initialDate)
Run Code Online (Sandbox Code Playgroud)
secondsFromGMT取Date你想知道偏移量的 ,所以在这两种情况下,目标偏移量应该真的是targetTz.secondsFromGMT(for: targetDate),这是一个 catch-22,因为我们还不知道目标日期。然而,在大多数情况下,Dates 接近,因为它们在这里targetTz.secondsFromGMT(for: initialDate)并且targetTz.secondsFromGMT(for: targetDate) 相等- 只有当它们不同时才会发生错误,当Date目标时区中的两个s之间的时间偏移发生变化时,例如 DST ,就会发生这种情况。以下是每种情况的错误示例:
extension Date {
// case 1 (bugged)
func converting(from initTz: TimeZone, to targetTz: TimeZone) -> Date {
return self + Double(initTz.secondsFromGMT(for: self) - targetTz.secondsFromGMT(for: self))
}
// case 2 (bugged)
func convertingTime(from initTz: TimeZone, to targetTz: TimeZone) -> Date {
return self + Double(targetTz.secondsFromGMT(for: self) - initTz.secondsFromGMT(for: self))
}
}
let formatter = ISO8601DateFormatter()
// case 1
do {
// example values
let initTz = TimeZone(abbreviation: "GMT")!
let targetTz = TimeZone(abbreviation: "EST")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 4))!
// usage
let targetDate = initDate.converting(from: initTz, to: targetTz)
// print results
formatter.timeZone = targetTz // case 1 is concerned with what the `Date` looks like in the target time zone
print(formatter.string(from: targetDate)) // 2020-03-08T05:00:00-04:00 (should be 4am)
}
// case 2
do {
// example values
let initTz = TimeZone(abbreviation: "EST")!
let targetTz = TimeZone(abbreviation: "GMT")!
let initDate = Calendar.current.date(from: .init(timeZone: initTz, year: 2020, month: 3, day: 8, hour: 1))!
// usage
let targetDate = initDate.convertingTime(from: initTz, to: targetTz)
// print results
formatter.timeZone = targetTz // for case 2, find the initial `Date`'s time in the target time zone
print(formatter.string(from: initDate)) // 2020-03-08T06:00:00Z (the target date should have this same time)
formatter.timeZone = initTz // case 2 is concerned with what the `Date` looks like in the initial time zone
print(formatter.string(from: targetDate)) // 2020-03-08T07:00:00-04:00 (should be 6am)
}
Run Code Online (Sandbox Code Playgroud)
如果您将示例日期向前或向后调整几个小时,则不会发生该错误。日历计算很复杂,尝试自己进行计算几乎总是会导致错误的边缘情况。由于时区是一个日历单位,为了避免错误,您应该使用现有的Calendar界面,就像我最初的例子一样。
因此,这是mukaissi 的回答,并根据 valeCocoa 的夏令时建议进行了增强:
func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
let delta = TimeInterval(targetTimeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22233 次 |
| 最近记录: |