1 year ago

#327998

test-img

Molly C

DateTimePicker not displaying the right date

I'm using a DateTimePicker that contains a Start Date and Time. Although the time updates properly, the date does not update based on the scrollview. Any idea what I can change to make it work?

Here's the code:

class DateTimePicker: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
    
  // Reference from https://stackoverflow.com/questions/40878547/is-it-possible-to-have-uidatepicker-work-with-start-and-end-time
    
    var didSelectDates: ((_ start: Date) -> Void)?
      
      private lazy var pickerView: UIPickerView = {
        let pickerView = UIPickerView()
        pickerView.delegate = self
        pickerView.dataSource = self
        pickerView.backgroundColor = .white
        return pickerView
      }()
      
      private var days = [Date]()
      private var startTimes = [Date]()
//      private var endTimes = [Date]()
      
      let dayFormatter = DateFormatter()
      let timeFormatter = DateFormatter()
      
      var inputView: UIView {
        return pickerView
      }
      
      func setup() {
        dayFormatter.dateFormat = "EE d MMM"
        timeFormatter.timeStyle = .short
        days = setDays()
        startTimes = setStartTimes()
//        endTimes = setEndTimes()
      }
      
      // MARK: - UIPickerViewDelegate & DateSource
      
      func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
      }
      
      func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0:
          return days.count
        case 1:
          return startTimes.count
//        case 2:
//          return endTimes.count
        default:
          return 0
        }
      }
      
      func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        var label: UILabel
        
        if let view = view as? UILabel {
          label = view
        } else {
          label = UILabel()
        }
        
        label.textColor = .black
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 15)
        
        var text = ""
        
        switch component {
        case 0:
          text = getDayString(from: days[row])
        case 1:
          text = getTimeString(from: startTimes[row])
//        case 2:
//          text = getTimeString(from: endTimes[row])
        default:
          break
        }
        
        label.text = text
        
        return label
      }
      
      func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        
        let dayIndex = pickerView.selectedRow(inComponent: 0)
        let startTimeIndex = pickerView.selectedRow(inComponent: 1)
//        let endTimeIndex = pickerView.selectedRow(inComponent: 2)
        
        guard days.indices.contains(dayIndex),
                startTimes.indices.contains(startTimeIndex)
//                endTimes.indices.contains(endTimeIndex)
          else { return }

        let startTime = startTimes[startTimeIndex]
//        let endTime = endTimes[endTimeIndex]
        
        didSelectDates?(startTime)
      }
      
      // MARK: - Private helpers
      
      private func getDays(of date: Date) -> [Date] {
        var dates = [Date]()
        
        let calendar = Calendar.current
        
        // first date
        var currentDate = date
        
        // adding 30 days to current date
        let oneMonthFromNow = calendar.date(byAdding: .day, value: 30, to: currentDate)
        
        // last date
        let endDate = oneMonthFromNow
        
        while currentDate <= endDate! {
          dates.append(currentDate)
          currentDate = calendar.date(byAdding: .day, value: 1, to: currentDate)!
        }
        
        return dates
      }
      
      private func getTimes(of date: Date) -> [Date] {
        var times = [Date]()
        var currentDate = date
        
        currentDate = Calendar.current.date(bySetting: .hour, value: 7, of: currentDate)!
        currentDate = Calendar.current.date(bySetting: .minute, value: 00, of: currentDate)!
        
        let calendar = Calendar.current
        
        let interval = 60
        var nextDiff = interval - calendar.component(.minute, from: currentDate) % interval
        var nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: currentDate) ?? Date()
        
        var hour = Calendar.current.component(.hour, from: nextDate)
        
        while(hour < 23) {
          times.append(nextDate)
          
          nextDiff = interval - calendar.component(.minute, from: nextDate) % interval
          nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: nextDate) ?? Date()
          
          hour = Calendar.current.component(.hour, from: nextDate)
        }
        
        return times
      }
      
      private func setDays() -> [Date] {
        let today = Date()
        return getDays(of: today)
      }
      
      private func setStartTimes() -> [Date] {
        let today = Date()
        return getTimes(of: today)
      }
      
//      private func setEndTimes() -> [Date] {
//        let today = Date()
//        return getTimes(of: today)
//      }
      
      private func getDayString(from: Date) -> String {
        return dayFormatter.string(from: from)
      }
      
      private func getTimeString(from: Date) -> String {
        return timeFormatter.string(from: from)
      }
      
    }

    extension Date {

      static func buildTimeRangeString(startDate: Date) -> String {
        
        let dayFormatter = DateFormatter()
        dayFormatter.dateFormat = "EEEE, MMM d"

        let startTimeFormatter = DateFormatter()
        startTimeFormatter.dateFormat = "h a"
        
//        let endTimeFormatter = DateFormatter()
//        endTimeFormatter.dateFormat = "h:mm a"
        
        return String(format: "%@, %@",
                      dayFormatter.string(from: startDate),
                      startTimeFormatter.string(from: startDate))
//                      endTimeFormatter.string(from: endDate))
      }
    }

(Reference: https://www.youtube.com/watch?v=vZsJwsZ3iKQ)

In the main MessagesViewController, I have :

    private lazy var dateTimePicker: DateTimePicker = {
        let picker = DateTimePicker()
        picker.setup()
        picker.didSelectDates = {[weak self](startDate) in
            let text = Date.buildTimeRangeString(startDate: startDate)
            self?.actualDate = startDate
            self?.label.text = text
            dateText = text
        }
        return picker
    }()

swift

xcode

datetimepicker

0 Answers

Your Answer

Accepted video resources