Skip to content

Instantly share code, notes, and snippets.

@matnogaj
Last active March 14, 2022 05:58
Show Gist options
  • Select an option

  • Save matnogaj/d6ffa9bd44ed52a38440 to your computer and use it in GitHub Desktop.

Select an option

Save matnogaj/d6ffa9bd44ed52a38440 to your computer and use it in GitHub Desktop.
Custom date picker with "infinite" hours and minutes
import UIKit
@objc protocol CustomDatePickerSourceDelegate:NSObjectProtocol {
func datePickerDidSelectDate(date:NSDate)
}
@objc class CustomDatePickerSource: NSObject {
enum Component:Int {
case Day = 0
case Hour = 1
case Minute = 2
}
private let currentDate = NSDate()
private let dateFormatter = NSDateFormatter()
private let numberFormatter = NSNumberFormatter()
private var days:[NSDate] = []
private var hours:[Int] = []
private var minutes:[Int] = []
@IBOutlet weak var delegate:CustomDatePickerSourceDelegate?
private var selectedDate:(day:NSDate, hour:Int, minute:Int)
override init() {
selectedDate.day = currentDate
selectedDate.hour = 0
selectedDate.minute = 0
super.init()
dateFormatter.dateStyle = .MediumStyle
dateFormatter.timeStyle = .NoStyle
numberFormatter.formatWidth = 2
numberFormatter.paddingPosition = .BeforePrefix
numberFormatter.paddingCharacter = "0"
let currentDateComponents = NSCalendar.currentCalendar().components([NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: currentDate)
days = setupDate(currentDate)
hours = setupHours(currentDateComponents.hour)
minutes = setupMinutes(currentDateComponents.minute, interval: 5)
selectedDate.day = days[0]
selectedDate.hour = hours[0]
selectedDate.minute = minutes[0]
}
private func setupDate(startingDate:NSDate) -> [NSDate] {
var result:[NSDate] = []
let calendar = NSCalendar.currentCalendar()
let todayComponents = NSDateComponents()
todayComponents.day = calendar.component(.Day, fromDate: startingDate)
todayComponents.month = calendar.component(.Month, fromDate: startingDate)
todayComponents.year = calendar.component(.Year, fromDate: startingDate)
let dayComponent = NSDateComponents()
dayComponent.day = 1
if let today = calendar.dateFromComponents(todayComponents) {
result.append(today)
var nextDay = today
for _ in 0...365 {
if let date = calendar.dateByAddingComponents(dayComponent, toDate: nextDay, options: NSCalendarOptions(rawValue: 0)) {
result.append(date)
nextDay = date
}
}
}
return result
}
private func setupHours(startingHour:Int) -> [Int] {
var result:[Int] = []
for i in 0..<24 {
let value = (startingHour + i) % 24
result.append(value)
}
return result
}
private func setupMinutes(startingMinute:Int, interval:Int = 1) -> [Int] {
var result:[Int] = []
let count = Int(60.0 / Double(interval))
for i in 0..<count {
let value = ((Int(ceil(Double(startingMinute) / Double(interval))) + i + 1) * interval) % 60
result.append(value)
}
return result
}
private func currentSelectedDate() -> NSDate? {
let timeComponents = NSDateComponents()
timeComponents.hour = selectedDate.hour
timeComponents.minute = selectedDate.minute
if let date = NSCalendar.currentCalendar().dateByAddingComponents(timeComponents, toDate: selectedDate.day, options: NSCalendarOptions(rawValue: 0)) {
return date
}
return nil
}
}
extension CustomDatePickerSource : UIPickerViewDataSource {
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 3
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if let column = Component(rawValue: component) {
switch column {
case .Day: return days.count
case .Hour: return Int(Int16.max)//hours.count
case .Minute: return Int(Int16.max)//minutes.count
}
}
return 10
}
}
extension CustomDatePickerSource : UIPickerViewDelegate {
func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
if let column = Component(rawValue: component) {
switch column {
case .Day: return 150.0
case .Hour: return 40.0
case .Minute: return 40.0
}
}
return 100.0
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 50.0
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if let column = Component(rawValue: component) {
switch column {
case .Day:
return dateFormatter.stringFromDate(days[row])
case .Hour:
return "\(numberFormatter.stringFromNumber(hours[row % hours.count])!)"
case .Minute:
return "\(numberFormatter.stringFromNumber(minutes[row % minutes.count])!)"
}
}
return ""
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if let column = Component(rawValue: component) {
switch column {
case .Day: selectedDate.day = days[row]
case .Hour: selectedDate.hour = hours[row % hours.count]
case .Minute: selectedDate.minute = minutes[row % minutes.count]
}
}
if let date = currentSelectedDate() {
delegate?.datePickerDidSelectDate(date)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment