Дата в миллисекундах и обратно до даты в Swift

Я использую текущее время в UTC и помещаю его в nanaoseconds, а затем мне нужно взять наносекунды и вернуться к дате по местному времени. Я могу получить время наносекунды, а затем вернуться к строке даты, но время становится запутанным, когда я иду из строки на сегодняшний день.

    //Date to milliseconds
     func currentTimeInMiliseconds() -> Int! {
            let currentDate = NSDate()
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = format
            dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
            let date = dateFormatter.date(from: dateFormatter.string(from: currentDate as Date))
            let nowDouble = date!.timeIntervalSince1970
            return Int(nowDouble*1000)
        }

    //Milliseconds to date
    extension Int {
        func dateFromMilliseconds(format:String) -> Date {
            let date : NSDate! = NSDate(timeIntervalSince1970:Double(self) / 1000.0)
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = format
            dateFormatter.timeZone = TimeZone.current
            let timeStamp = dateFormatter.string(from: date as Date)

let formatter = DateFormatter()
            formatter.dateFormat = format
            return ( formatter.date( from: timeStamp ) )!
        }
    }

//Временная метка верна, но возвращенная дата не является

Ответ 1

Я не понимаю, почему ты что-то делаешь со строками...

extension Date {
    var millisecondsSince1970:Int64 {
        return Int64((self.timeIntervalSince1970 * 1000.0).rounded())
    }

    init(milliseconds:Int64) {
        self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
    }
}


Date().millisecondsSince1970 // 1476889390939
Date(milliseconds: 0) // "Dec 31, 1969, 4:00 PM" (PDT variant of 1970 UTC)

Ответ 2

Как работает @Travis Solution, но в некоторых случаях

var millisecondsSince1970:Int вызовет сбой приложения,

с ошибкой

Двойное значение не может быть преобразовано в Int, потому что результат будет больше Int.max, если это произойдет. Пожалуйста, обновите свой ответ с Int64

Вот обновленный ответ

extension Date {
 var millisecondsSince1970:Int64 {
        return Int64((self.timeIntervalSince1970 * 1000.0).rounded()) 
        //RESOLVED CRASH HERE
    }

    init(milliseconds:Int) {
        self = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
    }
}

Об определениях Int.

На 32-разрядных платформах размер Int совпадает с размером Int32, а на 64-разрядных платформах размер Int совпадает с размером Int64.

Вообще, я сталкиваюсь с этой проблемой в iPhone 5, который работает в 32-битной среде. Новые устройства работают под управлением 64-битной среды. Их Int будет Int64.

Надеюсь, что это полезно для тех, кто также имеет такую же проблему

Ответ 3

Решение @Travis верное, но оно теряет миллисекунды при создании даты. Я добавил строку, чтобы включить миллисекунды в дату:

Если вам не нужна эта точность, используйте решение Travis, потому что оно будет быстрее.

extension Date {

    func toMillis() -> Int64! {
        return Int64(self.timeIntervalSince1970 * 1000)
    }

    init(millis: Int64) {
        self = Date(timeIntervalSince1970: TimeInterval(millis / 1000))
        self.addTimeInterval(TimeInterval(Double(millis % 1000) / 1000 ))
    }

}

Ответ 4

//Date to milliseconds
func currentTimeInMiliseconds() -> Int {
    let currentDate = Date()
    let since1970 = currentDate.timeIntervalSince1970
    return Int(since1970 * 1000)
}

//Milliseconds to date
extension Int {
    func dateFromMilliseconds() -> Date {
        return Date(timeIntervalSince1970: TimeInterval(self)/1000)
    }
}

Я удалил, казалось бы, бесполезное преобразование через строку и все эти случайные !.

Ответ 5

let dateTimeStamp = NSDate(timeIntervalSince1970:Double(currentTimeInMiliseconds())/1000)  //UTC time  //YOUR currentTimeInMiliseconds METHOD
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone() 
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle


let strDateSelect = dateFormatter.stringFromDate(dateTimeStamp)
print("Local Time", strDateSelect) //Local time


let dateFormatter2 = NSDateFormatter()
dateFormatter2.timeZone = NSTimeZone(name: "UTC") as NSTimeZone!
dateFormatter2.dateFormat = "yyyy-MM-dd"

let date3 = dateFormatter.dateFromString(strDateSelect)
print("DATE",date3)

Ответ 6

Остерегайтесь, если вы собираетесь сравнить даты после преобразования!

Например, я получил актив симулятора с датой TimeInterval (366144731.9), преобразованной в миллисекунды Int64 (1344451931900) и обратно в TimeInterval (366144731.9000001), используя

func convertToMilli(timeIntervalSince1970: TimeInterval) -> Int64 {
    return Int64(timeIntervalSince1970 * 1000)
}

func convertMilliToDate(milliseconds: Int64) -> Date {
    return Date(timeIntervalSince1970: (TimeInterval(milliseconds) / 1000))
}

Я попытался получить ресурс с помощью creationDate, и он не нашел актив, как вы могли догадаться, цифры не совпадают.

Я пробовал несколько решений, чтобы уменьшить двойную десятичную точность, таких как округление (интервал * 1000)/1000, использовать NSDecimalNumber и т. Д... безуспешно.

Я закончил выборку по интервалу -1 <creationDate <интервал + 1, а не creationDate == Interval.

Там может быть лучшее решение !?

Ответ 7

@Prashant Tukadiya ответ работает. Но если вы хотите сохранить значение в UserDefaults, а затем сравнить его с другой датой, вы усечете int64, чтобы это могло вызвать проблемы. Я нашел решение.

Свифт 4:

Вы можете сохранить int64 как строку в UserDefaults:

let value: String(Date().millisecondsSince1970)
let stringValue = String(value)
UserDefaults.standard.set(stringValue, forKey: "int64String")

Таким образом, вы избегаете Int усечения.

И тогда вы можете восстановить первоначальное значение:

let int64String = UserDefaults.standard.string(forKey: "int64String")
let originalValue = Int64(int64String!)

Это позволит вам сравнить его с другими значениями даты:

let currentTime = Date().millisecondsSince1970
let int64String = UserDefaults.standard.string(forKey: "int64String")
let originalValue = Int64(int64String!) ?? 0 

if currentTime < originalValue {
     return false
} else {
     return true
}

Надеюсь, это поможет тому, у кого такая же проблема