Restricting enabled time to a specific time span in UIDatePicker swift 4 - ios

I'm trying to restrict the time of a datePicker from 09:00 AM to 09:00 PM (21:00) with a time interval of 30 minutes. I have tried all known means for that and have been searching the internet for a long time. But I found nothing.
Here is the code I wrote
//datePicker.setDate(dateFormatter.date(from: "09.00")!, animated: true)
datePicker.maximumDate = Calendar.current.date(byAdding: .hour, value: -12, to: dateFormatter.date(from: "21.00")!) //)Calendar.current.date(byAdding: Calendar.Component.hour, value: 1, to: Date())
datePicker.minimumDate = Calendar.current.date(byAdding: Calendar.Component.hour, value: -12, to: dateFormatter.date(from: "09.00")!)
But it didn't work. Please help.

Restricting user so she/he can only pick date between 9 and 12 but will show all the available options as this is date picker view's default behaviour but by setting proper minimumDate and maximumDate user can only pick between 9 and 21. Try below code and let me know if it works
And if you want to display times of your choice I will suggest better create an array of times you want to display, So user will only choose from the array you will provide In this case times between 9 am and 9 pm like [9:00,9:30,10:00,10:30,.....,21:00] and set that array to normal picker
datePicker.datePickerMode = .time // setting mode to timer so user can only pick time as you want
datePicker.minuteInterval = 30 // with interval of 30
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
let min = dateFormatter.date(from: "9:00") //createing min time
let max = dateFormatter.date(from: "21:00") //creating max time
datePicker.minimumDate = min //setting min time to picker
datePicker.maximumDate = max //setting max time to picker

The values you want to put in minimumDate and maximumDate are 9am and 9pm of the current date. The current date is what is missing in your code
let cal = Calendar.current
let now = Date() // get the current date and time (2018-03-27 19:38:44)
let components = cal.dateComponents([.day, .month, .year], from: now) // extract the date components 28, 3, 2018
let today = cal.date(from: components)! // build another Date value just with date components, without the time (2018-03-27 00:00:00)
datePicker.minimumDate = today.addingTimeInterval(60 * 60 * 9) // adds 9h
datePicker.maximumDate = today.addingTimeInterval(60 * 60 * 21) // adds 21h

Did you try to achieve this from storyboard?
try following configuration:
from code:
let calendar = Calendar.current
var dateComponents = calendar.dateComponents([.day, .month, .year], from: Date())
dateComponents.setValue(9, for: .hour)
let minDate = Calendar.current.date(from: dateComponents)
dateComponents.setValue(21, for: .hour)
let maxDate = Calendar.current.date(from: dateComponents)
self.datePicker?.minimumDate = minDate
self.datePicker?.maximumDate = maxDate
self.datePicker?.minuteInterval = 30

Try this:
let now = Date()
datePicker.datePickerMode = .time
datePicker.minimumDate = Calendar.current.date(bySettingHour: 9, minute: 0, second: 0, of: now)
datePicker.maximumDate = Calendar.current.date(bySettingHour: 21, minute: 0, second: 0, of: now)
datePicker.minuteInterval = 30

Related

Why did date ordinality calculations change in iOS 12?

Try the following in playgrounds. Before iOS 12, it worked for all inputs (starting with 1):
input would equal output
let input = 1
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
var dateComponents = DateComponents()
dateComponents.day = input
dateComponents.hour = 0
dateComponents.minute = 0
dateComponents.second = 0
let date = Calendar.current.date(from: dateComponents)
let dateString = dateFormatter.string(from: date!)
let date2 = dateFormatter.date(from: dateString)
let output = Calendar.current.ordinality(of: .day, in: .era, for: date2!)
assert(output==input)
But, now in iOS 12, output and input will only be equal starting with an input of 577738... which is date: Oct 17, 1582, which is two days after the Gregorian calendar went into effect (source: https://en.wikipedia.org/wiki/Gregorian_calendar)
So, what's going on here? And why did this change in iOS 12?

How to get local time zone date in swift 3

I am getting year,month and day from a given date in this way.
let today=Date()
var calendar = Calendar.current
calendar.timeZone = .current
let components = calendar.dateComponents([.year, .month, .day], from: today)
let day=components.day
But I'm getting one day ahead from my current day. How can I solve this?
let date = Date().description(with: Locale.current)
print("date ---> \(date)")
Result: date ---> Tuesday, June 20, 2017 at 4:35:15 PM India Standard Time
I'm getting perfect system/local time.
You code is working,
let today=Date()
var calendar = Calendar.current
calendar.timeZone = .current
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: today)
let day = components.day
let hour = components.hour
let minute = components.minute
print("day = \(day)\nhour = \(hour)\nminute = \(minute)")
Result: day = Optional(20) hour = Optional(16) minute = Optional(35)
Get Local Date and Time
Swift 5:
let today = Date()
let timeZone = Double(TimeZone.current.secondsFromGMT(for: today))
let localDate = Calendar.current.date(byAdding: .second, value: Int(timeZone), to: today) ?? Date()
As per the documentation:
If you want “date information in a given time zone” in order to
display it, you should use DateFormatter to format the date.
eg:
// If date is "Dec 7, 2018 at 6:34 AM" UTC
let today=Date() // is always UTC
var calendar = Calendar.current
calendar.timeZone = .current
let components = calendar.dateComponents([.year, .month, .day], from: today)
let day = components.day // Is 7
// To print with local version
let myFormatter = DateFormatter()
myFormatter.timeZone = TimeZone(secondsFromGMT: 3600*10)
myFormatter.dateFormat = "dd"
print(myFormatter.string(from: today)) // prints "07\n"
myFormatter.timeZone = TimeZone(secondsFromGMT: -3600*11)
print(myFormatter.string(from: today)) // prints "06\n"

