提问人:Paul B 提问时间:7/3/2020 更新时间:7/4/2020 访问量:1058
可跨步日期
Strideable Date
问:
我正在寻找很酷的方式来以不同的增量(秒或又名,Date
TimeInterval
DateComponents
.hour
.minute
)
import Foundation
extension Date: Strideable {
// typealias Stride = SignedInteger // doesn't work (probably because declared in extension
public func advanced(by n: Int) -> Date {
self.addingTimeInterval(TimeInterval(n))
}
public func distance(to other: Date) -> Int {
return Int(self.distance(to: other))
}
}
let now = Date()
let dayAfterNow = Date().addingTimeInterval(86400)
let dateRange = now ... dayAfterNow
let dateArr : [Date] = Array(stride(from: now, to: dayAfterNow, by: 60)) // Solves my task but not exactly how I wanted.
let formatter: DateFormatter = {
let df = DateFormatter()
df.timeStyle = .short
return df }()
print (dateArr.prefix(7).map { formatter.string(from: $0) })
/// This hoever doesn't work
// There must be a way to make it work but couldn't figure it out for now
let errDateArr: [Date] = Array(dateRange)
// Error: Initializer 'init(_:)' requires that 'Date.Stride' (aka 'Double') conform to 'SignedInteger'
问题的第二部分是,我也想有这样的东西:
var components = DateComponents()
components.hour = 8
components.minute = 0
let date = Calendar.current.date(from: components)
let dateByComponentArr : [Date] = Array(stride(from: now, to: dayAfterNow, by: components))
答:
已经声明的实现存在冲突:Date.distance(to:)。
您定义的实现具有相同的名称,但类型不同。这个其他重载可以工作,但不幸的是,对你来说,已经声明了一个名为 的类型别名,它设置为(只是 的别名)。distance(to:)
Date
Date
Stride
TimeInterval
Double
我认为顺从是个坏主意。举个例子,它故意不符合:没有明确的普遍最佳步幅定义。它应该上升吗? ? ?这并不明显。 正是出于这个原因而存在,让你明确地知道你正在大步走过多少。Date
Strideable
Double
Strideable
0.1
0.01
3.14
stride(from:to:by:)
let errDateArr: [Date] = Array(now ... dayAfterNow)
肯定会获得高“WTFs/m”分
评论
Stride
Int
Double
Stridable
stride
...
Strideable
Stride
SignedInteger
对于问题的第二部分,我创建了一个简单的序列,其中考虑了夏令时设置和其他内容。在某些特定情况下,它可能会有所帮助。
let dayAfterNow = Date().addingTimeInterval(86400)
var components = DateComponents()
components.hour = 8
components.minute = 0
func dateIterator(start: Date = Date(), by components: DateComponents, wrappingComponents: Bool = false) -> AnyIterator<Date> {
var state = start
return AnyIterator {
let nextDate = Calendar.current.date(byAdding: components, to: state, wrappingComponents: wrappingComponents)
state = nextDate ?? state
return state
}
}
let dateCompSequence = AnySequence(dateIterator(by: components))
let dateArray = Array(dateCompSequence.prefix(10))
dateArray.map{print($0.description)}
print("starting for loop...")
for d in dateCompSequence.prefix(10) {
print(d.description)
}
值得注意的是,这可能总是有助于完成类似的任务。但有时有一个序列是可取的。在早期版本的 Swift 中,似乎有一个由 NSCalendar 提供的可跨步 DateRange 类型(正是我想要的),但现在标准库中没有类似的东西。Calendar.current.enumerateDates()
评论
let start = DateComponents(calendar: .current, year: 2020, month: 6, day: 30, hour: 23, minute: 45).date!
for d in dateIterator(start: start, by: .init(month: 1)).prefix(10) {
print(Date.formatter.string(from: d))
}
正如 @Alexander 已经提到的,您不应该尝试将 Date 与 Strideable 保持一致,但您可以实现自己的方法来生成接下来的 n 天、小时或分钟:
extension Date {
func year(using calendar: Calendar = .current) -> Int { calendar.component(.year, from: self) }
func month(using calendar: Calendar = .current) -> Int { calendar.component(.month, from: self) }
func day(using calendar: Calendar = .current) -> Int { calendar.component(.day, from: self) }
func hour(using calendar: Calendar = .current) -> Int { calendar.component(.hour, from: self) }
func minute(using calendar: Calendar = .current) -> Int { calendar.component(.minute, from: self) }
func nextDays(n: Int, nth: Int = 1, using calendar: Calendar = .current) -> [Date] {
let year = self.year(using: calendar)
let month = self.month(using: calendar)
let day = self.day(using: calendar)
var days: [Date] = []
for x in 0..<n where x.isMultiple(of: nth) {
days.append(DateComponents(calendar: calendar, year: year, month: month, day: day + x, hour: 12).date!)
}
return days
}
func nextHours(n: Int, nth: Int = 1, using calendar: Calendar = .current) -> [Date] {
let year = self.year(using: calendar)
let month = self.month(using: calendar)
let day = self.day(using: calendar)
let hour = self.hour(using: calendar)
var hours: [Date] = []
for x in 0..<n where x.isMultiple(of: nth) {
hours.append(DateComponents(calendar: calendar, year: year, month: month, day: day, hour: hour + x).date!)
}
return hours
}
func nextMinutes(n: Int, nth: Int = 1, using calendar: Calendar = .current) -> [Date] {
let year = self.year(using: calendar)
let month = self.month(using: calendar)
let day = self.day(using: calendar)
let hour = self.hour(using: calendar)
let minute = self.minute(using: calendar)
var minutes: [Date] = []
for x in 0..<n where x.isMultiple(of: nth) {
minutes.append(DateComponents(calendar: calendar, year: year, month: month, day: day, hour: hour, minute: minute + x).date!)
}
return minutes
}
}
extension Date {
static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter
}()
}
Playgournd测试:
let days = Date().nextDays(n: 10)
for day in days {
print(Date.formatter.string(from: day))
}
let hours = Date().nextHours(n: 10)
for hour in hours {
print(Date.formatter.string(from: hour))
}
let minutes = Date().nextMinutes(n: 10)
for minute in minutes {
print(Date.formatter.string(from: minute))
}
评论
nth
评论
Calendar
enumerateDates()
DateRange
NSCalendar