【问题标题】:Swift 3.0 : Convert server UTC time to local time and vice-versaSwift 3.0:将服务器 UTC 时间转换为本地时间,反之亦然
【发布时间】:2017-08-05 19:31:28
【问题描述】:

我想将服务器 UTC 时间转换为本地时间,反之亦然。 这是我的代码..

var isTimeFromServer = true
var time:String!
var period:String!
let timeString = "6:59 AM" //Current UTC time

if isTimeFromServer {

    let index = timeString.index(timeString.startIndex, offsetBy: 5)
    let twelve = timeString.substring(to: index)

    var dateString:String!

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "H:mm"
    let date12 = dateFormatter.date(from: twelve)!

    dateFormatter.dateFormat = "h:mm a"
    let date22 = dateFormatter.string(from: date12)

    //print(date22)
    dateString = date22
    //print("dateString=\(dateString)")

    time = dateString.components(separatedBy: " ")[0]
    period = dateString.components(separatedBy: " ")[1]

}
else {
    time = timeString.components(separatedBy: " ")[0]
    period = timeString.components(separatedBy: " ")[1]
}

var hour = Int(time.components(separatedBy: ":")[0])

hour = period == "AM" ? hour : hour! + 12
let minute = Int(time.components(separatedBy: ":")[1])
let calender = NSCalendar.current
var datecomponent = DateComponents()
datecomponent.calendar = calender
datecomponent.hour = hour
datecomponent.minute = minute

if !isTimeFromServer {
    // local to UTC
    datecomponent.timeZone = TimeZone.current
}
else {
    datecomponent.timeZone = TimeZone(abbreviation: "UTC")
}

let date = datecomponent.date
let dateFormatter = DateFormatter()

if !isTimeFromServer {
    dateFormatter.dateFormat = "H:mm"
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    dateFormatter.string(from: date!)
}
else {
    //UTC to local
    dateFormatter.dateFormat = "h:mm a"
    dateFormatter.timeZone = TimeZone.current
    dateFormatter.string(from: date!)
}

我知道当地时间

o/p: "12:52 PM"

但实际本地时间与输出时间相差23分钟。

