Search code examples
swifttime

how to check if time is within a specific range in swift


Hi I am trying to check if the current time is within a time range, say 8:00 - 16:30. My code below shows that I can obtain the current time as a string, but I am unsure how I can use this value to check if it is inside the time range specified above. Any help would be greatly appreciated!

var todaysDate:NSDate = NSDate()
var dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm"
var dateInFormat:String = dateFormatter.stringFromDate(todaysDate)
println(dateInFormat) // 23:54

Solution

  • There are lots of ways to do this. Personally, I don't like working with strings if I can avoid it. I'd rather deal with date components.

    Below is code that creates dates for 8:00 and 16:30, and then compares the dates to see if the current date/time falls in that range.

    It's longer than other people's code, but I think it's worth learning how to do calculations with dates using a Calendar:

    EDIT #3:

    This answer is from a long time ago. I'll leave the old answer below, but here is the current solution:

    @CodenameDuchess' answer uses a system function, date(bySettingHour:minute:second:of:matchingPolicy:repeatedTimePolicy:direction:)

    Using that function, the code can be simplified to this:

    import UIKit
    
    // The function `Calendar.date(bySettingHour:minute:second)` lets you 
    // create date objects for a given time in the same day of given date
    // For example, 8:00 today
    
    let calendar = Calendar.current
    let now = Date()
    let eight_today = calendar.date(
      bySettingHour: 8,
      minute: 0,
      second: 0,
      of: now)!
    
    let four_thirty_today = calendar.date(
      bySettingHour: 16,
      minute: 30,
      second: 0,
      of: now)!
    
    // In recent versions of Swift Date objectst are comparable, so you can 
    // do greater than, less than, or equal to comparisons on dates without
    // needing a date extension
    
    if now >= eight_today &&
      now <= four_thirty_today
    {
      print("The time is between 8:00 and 16:30")
    }
    

    The old (Swift 2) answer follows, for historical completeness:

    This code uses a Calendar object to get the day/month/year of the current date, and adds the desired hour/minute components, and then generates a date for those components.

    import UIKit
    //-------------------------------------------------------------
    //NSDate extensions.
    extension NSDate
    {
      /**
      This adds a new method dateAt to NSDate.
    
      It returns a new date at the specified hours and minutes of the receiver
    
      :param: hours: The hours value
      :param: minutes: The new minutes
    
      :returns: a new NSDate with the same year/month/day as the receiver, but with the specified hours/minutes values
      */
      func dateAt(#hours: Int, minutes: Int) -> NSDate
      {
        let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    
        //get the month/day/year componentsfor today's date.
    
        println("Now = \(self)")
    
        let date_components = calendar.components(
          NSCalendarUnit.CalendarUnitYear |
            NSCalendarUnit.CalendarUnitMonth |
            NSCalendarUnit.CalendarUnitDay,
          fromDate: self)
    
        //Create an NSDate for 8:00 AM today.
        date_components.hour = hours
        date_components.minute = minutes
        date_components.second = 0
    
        let newDate = calendar.dateFromComponents(date_components)!
            return newDate
      }
    }
    //-------------------------------------------------------------
    //Tell the system that NSDates can be compared with ==, >, >=, <, and <= operators
    extension NSDate: Equatable {}
    extension NSDate: Comparable {}
    
    //-------------------------------------------------------------
    //Define the global operators for the 
    //Equatable and Comparable protocols for comparing NSDates
    
    public func ==(lhs: NSDate, rhs: NSDate) -> Bool
    {
      return lhs.timeIntervalSince1970 == rhs.timeIntervalSince1970
    }
    
    public func <(lhs: NSDate, rhs: NSDate) -> Bool
    {
      return lhs.timeIntervalSince1970 < rhs.timeIntervalSince1970
    }
    public func >(lhs: NSDate, rhs: NSDate) -> Bool
    {
      return lhs.timeIntervalSince1970 > rhs.timeIntervalSince1970
    }
    public func <=(lhs: NSDate, rhs: NSDate) -> Bool
    {
      return lhs.timeIntervalSince1970 <= rhs.timeIntervalSince1970
    }
    public func >=(lhs: NSDate, rhs: NSDate) -> Bool
    {
      return lhs.timeIntervalSince1970 >= rhs.timeIntervalSince1970
    }
    //-------------------------------------------------------------
    
    let now = NSDate()
    let eight_today = now.dateAt(hours: 8, minutes: 0)
    let four_thirty_today = now.dateAt(hours:16, minutes: 30)
    
    if now >= eight_today &&
      now <= four_thirty_today
    {
      println("The time is between 8:00 and 16:30")
    }
    

    EDIT:

    The code in this answer has changed a LOT for Swift 3.

    Instead of using NSDate, it makes more sense to us the native Date object, and Date objects are Equatable and Comparable "out of the box".

    Thus we can get rid of the Equatable and Comparable extensions and the definitions for the <, > and = operators.

    Then we need to do a fair amount of tweaking of the syntax in the dateAt function to follow Swift 3 syntax. The new extension looks like this in Swift 3:

    Swift 3 version:

    import Foundation
    
    extension Date
    {
    
      func dateAt(hours: Int, minutes: Int) -> Date
      {
        let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
    
        //get the month/day/year componentsfor today's date.
    
    
        var date_components = calendar.components(
          [NSCalendar.Unit.year,
           NSCalendar.Unit.month,
           NSCalendar.Unit.day],
          from: self)
    
        //Create an NSDate for the specified time today.
        date_components.hour = hours
        date_components.minute = minutes
        date_components.second = 0
    
        let newDate = calendar.date(from: date_components)!
        return newDate
      }
    }
    
    
    let now = Date()
    let eight_today = now.dateAt(hours: 8, minutes: 0)
    let four_thirty_today = now.dateAt(hours: 16, minutes: 30)
    
    if now >= eight_today &&
      now <= four_thirty_today
    {
      print("The time is between 8:00 and 16:30")
    }