How to separate the date and time components of NSDate() in Swift? - swift

Would anyone be able to tell me how to separate the date and time components of NSDate() in Swift? I saw a few things about separating the date itself into components (day, month, year), but nothing really about how to get the time only or the day, month, and year only.
Basically, I'm trying to filter data on a table by date, but to also display the time the entry was made. I tried using the plain ol' NSDate(), but then the filtering didn't work because filtering by just today's date didn't yield results because the times those entries were made will always be less than the current time.

You need to use Calendar to break a date apart, using CalendarUnit to specify what components you want.
let calendar = Calendar.current
let components = calendar.dateComponents([.month, .day, .year, .hour, .minute], from: Date())
print("Hour: \(components.hour)")
print("Minute: \(components.minute)")
print("Day: \(components.day)")
print("Month: \(components.month)")
print("Year: \(components.year)")

Swift 5 Xcode 14.2
let myDate = .... // you date here
let cal = Calendar.current
let required : Set<Calendar.Component> = [.year, .month, .day, .hour, .minute, .second]
let components : DateComponents = cal.dateComponents(required, from: myDate)
print("Hour: \(components.hour)")
print("Minute: \(components.minute)")
print("Day: \(components.day)")
print("Month: \(components.month)")
print("Year: \(components.year)")

Related

DateComponents giving wrong hour

I am trying to implement a simple countdown timer in my test app.
I have two dates:
fromDate - which is current time that I get by Date(), e.g. 2021-08-27 11:07:34 +0000
toDate - is a future date, e.g. 2021-11-17 01:00:00 +0000
I am using DateComponents to get back the difference in days, hours, minutes and seconds.
let components = Calendar.current.dateComponents([.day, .hour, .minute, .second],
from: fromDate,
to: toDate)
Its returning me back the values for days hours minute and second 81, 12, 52, 25
The values for day, minute and second are correct, but the hour is 1 hour less.
I suspect daylight timing has to do something with this but I cannot find anything that can help here.
Kindly help me what I am doing wrong as I have tried many things in past few days but nothing seems to work
I was able to reproduce the behaviour by using:
let from = Date(timeIntervalSince1970: 1630062455)
print(from) // 2021-08-27 11:07:35 +0000
let to = Date(timeIntervalSince1970: 1637110800)
print(to) // 2021-11-17 01:00:00 +0000
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "Europe/London")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)
print(comp.day!, comp.hour!, comp.minute!, comp.second!)
The reason why this happens is because when doing dateComponents(_:from:to:), Calendar takes into account its timezone. After all, without a timezone, (almost) no date components would make sense - you would not be able to tell what hour a Date is, for example. A Date just represents an instant in time/n seconds since the epoch.
(In the case of Calendar.current, the timezone it uses is TimeZone.current)
Europe/London would go out of DST at some point between from and to. This means the calendar would calculate the difference in date components between:
from: 2021-08-27 12:07:35
to: 2021-11-17 01:00:00
Notice that the first time is 12:07:35, rather than 11:07:35. This is because at 2021-08-27 11:07:35 +0000, the local date time at Europe/London really is 2021-08-27 12:07:35.
To get your desired output, just change the calendar's timeZone to UTC:
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "UTC")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)

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

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.

Swift date manipulation - strange month return

I'm trying to do some date manipulation with Swift and I'm getting an unexpected result. The webservice will pass in a string date, and then I want to get that month and the previous month. I'm using this code (with input grab and such removed):
import Foundation
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "America/New_York")
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: "2018-12-01")!
let prev = Calendar.current.date(byAdding: .month, value: -1, to: date)!
formatter.string(from: date)
formatter.string(from: prev)
So I've got a valid date, and then I subtract a month from it. The first formatted date shows my expected 2018-12-01 but then on the second line, instead of saying 2018-11-01 it says 2018-10-31.
I'm in PST, which is of course 3 hours ahead of EST. If I add 3 hours I'd get the expected strings. However, since both the input and the output strings were done with a formatter using the timezone, why don't I get the expected output?
The problem is that Calendar.current is in a different timezone (for you) than the formatter.
So date is December 1, 2018 at midnight New York time. But that is November 30, 2018 at 9pm local time (PST) for you.
When you subtract one month it is done in local time (Calendar.current) so you get October 30, 2018 at 9pm. Then you format that date to New York time and it results in October 31, 2018 at midnight.
To get the proper results you want a Calendar in the same timezone as the formatter:
var cal = Calendar(identifier: Calendar.current.identifier)
cal.timeZone = formatter.timeZone
let prev = cal.date(byAdding: .month, value: -1, to: date)!
This will give the expected result.

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