如何在Swift中检查时间是否在特定范围内。

22

嗨,我正在尝试检查当前时间是否在一个时间范围内,比如8:00-16:30。下面的代码显示我可以将当前时间作为字符串获取,但我不确定如何使用这个值来检查它是否在上述时间范围内。任何帮助都将不胜感激!

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

41

有很多方法来实现这个。就我个人而言,如果可以避免使用字符串,我不喜欢与字符串一起工作。我宁愿处理日期组件。

以下是创建8:00和16:30日期的代码,并将日期进行比较,以查看当前日期/时间是否落在该范围内。

虽然比其他人的代码更长,但我认为学习如何使用日历进行计算是值得的:

编辑#3:

这个答案是很久以前的。我会保留旧答案,但这里是当前的解决方案:

@CodenameDuchess的答案使用了一个系统函数,date(bySettingHour:minute:second:of:matchingPolicy:repeatedTimePolicy:direction:)

使用那个函数,代码可以简化为这样:

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

为了历史完整性,以下是旧的(Swift 2)答案:

这段代码使用 Calendar 对象获取当前日期的日/月/年,并添加所需的时/分组件,然后生成这些组件对应的日期。

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

编辑:

这个答案中的代码已经在Swift 3中有了很大的改变。

现在不再使用NSDate,而是使用本地的Date对象,Date对象默认就是可比较和相等的。

因此,我们可以摆脱EquatableComparable扩展以及<>=操作符的定义。

然后,我们需要对dateAt函数中的语法进行一些微调,以遵循Swift 3的语法。Swift 3中新的扩展如下所示:

Swift 3版本:

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

