Как установить секунды на ноль для NSDate - PullRequest
15 голосов
/ 06 октября 2009

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

Ответы [ 6 ]

14 голосов
/ 06 октября 2009

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

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

Изменить, чтобы ответить на комментарий Ули

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

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

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

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

11 голосов
/ 27 января 2012

Вы не можете напрямую манипулировать 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: заботятся.

2 голосов
/ 26 января 2018

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

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 гораздо надежнее, чем добавление временного интервала к дате.

2 голосов
/ 06 августа 2014

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

NSDate *date = [NSDate date];
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSCalendarUnitSecond
                                                         fromDate:date];
date = [date dateByAddingTimeInterval:-comp.second];
1 голос
/ 21 июля 2016

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

extension NSDate {
    func truncateSeconds() -> NSDate {
        let roundedTime = floor(self.timeIntervalSinceReferenceDate / 60) * 60
        return NSDate(timeIntervalSinceReferenceDate: roundedTime)
    }
}
1 голос
/ 27 января 2012

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

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

...