简体   繁体   English

Swift-检查日期是否在下周/月。 (isDateInNextWeek()isDateInNextMonth())

[英]Swift - Check if date is in next week / month. ( isDateInNextWeek() isDateInNextMonth() )

We have those convenient functions in calendar: 我们在日历中具有以下便捷功能:

let calendar = NSCalendar.currentCalendar()
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)

But I am missing those two: 但是我缺少这两个:

  • calendar.isDateInNextWeek(date) calendar.isDateInNextWeek(date)

  • calendar.isDateInNextMonth(date) calendar.isDateInNextMonth(date)

As @Rob mentioned, the meaning is: "in the calendar week starting this coming Sunday, going through the following Saturday" 正如@Rob所提到的,其含义是:“在从下一个星期日开始的日历周中,直到下一个星期六”

I having a hard time figuring out how to implement those functions in a robust way that covers all the corner cases. 我很难弄清楚如何以健壮的方式来实现这些功能,从而涵盖所有极端情况。

Can someone provide an assistant? 有人可以提供助手吗?

The algorithm is not very spectacular: 该算法不是很出色:

  1. Calculate start of current week 计算本周开始
  2. Use result from 1 to calculate start of next week 使用1的结果来计算下周开始
  3. Use result from 2 to calculate start of week after next week 使用2的结果来计算下周之后的一周的开始
  4. Date is in next week if its on or after the start of next week and before the start of the week after next week 如果日期在下周开始或之后以及下周之后的一周开始之前,则在下周

NSCalendar does most of the work for us. NSCalendar为我们完成了大部分工作。 But it looks still a bit intimidating, at least if you don't use these date methods often. 但这看起来还是有些吓人,至少如果您不经常使用这些日期方法。 You should read the documentation of all of these methods to understand them. 您应该阅读所有这些方法的文档以了解它们。

let calendar = NSCalendar.currentCalendar()
let date = NSDate()

var startOfThisWeek: NSDate?
if !calendar.rangeOfUnit(.CalendarUnitWeekOfMonth, startDate: &startOfThisWeek, interval: nil, forDate: date) {
    fatalError("Can't calculate start of this week")
}
let startOfNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfThisWeek!, options: nil)!
let startOfNextNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfNextWeek, options: nil)!

Just switch .CalendarUnitWeekOfMonth with .CalendarUnitMonth and you get the calculation for this, next and the following month. 只需将.CalendarUnitWeekOfMonth.CalendarUnitMonth切换, .CalendarUnitMonth可以得到.CalendarUnitWeekOfMonth.CalendarUnitMonth.CalendarUnitMonth的计算。

var startOfThisMonth: NSDate?
if !calendar.rangeOfUnit(.CalendarUnitMonth, startDate: &startOfThisMonth, interval: nil, forDate: date) {
    fatalError("Can't calculate start of this month")
}
let startOfNextMonth = calendar.dateByAddingUnit(.CalendarUnitMonth, value: 1, toDate: startOfThisMonth!, options: nil)!
let startOfNextNextMonth = calendar.dateByAddingUnit(.CalendarUnitMonth, value: 1, toDate: startOfNextMonth, options: nil)!

And the test: 和测试:

let testDate = NSDate(timeIntervalSinceNow: 7*24*60*60)

if startOfThisWeek <= testDate && testDate < startOfNextWeek {
    println("\(testDate) is this week")
}
if startOfNextWeek <= testDate && testDate < startOfNextNextWeek {
    println("\(testDate) is next week")
}
if startOfThisMonth <= testDate && testDate < startOfNextMonth {
    println("\(testDate) is this month")
}
if startOfNextMonth <= testDate && testDate < startOfNextNextMonth {
    println("\(testDate) is next month")
}

Result: 结果:

"2015-03-22 02:55:19 +0000 is next week" “ 2015-03-22 02:55:19 +0000是下周”
"2015-03-22 02:55:19 +0000 is this month" “ 2015-03-22 02:55:19 +0000是这个月”

Sounds right. 听起来不错。

And if you want to use <= , == , < etc. instead of the ugly (and confusing) NSComparisonResult you need this as well: 而且,如果要使用<===<等,而不是丑陋(且令人困惑)的NSComparisonResult也需NSComparisonResult

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

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

