Swift - 检查日期是否在下周/下月。 ( isDateInNextWeek() isDateInNextMonth() )
Swift - Check if date is in next week / month. ( isDateInNextWeek() isDateInNextMonth() )
我们在日历中有那些方便的功能:
let calendar = NSCalendar.currentCalendar()
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)
但我错过了那两个:
calendar.isDateInNextWeek(日期)
calendar.isDateInNextMonth(日期)
正如@Rob所说,意思是:"in the calendar week starting this coming Sunday, going through the following Saturday"
我很难弄清楚如何以涵盖所有极端情况的稳健方式实现这些功能。
有人可以提供助手吗?
我想出了这个天真的代码:
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
}
}
}
但我一定遗漏了一些边缘情况。
算法不是很壮观:
- 计算本周的开始
- 使用 1 的结果计算下周的开始
- 使用 2 的结果计算下周之后的一周开始时间
- 如果日期在下周开始日或之后,并且在下周之后的一周开始之前,则为下周
NSCalendar 为我们完成了大部分工作。但它看起来还是有点吓人,至少如果你不经常使用这些日期方法的话。您应该阅读所有这些方法的文档以了解它们。
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)!
只需将 .CalendarUnitWeekOfMonth
切换为 .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)!
测试:
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")
}
结果:
"2015-03-22 02:55:19 +0000 is next week"
"2015-03-22 02:55:19 +0000 is this month"
听起来不错。
如果你想使用 <=
、==
、<
等而不是丑陋的(和令人困惑的)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 { }
这是 iOS8 代码。如果你想编写适用于旧版本的代码,你必须将 dateByAddingUnit:value::toDate:options:
替换为良好的旧 NSDateComponents。即:
let offSetComponents = NSDateComponents()
offSetComponents.weekOfMonth = 1
let startOfNextWeek = calendar.dateByAddingComponents(offSetComponents, toDate: startOfThisWeek, options: nil)
使用 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)
}
}
用法:
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
}
代码根据 Calendar
实例评估日期是否在范围内(sameWeek,nextWeek)。
如果 Calendar
实例是 current
它将根据设备设置确定一周的开始(星期一或星期日),但如果您想要不同的行为,您可以更改 Calendar
实例:
Calendar(identifier: .chinese).isDateInNextWeek(someDate)
如果我们尝试使用不正确的值创建 DateComponents
,此代码也有效,例如:DateComponents(year: 2019, month: 13)
。
在这种情况下,它创建日期 01 Jan 2020
.
我们在日历中有那些方便的功能:
let calendar = NSCalendar.currentCalendar()
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)
但我错过了那两个:
calendar.isDateInNextWeek(日期)
calendar.isDateInNextMonth(日期)
正如@Rob所说,意思是:"in the calendar week starting this coming Sunday, going through the following Saturday"
我很难弄清楚如何以涵盖所有极端情况的稳健方式实现这些功能。
有人可以提供助手吗?
我想出了这个天真的代码:
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
}
}
}
但我一定遗漏了一些边缘情况。
算法不是很壮观:
- 计算本周的开始
- 使用 1 的结果计算下周的开始
- 使用 2 的结果计算下周之后的一周开始时间
- 如果日期在下周开始日或之后,并且在下周之后的一周开始之前,则为下周
NSCalendar 为我们完成了大部分工作。但它看起来还是有点吓人,至少如果你不经常使用这些日期方法的话。您应该阅读所有这些方法的文档以了解它们。
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)!
只需将 .CalendarUnitWeekOfMonth
切换为 .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)!
测试:
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")
}
结果:
"2015-03-22 02:55:19 +0000 is next week"
"2015-03-22 02:55:19 +0000 is this month"
听起来不错。
如果你想使用 <=
、==
、<
等而不是丑陋的(和令人困惑的)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 { }
这是 iOS8 代码。如果你想编写适用于旧版本的代码,你必须将 dateByAddingUnit:value::toDate:options:
替换为良好的旧 NSDateComponents。即:
let offSetComponents = NSDateComponents()
offSetComponents.weekOfMonth = 1
let startOfNextWeek = calendar.dateByAddingComponents(offSetComponents, toDate: startOfThisWeek, options: nil)
使用 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)
}
}
用法:
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
}
代码根据 Calendar
实例评估日期是否在范围内(sameWeek,nextWeek)。
如果 Calendar
实例是 current
它将根据设备设置确定一周的开始(星期一或星期日),但如果您想要不同的行为,您可以更改 Calendar
实例:
Calendar(identifier: .chinese).isDateInNextWeek(someDate)
如果我们尝试使用不正确的值创建 DateComponents
,此代码也有效,例如:DateComponents(year: 2019, month: 13)
。
在这种情况下,它创建日期 01 Jan 2020
.