Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2016-06-07

Swift Code Library: 24h Wallclock Time in Swift

PS: I no longer use this class. I found that it is more convenient to stick with NSDateComponents. If I define some extensions for NSDate and NSDateComponents as in this post.

PPS: Dispatch now defines DispatchWallTime, maybe that will be enough for your needs.

While NSDateComponents is ok I find myself often needing something simpler: wouldn't it be nice to have a 24h "wallclock" time?

I finally took the (not-too-deep) plunge and defined it:

/// A 24-hour wallclock implementation
public struct WallclockTime {
    public let hour: Int
    public let minute: Int
    public let second: Int
}

There, that was not too difficult?

The wall clock time is not about accuracy, but about ease of use. Hence no sub-seconds, no days, no time-zones etc.

But to become really useful it does need some additional functions, for example comparing wall clock times to one another:

public func == (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    if lhs.hour != rhs.hour { return false }
    if lhs.minute != rhs.minute { return false }
    if lhs.second != rhs.second { return false }
    return true
}

public func != (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    return !(lhs == rhs)
}

public func > (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    if lhs.hour < rhs.hour { return false }
    if lhs.hour > rhs.hour { return true }
    // lhs.hour == rhs.hour
    if lhs.minute < rhs.minute { return false }
    if lhs.minute > rhs.minute { return true }
    // lhs.minute == rhs.minute
    if lhs.second < rhs.second { return false }
    if lhs.second > rhs.second { return true }
    // lhs.second == rhs.second
    return false
}

public func < (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    if lhs == rhs { return false }
    return !(lhs > rhs)
}

public func >= (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    if lhs == rhs { return true }
    return (lhs > rhs)
}

public func <= (lhs: WallclockTime, rhs: WallclockTime) -> Bool {
    if lhs == rhs { return true }
    return (lhs < rhs)

}

And then there is adding wall clock times to each other as well as to an NSDate:

public func + (lhs: WallclockTime, rhs: WallclockTime) -> (time: WallclockTime, tomorrow: Bool) {
    var seconds = lhs.second + rhs.second
    var minutes = lhs.minute + rhs.minute
    var hours = lhs.hour + rhs.hour
    if seconds > 59 { seconds -= 60; minutes += 1 }
    if minutes > 59 { minutes -= 60; hours += 1 }
    if hours < 24 {
        return (WallclockTime(hour: hours, minute: minutes, second: seconds), false)
    } else {
        return (WallclockTime(hour: (hours - 24), minute: minutes, second: seconds), true)
    }
}

public func + (lhs: NSDate, rhs: WallclockTime) -> NSDate {
    return NSCalendar.currentCalendar().dateByAddingComponents(rhs.dateComponents(), toDate: lhs, options: NSCalendarOptions.MatchFirst)!

}

Whoops, seems we need to be able to convert a wall clock time to date components as well:

/// A 24-hour wallclock implementation
public struct WallclockTime {
    public let hour: Int
    public let minute: Int
    public let second: Int
    
    public var dateComponents: NSDateComponents {
        let comp = NSDateComponents()
        comp.hour = self.hour
        comp.minute = self.minute
        comp.second = self.second
        return comp
    }
}
For now, I need to top it off with an extension for NSDate to create a wall clock times:

public extension NSDate {
    
    /// The wallclock time from self in the current calendar
    public var wallclockTime: WallclockTime {
        let comp = NSCalendar.currentCalendar().components([NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: self)
        return WallclockTime(hour: comp.hour, minute: comp.minute, second: comp.second)
    }
    
    /// A new NSDate set to the first future wallclock time in the current calendar
    public static func firstFutureDate(with wallclockTime: WallclockTime) -> NSDate {
        return NSCalendar.currentCalendar().nextDateAfterDate(NSDate(), matchingHour: wallclockTime.hour, minute: wallclockTime.minute, second: wallclockTime.second, options: NSCalendarOptions.MatchNextTime)!
    }
}

Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment