How to ask a user for an accurate date in a date format - swift

So I have a program which I need to ask a user for a date and time. But that date has to either be in the future or the the very far past. And I have tried a UIDatePicker but have found out that a date picker isn't the best way to tend to this sort of problem because it requires a lot of scrolling, and the it doesn't load past a certain date for some reason. I was thinking of a UIPickerView that asks for Year, Month, Day, and Time. But I don't know how to do it because lets say that the month is September there is only 30 days so then how can I stop the user from selecting 31. So if anyone can help me that would be amazing. And if you have any questions or need for code just ask. Oh and by the way I would like it in a date format where I can compare it to other date.

Given the year and month, you can calculate the array of possible day values to be supplied to your picker like so:
let calendar = Calendar.current
let components = DateComponents(year: year, month: month, day: 1)
guard let date = calendar.date(from: components),
let range = calendar.range(of: .day, in: .month, for: date) else { return }
let days = Array(range)
I would like it in a date format where I can compare it to other date.
Once you have the year, month, and day, hour (converted to 24 hour value, from 0 to 23), you can build the Date object like so:
let calendar = Calendar.current
let components = DateComponents(year: year, month: month, day: day, hour: hour, minute: minute)
guard let date = calendar.date(from: components) else { return }
That date can now be compared to any other Date object.

Related

Swift/SwiftUI: week/date management in swift

I'm working on fitness app where users selects the days he wants to exercise on.
When he opens the app I wanna shown him the current week where he can observe the days his training sessions are scheduled for.
If he is from the US i wanna show him a week starting from Sunday. For EU users it should start with Monday.
Is there any way to get the "current" week dates depending on user's location/geo? Taking into account what day does the week start with in appropriate location.
I tried to find a solution for your question. I think this should work:
// Define a function that returns the following seven dates, given a start date
func getWeekDates(of startDate: Date, with calender: Calendar) -> [Date] {
var weekDates: [Date] = []
for i in 0..<7 {
weekDates.append(calendar.date(byAdding: .day, value: i, to: startDate)!)
}
return weekDates
}
// This should automatically take the right calendar for the user's locale
// If you want to specify the day weeks start with manually, choose .gregorian or .iso8601:
// .gregorian starts on Sunday, .iso8601 starts on Monday
let calendar = Calendar.current
let startOfCurrentWeek = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))
let currentWeekDates = getWeekDates(of: startOfCurrentWeek!, with: calendar)
Hope this helps.
Use
Calendar.current.firstWeekday
If it returns 1, then Sunday is the first day of week
If it returns 2, then Monday is the first day of week.
You can test this by setting locale manually
var calendar = Calendar.current
calendar.locale = Locale(identifier: "en_GB")
print("\(calendar.locale!) starts on day \(calendar.firstWeekday)")
// en_GB starts on day 2
calendar.locale = Locale(identifier: "en_US")
print("\(calendar.locale!) starts on day \(calendar.firstWeekday)")

Get the current week number in month from Date