1
上面的代码似乎可以工作,但是当前时间被视为GMT。是否有一种方法可以创建一个使用手机本地时区或指定时区(例如澳大利亚东部时间,即UTC / GMT + 10)的NSDate对象? - redman
2
NSDates不使用任何时区,它们始终在GMT/UTC内部存储。只有在显示它们时,您才会看到它们在特定的时区中。以特定时区显示日期的最简单方法是使用日期格式化程序。(虽然println("\(someDate)")的语法似乎在设备上以默认区域设置显示。) - Duncan C
谢谢你的澄清,Duncan。我测试了一下,就像你说的那样它可以工作。干杯! - redman
1
@MahmoudZinji 如果您将您的问题作为新评论发布并标记我,我会回答您。 - Duncan C
1
我在这里创建了另一个问题(链接:https://dev59.com/v3kPtIcB2Jgan1znmH0P#73584697?noredirect=1#comment129942709_73584697),并回答了它。 - Duncan C
显示剩余8条评论

18
在 Swift 3.0 中,您可以使用新的日期值类型并直接使用 ==、>、< 等进行比较。
let now = NSDate()
let nowDateValue = now as Date
let todayAtSevenAM = calendar.date(bySettingHour: 7, minute: 0, second: 0, of: nowDateValue, options: [])
let todayAtTenPM = calendar.date(bySettingHour: 22, minute: 0, second: 0, of: nowDateValue, options: [])

if nowDateValue >= todayAtSevenAM! &&
   nowDateValue <= todayAtTenPM!
{
    // date is in range
}

非常方便。


depreciated...? - Dylan
1
公爵夫人,好答案,使用 date(bySettingHour:minute:second:of:)。这是一个较新的 Calendar 函数,似乎我错过了它。它消除了我对 Date 扩展的需求。 - Duncan C
实际上,date(bySettingHour:minute:second:of:options:) 看起来是一个 NSCalendar 函数,而等效的 Swift 3 Calendar 函数是 date(bySettingHour:minute:second:of:matchingPolicy:repeatedTimePolicy:direction:) - Duncan C
1
谢谢,这段Swift 3代码对我有用: let todayAtEightAM = calendar.date(bySettingHour: hourStart, minute: minStart, second: 00, of: nowDateValue) let todayAtSevenThirtyPM = calendar.date(bySettingHour: hourEnd, minute: minEnd, second: 00, of: nowDateValue) - Chandni

7
您可以从今天的日期中获取年、月、日,将它们附加到这些日期时间字符串中以构建新的Date对象。然后,将 todaysDate 与这两个结果Date对象进行比较
let todaysDate  = Date()
let startString = "8:00"
let endString   = "16:30"

// convert strings to `Date` objects

let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
let startTime = formatter.date(from: startString)
let endTime = formatter.date(from: endString)

// extract hour and minute from those `Date` objects

let calendar = Calendar.current

var startComponents = calendar.dateComponents([.hour, .minute], from: startTime!)
var endComponents = calendar.dateComponents([.hour, .minute], from: endTime!)

// extract day, month, and year from `todaysDate`

let nowComponents = calendar.dateComponents([.month, .day, .year], from: todaysDate)

// adjust the components to use the same date

startComponents.year  = nowComponents.year
startComponents.month = nowComponents.month
startComponents.day   = nowComponents.day

endComponents.year  = nowComponents.year
endComponents.month = nowComponents.month
endComponents.day   = nowComponents.day

// combine hour/min from date strings with day/month/year of `todaysDate`

guard
    let startDate = calendar.date(from: startComponents),
    let endDate = calendar.date(from: endComponents)
else {
    print("unable to create dates")
    return
}

// now we can see if today's date is inbetween these two resulting `NSDate` objects

let isInRange = todaysDate > startDate && todaysDate < endDate

查看此答案的上一个版本,获取Swift 2的答案。


7
下面的解决方案可以从系统中获取当前时间,然后检查它是否存在于指定范围内。 在我的情况下,时间范围为上午8点至下午5点。 这个解决方案适用于Swift 4.2。
 func CheckTime()->Bool{
    var timeExist:Bool
    let calendar = Calendar.current
    let startTimeComponent = DateComponents(calendar: calendar, hour:8)
    let endTimeComponent   = DateComponents(calendar: calendar, hour: 17, minute: 00)

    let now = Date()
    let startOfToday = calendar.startOfDay(for: now)
    let startTime    = calendar.date(byAdding: startTimeComponent, to: startOfToday)!
    let endTime      = calendar.date(byAdding: endTimeComponent, to: startOfToday)!

    if startTime <= now && now <= endTime {
        print("between 8 AM and 5:30 PM")
        timeExist = true
    } else {
        print("not between 8 AM and 5:30 PM")
        timeExist = false
    }
    return timeExist
}

3

这是我在当前项目中使用的一些代码。只需将开始时间设置为8:00,结束时间设置为16:30,时间戳设置为当前时间即可。

func isTimeStampCurrent(timeStamp:NSDate, startTime:NSDate, endTime:NSDate)->Bool{
    timeStamp.earlierDate(endTime) == timeStamp && timeStamp.laterDate(startTime) == timeStamp
}

感谢大家的反馈。我正在仔细研究,看哪个实现起来最容易。 - redman

3
此外,下面的解决方案如果我想查看某个时间是否在白天的特定时间范围内,则似乎较为简洁。
var greeting = String()
let date     = Date()
let calendar = Calendar.current
let hour     = calendar.component(.hour, from: date)
//let minutes  = calendar.component(.minute, from: date)
let morning = 3; let afternoon=12; let evening=16; let night=22;

print("Hour: \(hour)")
if morning < hour, hour < afternoon {
    greeting = "Good Morning!"
}else if afternoon < hour, hour < evening{
    greeting = "Good Afternoon!"
}else if evening < hour, hour < night{
    greeting = "Good Evening!"
}else{
    greeting = "Good Night"
}
print(greeting)

我想你可以修改它,例如检查月份是否也在某些范围内,例如:

sum = "Jan"
win = "March"
Spr = "May"
Aut = "Sept"

and continue from there...


这个是最好的,也很容易! - Björn

2
您可以使NSDate符合Comparable协议,以便能够使用==!=<=>=><运算符。例如:
extension NSDate : Comparable {}

//  To conform to Comparable, NSDate must also conform to Equatable.
//  Hence the == operator.
public func == (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedSame
}

public func > (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedDescending
}

public func < (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}

public func <= (lhs: NSDate, rhs: NSDate) -> Bool {
    return  lhs == rhs || lhs < rhs
}

public func >= (lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs == rhs || lhs > rhs
}

要检查一个日期是否在两个日期范围内,您可以使用以下代码:
let currentDate = NSDate()
let olderDate   = NSDate(timeIntervalSinceNow: -100)
let newerDate   = NSDate(timeIntervalSinceNow: 100)

olderDate < currentDate && currentDate < newerDate // Returns true

以下是使用运算符与NSDate的更多示例:
olderDate < newerDate  // True
olderDate > newerDate  // False
olderDate != newerDate // True
olderDate == newerDate // False

我在我的答案中也有这个,但是Swift 3使日期对象兼容和可比较,所以这个扩展不再需要了。 - Duncan C

2

点击以下链接查看如何在Swift中使用日期格式化器:

enter image description here

最初的回答


1
虽然这个链接可能回答了问题,但最好在这里包含答案的必要部分,并提供参考链接。仅有链接的答案如果链接页面发生更改,可能会变得无效。 - adiga

2
extension Date { 
    /// time returns a double for which the integer represents the hours from 1 to 24 and the decimal value represents the minutes.  
    var time: Double {
        Double(Calendar.current.component(.hour, from: self)) + Double(Calendar.current.component(.minute, from: self)) / 100
    }
}

// usage 
print(9.30...16.30 ~= Date().time ? "If you're on the East Coast, It is during market hours" : "its after hours")

1
你可以使用NSDatecompare方法:它会返回一个NSComparisonResultOrderedSameOrderedAscendingOrderedDescending),你可以将其与起始和结束日期进行比较:
let dateMaker = NSDateFormatter()
dateMaker.dateFormat = "yyyy/MM/dd HH:mm:ss"
let start = dateMaker.dateFromString("2015/04/15 08:00:00")!
let end = dateMaker.dateFromString("2015/04/15 16:30:00")!

func isBetweenMyTwoDates(date: NSDate) -> Bool {
    if start.compare(date) == .OrderedAscending && end.compare(date) == .OrderedDescending {
        return true
    }
    return false
}

println(isBetweenMyTwoDates(dateMaker.dateFromString("2015/04/15 12:42:00")!)) // prints true
println(isBetweenMyTwoDates(dateMaker.dateFromString("2015/04/15 17:00:00")!)) // prints false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接