以毫秒为单位的日期,以 Swift 为单位的日期

我以当前时间(UTC)为单位,以纳秒为单位,然后我需要以纳秒为单位,回到当地时间的一个日期。

我能够把时间控制在纳秒级别,然后再回到日期字符串,但是当我从一个字符串转换到日期时,时间就变得复杂了。

//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 ) )!
}
}

时间戳是正确的,但返回的日期不正确。

145124 次浏览
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)
//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)
}
}

I removed seemingly useless conversion via string and all those random !.

I don't understand why you're doing anything with strings...

extension Date {
var millisecondsSince1970:Int64 {
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)

As @Travis Solution works but in some cases

var millisecondsSince1970:Int WILL CAUSE CRASH APPLICATION ,

with error

Double value cannot be converted to Int because the result would be greater than Int.max if it occurs Please update your answer with Int64

Here is Updated Answer

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


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

About Int definitions.

On 32-bit platforms, Int is the same size as Int32, and on 64-bit platforms, Int is the same size as Int64.

Generally, I encounter this problem in iPhone 5, which runs in 32-bit env. New devices run 64-bit env now. Their Int will be Int64.

Hope it is helpful to someone who also has same problem

@Travis solution is right, but it loses milliseconds when a Date is generated. I have added a line to include the milliseconds into the date:

If you don't need this precision, use the Travis solution because it will be faster.

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 ))
}


}

Watch out if you are going to compare dates after the conversion!

For instance, I got simulator's asset with date as TimeInterval(366144731.9), converted to milliseconds Int64(1344451931900) and back to TimeInterval(366144731.9000001), using

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


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

I tried to fetch the asset by creationDate and it doesn't find the asset, as you could figure, the numbers are not the same.

I tried multiple solutions to reduce double's decimal precision, like round(interval*1000)/1000, use NSDecimalNumber, etc... with no success.

I ended up fetching by interval -1 < creationDate < interval + 1, instead of creationDate == Interval.

There may be a better solution!?

@Prashant Tukadiya answer works. But if you want to save the value in UserDefaults and then compare it to other date you get yout int64 truncated so it can cause problems. I found a solution.

Swift 4:

You can save int64 as string in UserDefaults:

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

Like that you avoid Int truncation.

And then you can recover the original value:

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

This allow you to compare it with other date values:

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


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

Hope this helps someone who has same problem

Heres a simple solution in Swift 5/iOS 13.

extension Date {
    

func toMilliseconds() -> Int64 {
Int64(self.timeIntervalSince1970 * 1000)
}


init(milliseconds:Int) {
self = Date().advanced(by: TimeInterval(integerLiteral: Int64(milliseconds / 1000)))
}
}

This however assumes you have calculated the difference between UTF time and local time and adjusted and accounted for in the milliseconds. For that look to calendar

var cal = Calendar.current
cal.timeZone = TimeZone(abbreviation: "UTC")!
let difference = cal.compare(dateGiven, to: date, toGranularity: .nanosecond)

Unless you absolutely have to convert the date to an integer, consider using a Double instead to represent the time interval. After all, this is the type that timeIntervalSince1970 returns. All of the answers that convert to integers loose sub-millisecond precision, but this solution is much more accurate (although you will still lose some precision due to floating-point imprecision).

public extension Date {
    

/// The interval, in milliseconds, between the date value and
/// 00:00:00 UTC on 1 January 1970.
/// Equivalent to `self.timeIntervalSince1970 * 1000`.
var millisecondsSince1970: Double {
return self.timeIntervalSince1970 * 1000
}


/**
Creates a date value initialized relative to 00:00:00 UTC
on 1 January 1970 by a given number of **milliseconds**.
     

equivalent to
```
self.init(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
```
- Parameter millisecondsSince1970: A time interval in milliseconds.
*/
init(millisecondsSince1970 milliseconds: Double) {
self.init(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
}


}

Simple one-line code to get time token in UInt64

let time = UInt64(Date().timeIntervalSince1970 * 1000)


print(time) <----- prints time in UInt64

Additional tip:

For timestamp with 10 Digit milliseconds since 1970 for API call then

let timeStamp = Date().timeIntervalSince1970


print(timeStamp) <-- prints current time stamp