Swift: ARKit TimeInterval to Date - swift

The currentFrame (ARFrame) of ARSession has a timestamp attribute of type TimeInterval which represents the uptime at the moment the frame has been captured.
I need to convert this TimeInterval to the current time domain of the device.
If my assumption about timestamp is correct, adding the kernel BootTime and timestamp together would give me the correct date.
Problem: Adding the kernel BootTime and timestamp together gives me an Date that is not correct. (depending on the device`s last boot time up to 2 days variance)
Current Code:
func kernelBootTime() -> Date {
var mib = [CTL_KERN, KERN_BOOTTIME]
var bootTime = timeval()
var bootTimeSize = MemoryLayout<timeval>.stride
if sysctl(&mib, UInt32(mib.count), &bootTime, &bootTimeSize, nil, 0) != 0 {
fatalError("Could not get boot time, errno: \(errno)")
}
return Date(timeIntervalSince1970: Double(bootTime.tv_sec) + Double(bootTime.tv_usec) / 1_000_000.0)
}
public func checkTime(_ session: ARSession) {
guard let frame = session.currentFrame else { return }
print(Date(timeInterval: frame.timestamp, since: kernelBootTime()))
}

I found the solution.
var refDate = Date.now - ProcessInfo.processInfo.systemUptime
gives you the date of the last device restart
public func checkTime(_ session: ARSession) {
guard let frame = session.currentFrame else { return }
print(Date(timeInterval: frame.timestamp, since: refDate))
}
prints the exact time when the image was taken. (in UTC time)

Related

Check if between two dates is no longer working under iOS16.3

Using iOS16.3, XCode14.2, Swift5.7.2,
Why is the following method no longer working ?
I call this method by setting date = Date() and maximumDate = Date() as well...
According to this solution, it should work - but it doesn't
public class THManager : ObservableObject {
#Published public var minimumDate: Date = Date()
#Published public var maximumDate: Date = Date()
public func isBetweenMinAndMaxDates(date: Date) -> Bool {
print(min(minimumDate, maximumDate))
print(max(minimumDate, maximumDate))
print(min(minimumDate, maximumDate)...max(minimumDate, maximumDate))
print(date)
print((min(minimumDate, maximumDate)...max(minimumDate, maximumDate)).contains(date))
return (min(minimumDate, maximumDate)...max(minimumDate, maximumDate)).contains(date)
}
}
2022-02-08 19:45:51 +0000
2023-02-03 19:45:51 +0000
2022-02-08 19:45:51 +0000...2023-02-03 19:45:51 +0000
2023-02-03 19:45:51 +0000
false
It supposed to return true ! Why does it return false ???
By the way it works if date = Date() and maximumDate = Date().addingTimeInterval(1)
Very strange, isn't it ?
There is no need for such complexity. Date objects conform to the Comparable and Equatable protocols, so testing for a date being between 2 other dates is one line:
extension Date {
func between(start: Date, end: Date) -> Bool {
return self > start && self < end
}
}
You'd use that like this:
let date = Date()
if date.betweeen(start: someDate, end: someOtherDate) {
// the date is between the start and the end
} else {
// The date is not between the start and end dates
}
The above will only return true if the date in question is not equal to start or end date. You could easily change it to match dates that match the beginning and end dates by using >= and <= instead of > and < in the comparisons.
And as discussed in the comments, Date objects have sub-millisecond precision. Two dates that appear identical may be different by a tiny fraction of a second, the best way to verify your comparisons is to convert your Dates to decimal seconds and log the seconds values. (See the Date property timeIntervalSinceReferenceDate.)
Edit:
Check out this sample code using the above exension:
extension Date {
func between(start: Date, end: Date) -> Bool {
return self > start && self < end
}
var asStringWithDecimal: String {
return DateFormatter.localizedString(from: self, dateStyle: .medium, timeStyle: .medium) + " ( \(self.timeIntervalSinceReferenceDate) seconds)"
}
}
let now = Date()
for _ in (1...5) {
let random = Double.random(in: -1.5...1.5)
let test = now.advanced(by: random)
let start = now.advanced(by: -1)
let end = now.advanced(by: 1)
let isBetween = test.between(start: start, end: end)
let isOrNot = isBetween ? "is" : "is not"
let output = "\(test.asStringWithDecimal) \n \(isOrNot) between \n \(start.asStringWithDecimal) and \n \(end.asStringWithDecimal)"
print(output)
}
That will generate 5 random dates ± 1.5 seconds from the current date, and then test each one to see if it is within 1 second of the current date. It logs the result as both Date strings and Doubles, so you can see what's happening when the seconds match (but the fractions of a second likely don't match.)

Automatically increase number everyday / Swift

I coded a SwiftUI App, and the User can choose how much days are left. For example he choose 20 days, it should count in a Circle. For example 10 days are done, the circle should be at 50%.
So I thought I create a Int that is everyday increasing by one. When the user choose 20 days, the Int should start to increase and after 10 days for example the Int is at 10 and because the user choose 20 days, the circle should be at 50%.
Days / Int(that is increasing)
But I dont know how to code the Int that is increasing everyday.
Could anyone help me?
Adding to the suggestion of storing the start date and using today's date to know how many days have passed, you can use this extension
extension Date {
func daysSinceDate(_ fromDate: Date = Date()) -> Int {
let earliest = self < fromDate ? self : fromDate
let latest = (earliest == self) ? fromDate : self
let earlierComponents:DateComponents = Calendar.current.dateComponents([.day], from: earliest)
let laterComponents:DateComponents = Calendar.current.dateComponents([.day], from: latest)
guard
let earlierDay = earlierComponents.day,
let laterDay = laterComponents.day,
laterDay >= earlierDay
else {
return 0
}
return laterDay - earlierDay
}
func dateForDaysFromNow(_ days: Int) -> Date? {
var dayComponent = DateComponents()
dayComponent.day = days
return Calendar.current.date(byAdding: dayComponent, to: self)
}
}

Transter custom object from Apple watch to iPhone using updateApplicationContext

I'm new to Swift and started my first app.
I'm trying to transfer data from the Apple watch to the iPhone using updateApplicationContext, but only get an error:
[WCSession updateApplicationContext:error:]_block_invoke failed due to WCErrorCodePayloadUnsupportedTypes
This is the code in my WatchKit Extension:
var transferData = [JumpData]()
func transferDataFunc() {
let applicationDict = ["data":self.transferData]
do {
try self.session?.updateApplicationContext(applicationDict)
} catch {
print("error")
}
}
These are the object structure I want to send:
class AltiLogObject {
let altitude : Float
let date : Date
init (altitude: Float) {
self.altitude = altitude
self.date = Date.init()
}
init (altitude: Float, date : Date) {
self.altitude = altitude
self.date = date
}
}
class JumpData {
let date : Date
let altitudes : [AltiLogObject]
init(altitudes: [AltiLogObject]) {
self.altitudes = altitudes
self.date = Date.init()
}
init(altitudes: [AltiLogObject], date : Date) {
self.date = date
self.altitudes = altitudes
}
}
To have it complete, the code of the receiver function:
private func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
let transferData = applicationContext["data"] as! [JumpData]
//Use this to update the UI instantaneously (otherwise, takes a little while)
DispatchQueue.main.async() {
self.jumpDatas += transferData
}
}
Any hints are welcome, as I'm trying to get it running for over a week now.
You can only send property list values through updateApplicationContext() - the documentation states this but it isn’t clear at all.
The type of objects that you can send can be found at https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html
Obviously your custom object types aren’t supported, so what you need to do is to break the properties down into the constituent parts (e.g your altitude and date properties), send them individually in the applicationContext dictionary passed into updateApplicationContext() and then reconstruct the objects on the receiving end.
It’s a real pain of course, but that’s the way this all works.
HTH

How do I get the milliseconds from epoc till starting of today's? using swift

var timeIntervalSince1970: NSTimeInterval {get}
I just hope someone can help me with this.
TimeInterval Since 1970 returns epoch time in seconds, you can change it to return milliseconds multiplying it by 1000.
Date().timeIntervalSince1970 * 1000
if you need it to count from start of today you can use calendar method startOfDay(for: Date)
extension Date {
var startOfDay: Date {
Calendar.current.startOfDay(for: self)
}
var millisecondsSince1970: Int {
.init(timeIntervalSince1970 * 1000)
}
}
let millisecondsSince1970 = Date().millisecondsSince1970 // 1604931753291
let startOfDayMsSince1970 = Date().startOfDay.millisecondsSince1970 // 1604890800000

Measure elapsed time in Swift

How can we measure the time elapsed for running a function in Swift? I am trying to display the elapsed time like this: "Elapsed time is .05 seconds". Saw that in Java, we can use System.nanoTime(), are there any equivalent methods available in Swift to accomplish this?
Please have a look at the sample program:
func isPrime(_ number: Int) -> Bool {
var i = 0;
for i=2; i<number; i++ {
if number % i == 0, i != 0 {
return false
}
}
return true
}
var number = 5915587277
if isPrime(number) {
print("Prime number")
} else {
print("NOT a prime number")
}
Update
With Swift 5.7, everything below becomes obsolete. Swift 5.7 introduces the concept of a Clock which has a function designed to do exactly what is required here.
There are two concrete examples of a Clock provided: ContinuousClock and SuspendingClock. The former keeps ticking when the system is suspending and the latter does not.
The following is an example of what to do in Swift 5.7
func doSomething()
{
for i in 0 ..< 1000000
{
if (i % 10000 == 0)
{
print(i)
}
}
}
let clock = ContinuousClock()
let result = clock.measure(doSomething)
print(result) // On my laptop, prints "0.552065882 seconds"
It also allows you to measure closures directly, of course
let clock = ContinuousClock()
let result = clock.measure {
for i in 0 ..< 1000000
{
if (i % 10000 == 0)
{
print(i)
}
}
}
print(result) // "0.534663798 seconds"
Pre Swift 5.7
Here's a Swift function I wrote to measure Project Euler problems in Swift
As of Swift 3, there is now a version of Grand Central Dispatch that is "swiftified". So the correct answer is probably to use the DispatchTime API.
My function would look something like:
// Swift 3
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer
{
print("Evaluating problem \(problemNumber)")
let start = DispatchTime.now() // <<<<<<<<<< Start time
let myGuess = problemBlock()
let end = DispatchTime.now() // <<<<<<<<<< end time
let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds // <<<<< Difference in nano seconds (UInt64)
let timeInterval = Double(nanoTime) / 1_000_000_000 // Technically could overflow for long running tests
print("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
return theAnswer
}
Old answer
For Swift 1 and 2, my function uses NSDate:
// Swift 1
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer
{
println("Evaluating problem \(problemNumber)")
let start = NSDate() // <<<<<<<<<< Start time
let myGuess = problemBlock()
let end = NSDate() // <<<<<<<<<< end time
let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)
let timeInterval: Double = end.timeIntervalSinceDate(start) // <<<<< Difference in seconds (double)
println("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
return theAnswer
}
Note that using NSdate for timing functions is discouraged: "The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.".
This is a handy timer class based on CoreFoundations CFAbsoluteTime:
import CoreFoundation
class ParkBenchTimer {
let startTime: CFAbsoluteTime
var endTime: CFAbsoluteTime?
init() {
startTime = CFAbsoluteTimeGetCurrent()
}
func stop() -> CFAbsoluteTime {
endTime = CFAbsoluteTimeGetCurrent()
return duration!
}
var duration: CFAbsoluteTime? {
if let endTime = endTime {
return endTime - startTime
} else {
return nil
}
}
}
You can use it like this:
let timer = ParkBenchTimer()
// ... a long runnig task ...
print("The task took \(timer.stop()) seconds.")
Use clock, ProcessInfo.systemUptime, or DispatchTime for simple start-up time.
There are, as far as I know, at least ten ways to measure elapsed time:
Monotonic Clock based:
ProcessInfo.systemUptime.
mach_absolute_time with mach_timebase_info as mentioned in this
answer.
clock() in POSIX standard.
times() in POSIX standard. (Too complicated since we need
to consider user-time v.s. system-time, and child processes are
involved.)
DispatchTime (a wrapper around Mach time API) as mentioned by JeremyP in accepted answer.
CACurrentMediaTime().
Wall Clock based:
(never use those for metrics: see below why)
NSDate/Date as mentioned by others.
CFAbsoluteTime as mentioned by others.
DispatchWallTime.
gettimeofday() in POSIX standard.
Option 1, 2 and 3 are elaborated below.
Option 1: Process Info API in Foundation
do {
let info = ProcessInfo.processInfo
let begin = info.systemUptime
// do something
let diff = (info.systemUptime - begin)
}
where diff:NSTimeInterval is the elapsed time by seconds.
Option 2: Mach C API
do {
var info = mach_timebase_info(numer: 0, denom: 0)
mach_timebase_info(&info)
let begin = mach_absolute_time()
// do something
let diff = Double(mach_absolute_time() - begin) * Double(info.numer) / Double(info.denom)
}
where diff:Double is the elapsed time by nano-seconds.
Option 3: POSIX clock API
do {
let begin = clock()
// do something
let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
where diff:Double is the elapsed time by seconds.
Why Not Wall-Clock Time for Elapsed Time?
In documentation of CFAbsoluteTimeGetCurrent:
Repeated calls to this function do not guarantee monotonically
increasing results.
Reason is similar to currentTimeMillis vs nanoTime in Java:
You can't use the one for the other purpose. The reason is that no
computer's clock is perfect; it always drifts and occasionally
needs to be corrected. This correction might either happen
manually, or in the case of most machines, there's a process that
runs and continually issues small corrections to the system clock
("wall clock"). These tend to happen often. Another such correction
happens whenever there is a leap second.
Here CFAbsoluteTime provides wall clock time instead of start-up
time. NSDate is wall clock time as well.
Swift 4 shortest answer:
let startingPoint = Date()
// ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
It will print you something like 1.02107906341553 seconds elapsed (time of course will vary depending on the task, I'm just showing this for you guys to see the decimal precision level for this measurement).
Hope it helps someone in Swift 4 from now on!
Update
If you want to have a generic way of testing portions of code, I'd suggest the next snippet:
func measureTime(for closure: #autoclosure () -> Any) {
let start = CFAbsoluteTimeGetCurrent()
closure()
let diff = CFAbsoluteTimeGetCurrent() - start
print("Took \(diff) seconds")
}
Usage
measureTime(for: <insert method signature here>)
Console log
Took xx.xxxxx seconds
Just Copy and Paste this function. Written in swift 5.
Copying JeremyP here.
func calculateTime(block : (() -> Void)) {
let start = DispatchTime.now()
block()
let end = DispatchTime.now()
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime) / 1_000_000_000
print("Time: \(timeInterval) seconds")
}
Use it like
calculateTime {
exampleFunc()// function whose execution time to be calculated
}
let start = NSDate()
for index in 1...10000 {
// do nothing
}
let elapsed = start.timeIntervalSinceNow
// elapsed is a negative value.
You could create a time function for measuring you calls.
I am inspired by Klaas' answer.
func time <A> (f: #autoclosure () -> A) -> (result:A, duration: String) {
let startTime = CFAbsoluteTimeGetCurrent()
let result = f()
let endTime = CFAbsoluteTimeGetCurrent()
return (result, "Elapsed time is \(endTime - startTime) seconds.")
}
This function would allow you to call it like this time (isPrime(7)) which would return a tuple containing the result and a string description of the elapsed time.
If you only wish the elapsed time you can do this time (isPrime(7)).duration
It looks like iOS 13 introduced a new API to use with DispatchTime that removes a need to calculate the difference between two timestamps manually.
distance(to:)
let start: DispatchTime = .now()
heavyTaskToMeasure()
let duration = start.distance(to: .now())
print(duration)
// prints: nanoseconds(NUMBER_OF_NANOSECONDS_BETWEEN_TWO_TIMESTAMPS)
Sadly the documentation is not provided, but after doing some tests it looks like the .nanoseconds case is always returned.
With a simple extension you could convert the DispatchTimeInterval to TimeInterval. credit
extension TimeInterval {
init?(dispatchTimeInterval: DispatchTimeInterval) {
switch dispatchTimeInterval {
case .seconds(let value):
self = Double(value)
case .milliseconds(let value):
self = Double(value) / 1_000
case .microseconds(let value):
self = Double(value) / 1_000_000
case .nanoseconds(let value):
self = Double(value) / 1_000_000_000
case .never:
return nil
}
}
}
Simple helper function for measuring execution time with closure.
func printExecutionTime(withTag tag: String, of closure: () -> ()) {
let start = CACurrentMediaTime()
closure()
print("#\(tag) - execution took \(CACurrentMediaTime() - start) seconds")
}
Usage:
printExecutionTime(withTag: "Init") {
// Do your work here
}
Result:
#Init - execution took 1.00104497105349 seconds
you can measure the nanoseconds like e.g. this:
let startDate: NSDate = NSDate()
// your long procedure
let endDate: NSDate = NSDate()
let dateComponents: NSDateComponents = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian).components(NSCalendarUnit.CalendarUnitNanosecond, fromDate: startDate, toDate: endDate, options: NSCalendarOptions(0))
println("runtime is nanosecs : \(dateComponents.nanosecond)")
I use this:
public class Stopwatch {
public init() { }
private var start_: NSTimeInterval = 0.0;
private var end_: NSTimeInterval = 0.0;
public func start() {
start_ = NSDate().timeIntervalSince1970;
}
public func stop() {
end_ = NSDate().timeIntervalSince1970;
}
public func durationSeconds() -> NSTimeInterval {
return end_ - start_;
}
}
I don't know if it's more or less accurate than previously posted. But the seconds have a lot of decimals and seem to catch small code changes in algorithms like QuickSort using swap() vs. implementing swap urself etc.
Remember to crank up your build optimizations when testing performance:
Here is my try for the simplest answer:
let startTime = Date().timeIntervalSince1970 // 1512538946.5705 seconds
// time passes (about 10 seconds)
let endTime = Date().timeIntervalSince1970 // 1512538956.57195 seconds
let elapsedTime = endTime - startTime // 10.0014500617981 seconds
Notes
startTime and endTime are of the type TimeInterval, which is just a typealias for Double, so it is easy to convert it to an Int or whatever. Time is measured in seconds with sub-millisecond precision.
See also DateInterval, which includes an actual start and end time.
Using the time since 1970 is similar to Java timestamps.
The recommend way to check elapsed time/performance is using the measure function that is available in XCTests.
It isn't reliable to write your own measure blocks, since the performance (and therefore execution/elapsed time) of a block of code is influenced by e.g. CPU caches.
The second time a function is invoked, would likely be quicker than the first time it is invoked, although it can vary a few %. Therefore 'benchmarking' by using your own closures (given all over the place here) by executing it once, can give different results than your code being executed in production by real users.
The measure function invokes your block of code several times, mimicking the performance/elapsed time of your code like it is used in production (at least gives more accurate results).
I have borrowed the idea from Klaas to create a lightweight struct to measure running and interval time:
Code Usage:
var timer = RunningTimer.init()
// Code to be timed
print("Running: \(timer) ") // Gives time interval
// Second code to be timed
print("Running: \(timer) ") // Gives final time
The stop function does not have to be called, as the print function will give the time lapsed. It may be called repeatedly to get the time lapsed.
But to stop the timer at certain point in the code use timer.stop() it may also be used to return the time in seconds: let seconds = timer.stop()
After the timer is stopped the interval timer will not, so the print("Running: \(timer) ") will give the correct time even after a few lines of code.
Following is the code for RunningTimer. It is tested for Swift 2.1:
import CoreFoundation
// Usage: var timer = RunningTimer.init()
// Start: timer.start() to restart the timer
// Stop: timer.stop() returns the time and stops the timer
// Duration: timer.duration returns the time
// May also be used with print(" \(timer) ")
struct RunningTimer: CustomStringConvertible {
var begin:CFAbsoluteTime
var end:CFAbsoluteTime
init() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
mutating func start() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
mutating func stop() -> Double {
if (end == 0) { end = CFAbsoluteTimeGetCurrent() }
return Double(end - begin)
}
var duration:CFAbsoluteTime {
get {
if (end == 0) { return CFAbsoluteTimeGetCurrent() - begin }
else { return end - begin }
}
}
var description:String {
let time = duration
if (time > 100) {return " \(time/60) min"}
else if (time < 1e-6) {return " \(time*1e9) ns"}
else if (time < 1e-3) {return " \(time*1e6) µs"}
else if (time < 1) {return " \(time*1000) ms"}
else {return " \(time) s"}
}
}
Wrap it up in a completion block for easy use.
public class func secElapsed(completion: () -> Void) {
let startDate: NSDate = NSDate()
completion()
let endDate: NSDate = NSDate()
let timeInterval: Double = endDate.timeIntervalSinceDate(startDate)
println("seconds: \(timeInterval)")
}
Static Swift3 class for basic function timing. It will keep track of each timer by name. Call it like this at the point you want to start measuring:
Stopwatch.start(name: "PhotoCapture")
Call this to capture and print the time elapsed:
Stopwatch.timeElapsed(name: "PhotoCapture")
This is the output: *** PhotoCapture elapsed ms: 1402.415125
There is a "useNanos" parameter if you want to use nanos.
Please feel free to change as needed.
class Stopwatch: NSObject {
private static var watches = [String:TimeInterval]()
private static func intervalFromMachTime(time: TimeInterval, useNanos: Bool) -> TimeInterval {
var info = mach_timebase_info()
guard mach_timebase_info(&info) == KERN_SUCCESS else { return -1 }
let currentTime = mach_absolute_time()
let nanos = currentTime * UInt64(info.numer) / UInt64(info.denom)
if useNanos {
return (TimeInterval(nanos) - time)
}
else {
return (TimeInterval(nanos) - time) / TimeInterval(NSEC_PER_MSEC)
}
}
static func start(name: String) {
var info = mach_timebase_info()
guard mach_timebase_info(&info) == KERN_SUCCESS else { return }
let currentTime = mach_absolute_time()
let nanos = currentTime * UInt64(info.numer) / UInt64(info.denom)
watches[name] = TimeInterval(nanos)
}
static func timeElapsed(name: String) {
return timeElapsed(name: name, useNanos: false)
}
static func timeElapsed(name: String, useNanos: Bool) {
if let start = watches[name] {
let unit = useNanos ? "nanos" : "ms"
print("*** \(name) elapsed \(unit): \(intervalFromMachTime(time: start, useNanos: useNanos))")
}
}
}
This is the snippet I came up with and it seems to work for me on my Macbook with Swift 4.
Never tested on other systems, but I thought it's worth sharing anyway.
typealias MonotonicTS = UInt64
let monotonic_now: () -> MonotonicTS = mach_absolute_time
let time_numer: UInt64
let time_denom: UInt64
do {
var time_info = mach_timebase_info(numer: 0, denom: 0)
mach_timebase_info(&time_info)
time_numer = UInt64(time_info.numer)
time_denom = UInt64(time_info.denom)
}
// returns time interval in seconds
func monotonic_diff(from: MonotonicTS, to: MonotonicTS) -> TimeInterval {
let diff = (to - from)
let nanos = Double(diff * time_numer / time_denom)
return nanos / 1_000_000_000
}
func seconds_elapsed(since: MonotonicTS) -> TimeInterval {
return monotonic_diff(from: since, to:monotonic_now())
}
Here's an example of how to use it:
let t1 = monotonic_now()
// .. some code to run ..
let elapsed = seconds_elapsed(since: t1)
print("Time elapsed: \(elapsed*1000)ms")
Another way is to do it more explicitly:
let t1 = monotonic_now()
// .. some code to run ..
let t2 = monotonic_now()
let elapsed = monotonic_diff(from: t1, to: t2)
print("Time elapsed: \(elapsed*1000)ms")
This is how I wrote it.
func measure<T>(task: () -> T) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
task()
let endTime = CFAbsoluteTimeGetCurrent()
let result = endTime - startTime
return result
}
To measure a algorithm use it like that.
let time = measure {
var array = [2,4,5,2,5,7,3,123,213,12]
array.sorted()
}
print("Block is running \(time) seconds.")
Based on Franklin Yu answer and Cœur comments
Details
Xcode 10.1 (10B61)
Swift 4.2
Solution 1
measure(_:)
Solution 2
import Foundation
class Measurer<T: Numeric> {
private let startClosure: ()->(T)
private let endClosure: (_ beginningTime: T)->(T)
init (startClosure: #escaping ()->(T), endClosure: #escaping (_ beginningTime: T)->(T)) {
self.startClosure = startClosure
self.endClosure = endClosure
}
init (getCurrentTimeClosure: #escaping ()->(T)) {
startClosure = getCurrentTimeClosure
endClosure = { beginningTime in
return getCurrentTimeClosure() - beginningTime
}
}
func measure(closure: ()->()) -> T {
let value = startClosure()
closure()
return endClosure(value)
}
}
Usage of solution 2
// Sample with ProcessInfo class
m = Measurer { ProcessInfo.processInfo.systemUptime }
time = m.measure {
_ = (1...1000).map{_ in Int(arc4random()%100)}
}
print("ProcessInfo: \(time)")
// Sample with Posix clock API
m = Measurer(startClosure: {Double(clock())}) { (Double(clock()) - $0 ) / Double(CLOCKS_PER_SEC) }
time = m.measure {
_ = (1...1000).map{_ in Int(arc4random()%100)}
}
print("POSIX: \(time)")
From Swift 5.7 (macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0), you can use ContinuousClock and the measure block, which returns a Duration object. It has components that contain the measured time in seconds or attoseconds, which is 1×10−18 of a second.
let clock = ContinuousClock()
let duration = clock.measure {
// put here what you want to measure
}
print("Duration: \(duration.components.seconds) seconds")
print("Duration: \(duration.components.attoseconds) attoseconds")