Как установить секунды до нуля для NSDate

Я пытаюсь получить NSDate от UIDatePicker, но он постоянно возвращает мне время с завершением 20 секунд. Как я могу вручную установить NSDate second на ноль?

Ответы

Ответ 1

NSDate неизменен, поэтому вы не можете изменить свое время. Но вы можете создать новый объект даты, который привязывается к ближайшей минуте:

NSTimeInterval time = floor([date timeIntervalSinceReferenceDate] / 60.0) * 60.0;
NSDate *minute = [NSDate dateWithTimeIntervalSinceReferenceDate:time];

Редактировать, чтобы ответить на комментарий Uli

Референтная дата для NSDate - 1 января 2001 года, 0:00 GMT. С тех пор было добавлено две секунды прыжка: 2005 и 2010, поэтому значение, возвращаемое [NSDate timeIntervalSinceReferenceDate], должно быть отключено на две секунды.

Это не тот случай: timeIntervalSinceReferenceDate точно синхронно времени стены.

Отвечая на вопрос, я не удостоверился, что это действительно так. Я просто предположил, что Mac OS ведет себя как время UNIX (1970-е годы): POSIX гарантирует, что каждый день начинается с кратного 86 400 секунд.

Глядя на значения, возвращаемые из NSDate, это предположение кажется правильным, но было бы неплохо найти определенную (документированную) формулировку этого.

Ответ 2

Вы не можете напрямую манипулировать NSTimeInterval, так как это расстояние в секундах от контрольной даты, что не гарантируется на 00-секундное время при делении на 60. В конце концов, возможно, были вставлены секунды прыжка для корректировки различий между солнечным временем и UTC. Каждый прыжок второй выкинул бы вас на 1. Что я делаю, чтобы исправить секунды моей даты до 0:

NSDate              *   startDateTime = [NSDate date];
NSDateComponents    *   startSeconds = [[NSCalendar currentCalendar] components: NSSecondCalendarUnit fromDate: startDateTime];

startDateTime = [NSDate dateWithTimeIntervalSinceReferenceDate: [startDateTime timeIntervalSinceReferenceDate] -[startSeconds second]];

Это займет секунды прыжка. Я думаю, что еще более чистым способом было бы использовать -dateByAddingComponents:

NSDate              *   startDateTime = [NSDate date];
NSDateComponents    *   startSeconds = [[NSCalendar currentCalendar] components: NSSecondCalendarUnit fromDate: startDateTime];
[startSeconds setSecond: -[startSeconds second]];

startDateTime = [[NSCalendar currentCalendar] dateByAddingComponents: startSeconds toDate: startDateTime options: 0];

Таким образом, вам гарантируется, что любые специальные вещи -dateByAddingComponents: позаботится об этом также учтены.

Ответ 3

Хотя это старый вопрос, и Ули дал "правильный" ответ, самым простым решением IMHO является просто вычесть секунды с даты, полученные из календаря. Имейте в виду, что это все равно может оставить миллисекунды на месте.

NSDate *date = [NSDate date];
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitSecond
                                                         fromDate:date];
date = [date dateByAddingTimeInterval:-comp.second];

Ответ 4

NSDate записывает один момент времени. Если вы хотите сохранить определенный день, не используйте NSDate. Вы получите много неожиданных головных болей, связанных с часовыми поясами, летнее время e.tc.

Одним из альтернативных решений является сохранение дня в виде целого числа в стандартном формате квази-ISO, например, 20110915 для 15 сентября 2011 года. Это гарантированно будет сортироваться так же, как сортировка NSDate.

Ответ 5

Вот расширение для этого в Swift:

extension NSDate {
    func truncateSeconds() -> NSDate {
        let roundedTime = floor(self.timeIntervalSinceReferenceDate / 60) * 60
        return NSDate(timeIntervalSinceReferenceDate: roundedTime)
    }
}

Ответ 6

Вот расширение для всех, кто заинтересован:

extension Date {
    public mutating func floorSeconds() {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: self)
        self = calendar.date(from: components) ?? self // you can handle nil however you choose, probably safe to force unwrap in most cases anyway
    }
}

Пример использования:

let date = Date()
date.floorSeconds()

Использование DateComponents гораздо более надежное, чем добавление временного интервала к дате.