extension NSDate: Comparable { }

This is iOS8 code. 这是iOS8代码。 If you want to write code that works on older versions you have to replace dateByAddingUnit:value::toDate:options: by good old NSDateComponents. 如果要编写适用于较旧版本的代码,则必须用良好的旧NSDateComponents替换dateByAddingUnit:value::toDate:options: ie: 即:

let offSetComponents = NSDateComponents()
offSetComponents.weekOfMonth = 1
let startOfNextWeek = calendar.dateByAddingComponents(offSetComponents, toDate: startOfThisWeek, options: nil)

Problem solved using Swift 5 and extending Calendar . 使用Swift 5和扩展Calendar解决了问题。

extension Calendar {
  private var currentDate: Date { return Date() }

  func isDateInThisWeek(_ date: Date) -> Bool {
    return isDate(date, equalTo: currentDate, toGranularity: .weekOfYear)
  }

  func isDateInThisMonth(_ date: Date) -> Bool {
    return isDate(date, equalTo: currentDate, toGranularity: .month)
  }

  func isDateInNextWeek(_ date: Date) -> Bool {
    guard let nextWeek = self.date(byAdding: DateComponents(weekOfYear: 1), to: currentDate) else {
      return false
    }
    return isDate(date, equalTo: nextWeek, toGranularity: .weekOfYear)
  }

  func isDateInNextMonth(_ date: Date) -> Bool {
    guard let nextMonth = self.date(byAdding: DateComponents(month: 1), to: currentDate) else {
      return false
    }
    return isDate(date, equalTo: nextMonth, toGranularity: .month)
  }

  func isDateInFollowingMonth(_ date: Date) -> Bool {
    guard let followingMonth = self.date(byAdding: DateComponents(month: 2), to: currentDate) else {
      return false
    }
    return isDate(date, equalTo: followingMonth, toGranularity: .month)
  }
}

Usage: 用法:

let day: Double = 60 * 60 * 24
let currentDate = Date() // Thu 25 Apr 2019
let futureDate = Date(timeInterval: 3 * day, since: currentDate) // Sun 28 Apr 2019
if Calendar.current.isDateInThisWeek(futureDate) { 
    // this will be executed if first day of week is Monday
} else {
    // this will be executed if first day of week is Sunday
}

Code evaluates if the dates are in the range (sameWeek, nextWeek) according to Calendar instance. 代码根据Calendar实例评估日期是否在范围内(sameWeek,nextWeek)。

If Calendar instance is current it will determine start of the week (Monday or Sunday) according to device settings, but if you want different behaviour you can change Calendar instance: Calendar(identifier: .chinese).isDateInNextWeek(someDate) 如果Calendar实例是current ,它将根据设备设置确定一周的开始时间(星期一或星期日),但是如果您想要其他行为,则可以更改Calendar实例: Calendar(identifier: .chinese).isDateInNextWeek(someDate)

This code also works if we're trying to create DateComponents with improper values like so: DateComponents(year: 2019, month: 13) . 如果我们试图使用不正确的值创建DateComponents ,则此代码也可以使用: DateComponents(year: 2019, month: 13) In this case it creates date 01 Jan 2020 . 在这种情况下,它将创建日期01 Jan 2020

I came up with this naive code: 我想出了这个天真的代码:

extension NSCalendar
{
    func isDateInNextWeek(value: NSDate) -> Bool
    {
        let componentsValue = self.components(.WeekOfYearCalendarUnit | .YearCalendarUnit,  fromDate: value)
        let componentsToday = self.components(.WeekOfYearCalendarUnit | .YearCalendarUnit,  fromDate: NSDate())

        let weekOfYearValue = componentsValue.weekOfYear
        let weekOfYearToday = componentsToday.weekOfYear
        let yearValue = componentsValue.year
        let yearToday = componentsToday.year

        if(yearValue < yearToday)
        {
            return false
        }
        else if(yearValue == yearToday && weekOfYearValue - weekOfYearToday == 1)
        {
           return true
        }
        else if(yearValue - yearToday == 1 && weekOfYearValue == 1 && weekOfYearToday == 52)
        {
            return true
        }
        else
        {
            return false
        }
    }
}

But I must be missing some edge cases here. 但是我在这里一定会错过一些极端情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM