I'm trying to get NSDate from UIDatePicker, but it constantly returns me a date time with trailing 20 seconds. How can I manually set NSDate's second to zero in swift?
- 181
 - 1
 - 1
 - 6
 
- 
                    I need this in swift – aftab ahmed Apr 22 '15 at 06:15
 - 
                    http://stackoverflow.com/questions/1525825/how-to-set-seconds-to-zero-for-nsdate You can use same way in swift – Elliot Li Apr 22 '15 at 06:20
 
7 Answers
extension Date {
    var zeroSeconds: Date? {
        let calendar = Calendar.current
        let dateComponents = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: self)
        return calendar.date(from: dateComponents)
    }
}
Usage:
let date1 = Date().zeroSeconds
let date2 = Date()
print(date2.zeroSeconds)
- 154
 - 9
 
- 16,359
 - 15
 - 81
 - 92
 
Truncating a date to a full minute can be done with
let date = NSDate()
let cal = NSCalendar.currentCalendar()
var fullMinute : NSDate?
cal.rangeOfUnit(.CalendarUnitMinute, startDate: &fullMinute, interval: nil, forDate: date)
println(fullMinute!)
Update for Swift 4 and later:
let date = Date()
let cal = Calendar.current
if let fullMinute = cal.dateInterval(of: .minute, for: date)?.start {
    print(fullMinute)
}
This method can easily be adapted to truncate to a full hour, day, month, ...
- 529,903
 - 94
 - 1,240
 - 1,382
 
- 
                    1This strikes me as the best way to do this. Any date calculation that includes "`60`" in it makes me shiver! Don't get me started on "`60 * 60`" or even "`60 * 60 * 24`"!! – Ashley Mills Apr 22 '15 at 10:00
 - 
                    What if the `Date` to-be-truncated has the exact same value, won't it always "skip" to the next/previous `Date`? – Guilherme Matuella Feb 13 '20 at 13:03
 - 
                    @GuilhermeMatuella: You are right, if the date is already on an full minute then it would yield the previous minute. I have removed that part, thank you for the feedback. – Martin R Feb 14 '20 at 09:49
 
This is how to do it in Swift 3.
In this example I remove the seconds in the date components:
let date = picker.date
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
let fullMinuteDate = calendar.date(from: components)!
- 1,623
 - 17
 - 16
 
Just reformat the date:
func stripSecondsFromDate(date: NSDate) -> NSDate {
  let dateFormatter = NSDateFormatter()
  dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
  let str = dateFormatter.stringFromDate(date)
  let newDate = dateFormatter.dateFromString(str)!
  return newDate
}
- 3,834
 - 4
 - 40
 - 45
 
import Foundation
let now = Date()
let calendar = Calendar.current
let date = calendar.date(bySettingHour: 0,
                         minute: 0,
                         second: 0,
                         of: now,
                         direction: .backward)
There is another way, with two more parameters: matchingpolicy and repeatedTimePolicy.
let date = calendar.date(bySettingHour: 0,
                         minute: 0,
                         second: 0,
                         of: now,
                         matchingPolicy: .strict,
                         repeatedTimePolicy: .first,
                         direction: .backward)
To check the result:
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone.current // defaults to GMT
let string = formatter.string(from: date!)
print(string) // 2019-03-27T00:00:00+01:00
- 62,815
 - 21
 - 164
 - 192
 
I know this doesn't address NSDate directly, but it might be worth anyways - I had this exact same problem with Date and also because I think this might be a more clean approach.
extension Calendar {
    /// Removes seconds `Calendar.Component` from a `Date`. If `removingFractional` is `true`, it also
    /// removes all fractional seconds from this particular `Date`.
    ///
    /// `removingFractional` defaults to `true`.
    func removingSeconds(fromDate date: Date, removingFractional removesFractional: Bool = true) -> Date? {
        let seconds = component(.second, from: date)
        let noSecondsDate = self.date(byAdding: .second, value: -seconds, to: date)
        if removesFractional, let noSecondsDate = noSecondsDate {
            let nanoseconds = component(.nanosecond, from: noSecondsDate)
            return self.date(byAdding: .nanosecond, value: -nanoseconds, to: noSecondsDate)
        }
        return noSecondsDate
    }
}
Now, to solve your problem, we created the function removingSeconds(fromDate: removingFractional). It's really simple - as you can see in the docs of the function. It removes the .second component and, if removingFractional is true, it also removes any fractional seconds that this Date may have - or the .nanosecond component.
- 2,193
 - 1
 - 17
 - 32
 
- 
                    Note that this does not remove *fractional seconds,* so that the result is not necessarily on a full minute. – Martin R Feb 14 '20 at 09:52
 - 
                    @MartinR I've updated the solution to handle such scenarios where fractional seconds may be necessary to take into consideration. Do you think this is a decent approach now? – Guilherme Matuella Feb 21 '20 at 13:27
 - 
                    1Well, you have a method to remove seconds (including fractional seconds) now. But what is the purpose of removing other units? Note that `cal.removing(component: .day, fromDate: d)` gives you a *the last day of the previous month* because days start counting at 1. As an example, "2020-02-21 12:34" would become "2020-01-31 12:34". I am not sure if that is useful, to be honest. – Martin R Feb 22 '20 at 10:03
 - 
                    You're totally correct. I've removed the abstraction that would probably cause confusion if used in any `Calendar.Component` that is "greater" than `.second` - or anything that does not relate to Time directly. Thanks, I've once again improved the answer to be more straightforward. – Guilherme Matuella Feb 22 '20 at 13:27
 
