Setting seconds to 0 is also adding 1 to minutes in Swift

113 Views Asked by At

I'm trying to set the seconds of a date object to 0 with the following:

if let date = value{
   var calendar = Calendar.current
    if let mdate = calendar.date(bySetting: .second, value: 0, of: date) {
        ...
}
}

However, this isn't just setting the seconds to 0, it's also adding 1 to the minutes, and I cannot understand why.

As you can see in this screenshot - I have a date object with a time value of "15:00:10", but this becomes "15:01:00" when I set the seconds to 0.

This does not seem intuitive. Do I need to subtract a minute each time? Can I be sure that this behavior is consistent?

enter image description here

3

There are 3 best solutions below

0
Duncan C On BEST ANSWER

That is odd, and I'm not quite sure why it increments the minute.

You can get the result you are after by fetching the year/month/day/hour/minute component values from your date and then using those to create another date:

let value: Date? = Date()
if let date = value{
    var calendar = Calendar.current
    print(date.description(with: .current))
    
    let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
    
    if let mdate = calendar.date(from: components) {
        print(mdate.description(with: .current))
    }
}
4
Rob On

The misleadingly named date(bySetting:value:of:) is, effectively, a simplified rendition of nextDate(after:matching:matchingPolicy:behavior:direction:). As the docs say, if you need more control, you should use the latter.

E.g., go .backward.

if let mdate = calendar.nextDate(after: date, matching: DateComponents(second: 0), matchingPolicy: .nextTime, direction: .backward) {
    …
}

But as has been noted below, if seconds is already zero, this will get the prior date (!) with zero seconds.


Better might be to extract the components (sans seconds) and then build a date from that:

let components = calendar.dateComponents([.era, .year, .month, .day, .hour, .minute], from: date)
if let mdate = calendar.date(from: components) {
    …
}
0
Joakim Danielson On

An alternative solution if, and I assume this based on the image, the end goal is to generate a formatted string of the time with seconds set to zero then it can be directly solved with the date formatter by replacing ss in the format with 00.

let dateformatter = DateFormatter()
dateformatter.dateFormat = "HH:mm:00"