【问题讨论】:

    标签: swift nsdate nsdateformatter nsdatecomponents


    【解决方案1】:

    我不知道你的代码有什么问题。
    但是看起来有太多不必要的东西,比如你正在设置日历,从字符串中获取一些元素。 这是我的 UTCToLocal 和 localToUTC 函数的小版本。
    但为此,您需要以特定格式传递字符串。因为我强行解开日期对象。但是您可以使用一些保护条件来防止您的应用崩溃。

    func localToUTC(dateStr: String) -> String? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "h:mm a"
        dateFormatter.calendar = Calendar.current
        dateFormatter.timeZone = TimeZone.current
        
        if let date = dateFormatter.date(from: dateStr) {
            dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
            dateFormatter.dateFormat = "H:mm:ss"
        
            return dateFormatter.string(from: date)
        }
        return nil
    }
    
    func utcToLocal(dateStr: String) -> String? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "H:mm:ss"
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        
        if let date = dateFormatter.date(from: dateStr) {
            dateFormatter.timeZone = TimeZone.current
            dateFormatter.dateFormat = "h:mm a"
        
            return dateFormatter.string(from: date)
        }
        return nil
    }
    

    并像下面这样调用这些函数。

    print(utcToLocal(dateStr: "13:07:00"))
    print(localToUTC(dateStr: "06:40 PM"))
    

    希望这会对您有所帮助。
    编码愉快!

    【讨论】:

    • 这正是我想要的......谢谢@Mrugesh。
    • 唯一的缺点是效率低下。此函数的每次迭代大约需要 0.23 毫秒。为了比较数千个日期,这将是无效的
    • 为了更有效地将 DateFormatter() 的声明和初始化放在 viewDidLoad 或 init 中的这些方法之外。 DateFormatter() 是一项昂贵的操作,因此这可以允许它被创建一次,然后我们可以在 UTCToLocal 方法等中操作 dateFormat 等......您只需要设置一次的任何内容都可以进入 viewDidLoad 或 init 实际上。这将提高效率
    • 致命错误:每次打开可选值 Swift 4.2 时意外发现 nil...
    • @Oleksandr,可能你的日期格式不同,然后写在答案中
    【解决方案2】:

    Mrugesh 的回答是完美的,但如果有人需要使用自己的格式,或者以某种不同的格式,我已经对其进行了概括,因此您可以在两个参数中给出不同的格式或相同的格式。

    func localToUTC(date:String, fromFormat: String, toFormat: String) -> String {
    
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = fromFormat
        dateFormatter.calendar = NSCalendar.current
        dateFormatter.timeZone = TimeZone.current
        dateFormatter.date
        let dt = dateFormatter.date(from: date)
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        dateFormatter.dateFormat = toFormat
    
        return dateFormatter.string(from: dt!)
    }
    
    func UTCToLocal(date:String, fromFormat: String, toFormat: String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = fromFormat
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    
        let dt = dateFormatter.date(from: date)
        dateFormatter.timeZone = TimeZone.current
        dateFormatter.dateFormat = toFormat
    
    return dateFormatter.string(from: dt!)
    }
    
    let localDateAsString = UTCToLocal(date: dateAsString!, fromFormat: "hh:mm a, dd MMM yyyy", toFormat: "hh:mm a, dd MMM yyyy")
    

    你可以像上面那样使用它。希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      在 Mrugesh Tank Answer 的帮助下,

      我已经更新了他的答案并为该日期创建了扩展名。这样您就可以轻松地从任何地方从 ViewController 或单元类访问函数。

      extension String {
      
        //MARK:- Convert UTC To Local Date by passing date formats value
        func UTCToLocal(incomingFormat: String, outGoingFormat: String) -> String {
          let dateFormatter = DateFormatter()
          dateFormatter.dateFormat = incomingFormat
          dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
      
          let dt = dateFormatter.date(from: self)
          dateFormatter.timeZone = TimeZone.current
          dateFormatter.dateFormat = outGoingFormat
      
          return dateFormatter.string(from: dt ?? Date())
        }
      
        //MARK:- Convert Local To UTC Date by passing date formats value
        func localToUTC(incomingFormat: String, outGoingFormat: String) -> String {
          let dateFormatter = DateFormatter()
          dateFormatter.dateFormat = incomingFormat
          dateFormatter.calendar = NSCalendar.current
          dateFormatter.timeZone = TimeZone.current
      
          let dt = dateFormatter.date(from: self)
          dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
          dateFormatter.dateFormat = outGoingFormat
      
          return dateFormatter.string(from: dt ?? Date())
        }
      }
      

      使用示例:-

      Note:- eventStartDate is the string which you have to converted in your format like this:- "2018-07-11T16:22:00.000Z" 
      
      let finalDate = eventStartDate.UTCToLocal(incomingFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ", outGoingFormat: "MMM d, yyyy h:mm a")
      

      【讨论】:

      • 感谢您的帮助!
      【解决方案4】:

      适用于所有使用 TimeZone 对象的人。 如果有可能,我建议您使用标识符而不是缩写来创建您的 TimeZone。

      这可以防止夏令时引起的错误。

      为了说明我的观点,让我们举个例子。 你可以像这样实例化 let timeZone = TimeZone(identifier: "Europe/Paris") 或者像那样 let timeZone = TimeZone(abbreviation: "CEST") 或“UTC +2:00”

      但这是夏季时区 CEST,意思是 中欧夏令时 我们有 CET 表示冬季的 中欧时间,即“UTC +1:00”

      您可以使用 Date.isDaylightSavingsTime 自行管理夏令时,但这意味着需要更多代码,并且您无法控制夏令时的来源。 来自官方文档的“指示接收器当前是否使用夏令时”

      就是说支持 TimeZone(identifier: ...)

      【讨论】:

      • 这不是问题的答案。
      【解决方案5】:

      要将 UTC 日期转换为本地系统日期,您可以使用以下日期扩展:

      extension Date {
      
          // Convert local time to UTC (or GMT)
          func toGlobalTime() -> Date {
              let timezone = TimeZone.current
              let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
              return Date(timeInterval: seconds, since: self)
          }
      
          // Convert UTC (or GMT) to local time
          func toLocalTime() -> Date {
              
              // 1) Get the current TimeZone's seconds from GMT. Since I am in Chicago this will be: 60*60*5 (18000)
              let timezoneOffset = TimeZone.current.secondsFromGMT()
              
              // 2) Get the current date (GMT) in seconds since 1970. Epoch datetime.
              let epochDate = self.timeIntervalSince1970
              
              // 3) Perform a calculation with timezoneOffset + epochDate to get the total seconds for the
              //    local date since 1970.
              //    This may look a bit strange, but since timezoneOffset is given as -18000.0, adding epochDate and timezoneOffset
              //    calculates correctly.
              let timezoneEpochOffset = (epochDate + Double(timezoneOffset))
              
              
              // 4) Finally, create a date using the seconds offset since 1970 for the local date.
              return Date(timeIntervalSince1970: timezoneEpochOffset)
          }
      
      }
      

      【讨论】:

        【解决方案6】:

        您可以在 swift 4/5 中使用

          var myDate:String = "2020-02-18 14:30:57"
            var convertedLocalTime:String = ""
        
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd H:mm:ss"
        
            dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        
            if let dt = dateFormatter.date(from: myDate) {
                dateFormatter.timeZone = TimeZone.current
                dateFormatter.dateFormat = "yyyy-MM-dd h:mm a"
                convertedLocalTime = dateFormatter.string(from: dt)
            } else {
                print("There was an error decoding the string")
            }
        
            print("convertedLocalTime--",convertedLocalTime)
        

        【讨论】:

          【解决方案7】:

          请试一试:

          func convertUTCToLocal(timeString: String) -> String? {
              let dateFormatter = DateFormatter()
              dateFormatter.dateFormat = "h:mm a"
          
              dateFormatter.timeZone = TimeZone.init(abbreviation: "UTC")
              let timeUTC = dateFormatter.date(from: timeString)
          
              if timeUTC != nil {
                  dateFormatter.timeZone = NSTimeZone.local
          
                  let localTime = dateFormatter.string(from: timeUTC!)
                  return localTime
              }
          
              return nil
          }
          
          
          
          func convertLocalToUTC(localTime: String) -> String? {
          
              let dateFormatter = DateFormatter()
              dateFormatter.dateFormat = "h:mm a"
              dateFormatter.timeZone = NSTimeZone.local
              let timeLocal = dateFormatter.date(from: localTime)
          
              if timeLocal != nil {
                  dateFormatter.timeZone = TimeZone.init(abbreviation: "UTC")
          
                  let timeUTC = dateFormatter.string(from: timeLocal!)
                  return timeUTC
              }
              return nil
          }
          
          
              var isTimeFromServer = true
              var time:String!
              var period:String!
              let timeString = "6:59 AM" //Current UTC time
          
          
              if isTimeFromServer {
                  print(convertUTCToLocal(timeString: timeString))
              } else {
                  print(convertLocalToUTC(localTime: timeString))
              }
          

          【讨论】:

          • 一些解释对未来的读者很有用:问题中的代码有什么问题?你做了什么改变,为什么?
          【解决方案8】:

          如果您需要转换时间戳,您可以使用 timezoneOffset,如下所示:

          if let dateStr = model.date, let dateInt = Int(dateStr) {
                      let timezoneOffset =  TimeZone.current.secondsFromGMT()
                      let localDateInt = dateInt + timezoneOffset
                      let date = Date(timeIntervalSince1970: Double(localDateInt))
                      cell.dateLbl.text = date.toShortDateTimeString()
                  }
          

          【讨论】:

            猜你喜欢
            • 2016-09-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-26
            相关资源
            最近更新 更多