将 UNIX 时间从 json 导入(swift 结构)转换为日期作为字符串并填充表

Posted

技术标签:

【中文标题】将 UNIX 时间从 json 导入(swift 结构)转换为日期作为字符串并填充表【英文标题】:Convert UNIX time from json import (swift struct) to date as string and populate table 【发布时间】:2018-08-16 09:15:02 【问题描述】:

我有一个 json 文件被导入我的项目 (https://api.myjson.com/bins/ywv0k)。 json 属性被解码并存储在我的结构类“News”中,它与 json 文件具有相同的属性。

在第二步中,我使用结构类“News”中的字符串属性“timestamp”填充一个表,这实际上是一个 UNIX 时间。

我现在的问题是我不知道如何将此 UNIX 时间更改为格式为“dd/mm/yy HH:mm:ss”的字符串,因为当我尝试放置函数时出现错误

let date = NSDate(timeIntervalSince1970: timestamp) //error since timestamp is currently defined as string. If I make it a long variable, I cannot populate the table with it any more, since the label requires a text with string format.

let dayTimePeriodFormatter = NSDateFormatter()
dayTimePeriodFormatter.dateFormat = "dd/mm/yy HH:mm:ss"

 let dateString = dayTimePeriodFormatter.stringFromDate(date)

进入do-encoding-loop以及当我把它放入这个表函数时:func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell。

斯威夫特 4

import UIKit

// structure from json file
struct News: Codable
    let type: String
    let timestamp: String // UNIX format, eg. "1531294146340"
    let title: String
    let message: String


class HomeVC: BaseViewController, UITableViewDelegate, UITableViewDataSource 
    var myNewsItems: [News] = []
    @IBOutlet weak var myNewTableView: UITableView!   

    override func viewDidLoad() 
        super.viewDidLoad()

        let nibName = UINib(nibName: "CustomTableViewCell", bundle: nil)
        myNewTableView.register(nibName, forCellReuseIdentifier: "tableViewCell")


// JSON Decoding

        let url=URL(string:"https://api.myjson.com/bins/ywv0k")
        let session = URLSession.shared
        let task = session.dataTask(with: url!)  (data, response, error) in

            guard let data = data else  return 

            do 
                let myNewsS = try
                    JSONDecoder().decode([News].self, from: data)
                print(myNewsS)

                self.myNewsItems = myNewsS
                DispatchQueue.main.async 
                    self.myNewTableView.reloadData()
                
             catch let jsonErr 
            

        
        task.resume()
    

    func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return myNewsItems.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as!
CustomTableViewCell

// populate table with json content
        cell.commonInit(timestamp: myNewsItems[indexPath.row].timestamp, message: myNewsItems[indexPath.row].message)

        return cell
    

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
            cell.backgroundColor = UIColor(white: 1, alpha: 0.5)
    

【问题讨论】:

【参考方案1】:

首先日期格式是错误的。必须是"dd/MM/yy HH:mm:ss"

最有效的解决方案 – 如果您负责 JSON – 将 timestamp 的值发送为 Double。那么声明timestamp就足够了

let timestamp: Date // UNIX format, eg. 1531294146340

并添加日期解码策略

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970

另一种解决方法是将日期转换代码放入struct中

struct News: Codable
    let type: String
    let timestamp: String // UNIX format, eg. "1531294146340"
    let title: String
    let message: String

    enum  CodingKeys: String, CodingKey  case type, timestamp, title, message

    let dateFormatter : DateFormatter = 
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/yy HH:mm:ss"
        return formatter
    ()

    var dateString : String 
        let timeInterval = TimeInterval(timestamp)!
        let date = Date(timeIntervalSince1970: timeInterval / 1000)
        return dateFormatter.string(from:date)
    

计算属性dateString 包含日期字符串。


您还可以将type 声明为枚举

enum Type : String, Codable 
    case organizational, planning


struct News: Codable
    let type: Type
...

【讨论】:

【参考方案2】:

您应该能够将时间戳转换为日期,然后将其格式化为特定格式并转换回字符串以显示在 UILabel 上。看看以下是否有帮助

func string(from timestamp: String) -> String 
    if let timeInterval = TimeInterval(timestamp) 
        let date = Date(timeIntervalSince1970: timeInterval)
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/yy HH:mm:ss"
        return formatter.string(from: date)
    
    return "" //return empty if somehow the timestamp conversion to TimeInterval (Double) fails
 

【讨论】:

【参考方案3】:

1) 作为第一个建议,不要出于数字或原因将日期存储为字符串。

(Apple 说要使用非常基本的类型......所以为 UnixTimestamp 或 NSDate 使用 64 位......更灵活,例如执行计算、差异、本地化等......(以及更好的内存使用。 . (Ints 甚至不使用 ARC...))

(并为字段使用可选......更安全......)

2) 所以使用 extension 保存为日期(例如)

让我们从一个 int unixTimestamp 开始:

(我为控制器添加了一个完整的示例......)

//
//  ViewController.swift
//  sampleDate
//
//  Created by ing.conti on 16/08/2018.
//  Copyright © 2018 com.ingconti. All rights reserved.
//

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        //sample with int...

        if let dm =
            // Thursday, January 1, 2015 12:00:00 AM GMT+01:00
            (1420066800000/1000).fromUnixTimeStamp()
            // note: usual timestamp from server come with milliseincods..

            //now You get a date... use and format!
            print(dm.description)
        

        let testString = "1420066800"
        if let n = Int(testString), let dm = n.fromUnixTimeStamp()
                print(dm.description)
            
        







extension Int 

    func  fromUnixTimeStamp() -> Date? 
        let date = Date(timeIntervalSince1970: TimeInterval(self))
        return date



所以使用扩展名并更改您的使用日期。

最后一点:可编码很好,但不适用于“边缘情况”广告苹果在 “Reflecting on Reflection”(https://developer.apple.com/swift/blog/?id=37) 有时更好地手动编写解析器……对于一小段 JSON。

所以例如使用:

(我重写了一点你的课...)

typealias Dict = [String : Any]



struct News
    let type: String?
    // NO! let timestamp: String // UNIX format, eg. "1531294146340"
    let timestamp: Date?
    let title: String?
    let message: String?


    init?(dict : Dict?) 

        guard let d = dict else
            return nil
        

        if let s = d["timestamp"] as? String, let n = Int(s) 
            timestamp = n.fromUnixTimeStamp()
        else
            timestamp = nil // or other "default" ..
        

        // go on parsing... other fields..


        if let s = d["type"] as? String
            type = s
        else
            type = nil // or other "default" ..
        

        if let s = d["title"] as? String 
            title = s
        
        else
            title = nil // or other "default" ..
        

        if let s = d["message"] as? String 
            message = s
        else
            message = nil // or other "default" ..
        
    


所以这样使用:

...

let new = News(dict: dict)

我通常用这种方式从 JSON 中提取数据:

...

      guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? Dict
                else
                    return
            

            guard let dict = json else
                return
            


..
        let new = News(dict: dict)

【讨论】:

以上是关于将 UNIX 时间从 json 导入(swift 结构)转换为日期作为字符串并填充表的主要内容,如果未能解决你的问题,请参考以下文章

从 Avro 将 unix 时间戳(以秒为单位)导入 Bigquery 中的正确时间戳

Swift 4 Playground - 从 JSON 获取对象/结果

在Swift中将这个JSON数据导入数组的最简单方法是什么?

Swift 4 - Json 解码器

解码 JSON (Swift) 时将单个字符串拆分为多个部分

如何将 json 数据从 alamofire 转换为 swift 对象