I am currently facing a weird issue. I am trying to find out in which week of a month a given Date instance lies.
My code is the following:
var calendar : Calendar {
var calendar = Calendar(identifier: .iso8601)
calendar.timeZone = .UTC
return calendar
}
func generateDate(year: Int, month: Int, day: Int) -> Date {
let dateComponents = DateComponents(year: year, month: month, day: day)
return calendar.date(from: dateComponents)!
}
print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2019, month: 12, day: 1))) // prints "0"
print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2020, month: 1, day: 1))) // prints "1"
generateDate simply generates a Date with the help of calendar. When I print the both statements I get 0 and 1 as the result. In my opinion this is wrong. I would assume I get the same value for both since both dates should be in the first week of their respective month value.
Another example would be the 2. Dec 2019, this should give the second week as well as the 6. January 2020 should also give me the second week.
Does anyone know what could be wrong here or where my mistake could be ?
This is due to the 1st day of the month falling on a sunday, try march 01, 2020 if you want confirmation.
The first week of the month is chosen by Swift according to their own standards as ISO standards do not suggest any specific implementations so the Swift team went with this. You can ask them in their forums what their reasoning behind this is Wikipedia link
The logic for .weekOfMonth seems to be that if the "first" week is less than half a week, that is 3 days, then it is considered to be week 0 and otherwise week 1. But note that this is dependent on what locale is being used, for a country like Canada that has Sunday as first day of week there is never a week 0 when running the below code. So when the first day of week is Monday .weekOfMonth will return a value between 0 and 5 but when it is Sunday the range is 1 to 6.
This can be seen running the following code in a playground
let calendar = Calendar.current
let year = 2019
print("First day of week: \(calendar.weekdaySymbols[calendar.firstWeekday - 1])")
for month in 1...12 {
print(calendar.monthSymbols[month - 1])
let first = calendar.date(from: DateComponents(year: year, month: month, day: 1))!
if let range = calendar.range(of: .day, in: .month, for: first) {
var currentWeek = -1
for day in range {
let date = calendar.date(from: DateComponents(year: year, month: month, day: day))!
let week = calendar.component(.weekOfMonth, from: date)
if week > currentWeek {
currentWeek = week
let dayOfWeek = calendar.component(.weekday, from: date)
print("Week# \(week), weekday \(calendar.weekdaySymbols[dayOfWeek - 1])")
}
}
}
}
It seems to me if you want whatever day it is on the 1st to be the first day of weekOfMonth = 1 then you need to write your own code for this

Calculate next pay day in Swift

I am trying to do some math calculations in Swift and getting a bit stuck.
Essentially we get paid every 4th Friday, and I want to do a calculation that based on today's date, works out how many days until our next Pay Day.
I've got a reference day of "28/03/2008",
In order to calculate the next 4th Friday of the month, you need a combination of the right DateComponents and Calendar.
// The 4th Friday at noon
let payDayComps = DateComponents(hour: 12, weekday: 6, weekdayOrdinal: 4)
// Given the current date, calculate the next 4th Friday at noon
let nextPayDay = Calendar.current.nextDate(after: Date(), matching: payDayComps, matchingPolicy: .nextTime)
You don't need a past reference date for this if your goal is to get the next 4th Friday based on today's date. Change the value of the after parameter if you need to calculate the 4th Friday based on some other specific date.
If this is run on the 4th Friday of a month then it will return today's date if run before noon and it will return the 4th Friday of the next month if run after noon. Change the hour value in payDayComps if you want different results (such as 0 for midnight).
To calculate the number of days until that next pay day you can do:
let daysToPayDay = Calendar.current.dateComponents([.day], from: Date(), to: nextPayDay).day!

Swift: Set custom Date(Day only) in DatePicker

I have two date pickers. Let's say fromDatePicker and untilDatePicker. I set the untilDatePicker to current date (ex: 12/06/17) and I want to set the fromDatePicker into first date of the current month (ex: 01/06/17) but I don't have any idea to set the untilDatePicker.
I have read this question but it's not helped me much.
This is swift3 solution and how you set first day of current month in datePicker , if you need to get first of other month just change date variable with some day from that month
let date = NSDate()
let calendar = NSCalendar.current
let components = calendar.dateComponents([.year,.month], from: date as Date)
let startOfMonth = calendar.date(from: components)
self.datePicker.setDate(startOfMonth!, animated: true)

Swift NSDate get current date but strip Year, Month, and Day

I am trying to get the current date using swift. I have that taken care of but it gets the year month and day and I really only want the current hour and minute. The reason being is that I am trying to later on compare a created date that only has an hour and minute. I am currently just using this
let currentDate = NSDate()
Thank you
let calendar = Calendar.autoupdatingCurrent
let components = calendar.dateComponents([.hour, .minute], from: Date())
let hour = components.hour
let minute = components.minute