Getting incorrect start and end dates from weekOfYear

When I run this code:
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.weekday = calendar.firstWeekday
dateComponents.weekOfYear = 2
dateComponents.year = 2017
let startOfWeek = calendar.date(from: dateComponents)
let endOfWeek = calendar.date(byAdding: .day, value: 6, to: startOfWeek!)
let formatter = DateFormatter()
formatter.dateStyle = .short
print(formatter.string(from: startOfWeek!))
print(formatter.string(from: endOfWeek!))
It prints this:
1/8/17
1/14/17
When I change the code to this:
dateComponents.weekOfYear = 1
dateComponents.year = 2017
It prints this:
12/31/17
1/6/18
Why is it 12/31/17?
When I use .full style to print the dates, I get Sunday, December 31, 2017 for the first date, but it's obviously wrong because December 31 is a Thursday.
If you want to get the correct date, use yearForWeekOfYear instead of year. Docs:
You can use the yearForWeekOfYear property with the weekOfYear and weekday properties to get the date corresponding to a particular weekday of a given week of a year. For example, the 6th day of the 53rd week of the year 2005 (ISO 2005-W53-6) corresponds to Sat 1 January 2005 on the Gregorian calendar.
Alternative, you can be a little naughty and not listen to the docs and use weekOfYear = 54:
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.weekday = calendar.firstWeekday
dateComponents.weekOfYear = 54
dateComponents.year = 2017
let startOfWeek = calendar.date(from: dateComponents)
let endOfWeek = calendar.date(byAdding: .day, value: 6, to: startOfWeek!)
let formatter = DateFormatter()
formatter.dateStyle = .short
print(formatter.string(from: startOfWeek!))
print(formatter.string(from: endOfWeek!))
This prints:
1/1/17
1/7/17
which is coincidentally, the correct dates.

Swift - Get date from day of year

We can get day of year for date using below line.
let day = cal.ordinalityOfUnit(.Day, inUnit: .Year, forDate: date)
But how can we get the date from day of year?
If you know the year you can get DateComponents date property as follow:
extension Calendar {
static let iso8601 = Calendar(identifier: .iso8601)
}
let now = Date()
let day = Calendar.iso8601.ordinality(of: .day, in: .year, for: now)! // 121
let year = Calendar.iso8601.component(.year, from: now) // 2017
let date = DateComponents(calendar: .iso8601, year: year, day: day).date // "May 1, 2017, 12:00 AM"
or using DateFormatter
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy D"
if let date = dateFormatter.date(from: "\(year) \(day)") {
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.string(from: date) // "May 1, 2017, 12:00 AM"
}
You cannot go the other way. Going from a date to a day of the year discards all other information, you are left with only the day of the year (you no longer know what year). To go back to a full date you would have to make assumptions about the year the day was in.
The answer that #LeoDabus gave is more succinct than this, so it is perhaps the better choice. Having said that, this is the code that I would have used:
let dateComponents = NSDateComponents();
dateComponents.year = 2015
dateComponents.day = day
let calendar = NSCalendar.currentCalendar()
let date = calendar.dateFromComponents(dateComponents)
Updated for Swift 4:
let dateComponents = NSDateComponents();
dateComponents.year = 2018
dateComponents.day = someDay
let calendar = NSCalendar.current
let date = calendar.date(from: dateComponents as DateComponents)

NSDate day of the year (swift)

How might the day number of the year be found with swift? Is there a simple way that I'm not seeing, or do I have to find the number of seconds from Jan 1 to the current date and divide by the number of seconds in a day?
This is a translation of the answer to How do you calculate the day of the year for a specific date in Objective-C? to Swift.
Swift 2:
let date = NSDate() // now
let cal = NSCalendar.currentCalendar()
let day = cal.ordinalityOfUnit(.Day, inUnit: .Year, forDate: date)
print(day)
Swift 3:
let date = Date() // now
let cal = Calendar.current
let day = cal.ordinality(of: .day, in: .year, for: date)
print(day)
This gives 1 for the first day in the year, and 56 = 31 + 25 for today (Feb 25).
... or do I have to find the number of seconds from Jan 1 to the current date
and divide by the number of seconds in a day
This would be a wrong approach, because a day does not have a fixed
number of seconds (transition from or to Daylight Saving Time).
Swift 3
extension Date {
var dayOfYear: Int {
return Calendar.current.ordinality(of: .day, in: .year, for: self)!
}
}
use like
Date().dayOfYear
Not at all !!! All you have to do is to use NSCalendar to help you do your calendar calculations as follow:
let firstDayOfTheYear = NSCalendar.currentCalendar().dateWithEra(1, year: NSCalendar.currentCalendar().component(.CalendarUnitYear, fromDate: NSDate()), month: 1, day: 1, hour: 0, minute: 0, second: 0, nanosecond: 0)! // "Jan 1, 2015, 12:00 AM"
let daysFromJanFirst = NSCalendar.currentCalendar().components(.CalendarUnitDay, fromDate: firstDayOfTheYear, toDate: NSDate(), options: nil).day // 55
let secondsFromJanFirst = NSCalendar.currentCalendar().components(.CalendarUnitSecond, fromDate: firstDayOfTheYear, toDate: NSDate(), options: nil).second // 4,770,357
You can find the number of days since your date like this:
let date = NSDate() // your date
let days = cal.ordinalityOfUnit(.CalendarUnitDay, inUnit: .CalendarUnitYear, forDate: date)
println(days)

Resources