2009-10-06 16 views

Odpowiedz

12

NSDate jest niezmienny, więc nie można zmienić jego czasu. Ale można utworzyć nowy obiekt Date, który jest przyciągany do najbliższej minuty:

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

Edycja, aby odpowiedzieć na komentarz Uli za

Datą odniesienia dla NSDate jest 1 stycznia, 2001, 00:00 GMT. Od tego czasu dodano dwie sekundy przestępczości: 2005 i 2010, więc wartość zwrócona przez [NSDate timeIntervalSinceReferenceDate] powinna być wyłączona o dwie sekundy.

Nie dotyczy: timeIntervalSinceReferenceDate jest dokładnie synchroniczna z czasem ściany.

Podczas odpowiadania na pytanie nie upewniłem się, że jest to prawda. Właśnie założyłem, że Mac OS będzie miał behave as UNIX time (1970 rok): POSIX gwarantuje, że każdy dzień zaczyna się od wielokrotności 86 400 sekund.

Patrząc na wartości zwrócone z NSDate to założenie wydaje się prawidłowe, ale na pewno dobrze byłoby znaleźć określone (udokumentowane) oświadczenie o tym.

+4

To nie zadziała. Przedział czasu od daty odniesienia nie może być równy wielokrotności 60 dla czasu, który ma 00 sekund. Jest to liczba sekund od daty odniesienia i jako takie, sekundy przestępne, które czasami są wstawiane, wyrzucą cię. Myślę, że będziesz musiał użyć NSCalendar, aby dowiedzieć się, jakie sekundy ma data, a następnie odejmij * to * od przedziału czasu. – uliwitness

+1

Czas, jaki otrzymasz, może wynosić jedną minutę w przyszłości, jeśli aktualna minuta minie 30 sekund. Dzieje się tak, ponieważ runda może zaokrąglić. Spróbuj z 'podłogą ([date timeIntervalSinceReferenceDate]/60.0) * 60.0;' –

+1

@flovonderuni Dobry połów. Wyniki z przełącznika 'podłogowego' w tym samym czasie robią zegary ścienne. Edytowana odpowiedź, dzięki! –

1

rejestruje pojedynczy moment w czasie. Jeśli chcesz zachować określony dzień, nie używaj NSDate. Otrzymasz wiele nieoczekiwanych bólów głowy związanych ze strefami czasowymi, czas letni e.tc.

Jednym z alternatywnych rozwiązań jest przechowywanie dnia jako liczby całkowitej w formacie standardowym quasi-ISO, na przykład 20110915 z 15 września 2011 r. Gwarantuje to sortowanie w ten sam sposób, w jaki sortuje się NSDate.

10

Nie można bezpośrednio manipulować NSTimeInterval, ponieważ jest to odległość w sekundach od daty odniesienia, co nie jest gwarantowane jako 00-sekundowy czas podzielony przez 60. W końcu mogły być sekundy przestępne włożona, aby skorygować różnice między czasem słonecznym a czasem UTC. Każdy drugi skok byłoby wyrzucić cię o 1. Co zrobić, aby naprawić sekund moim dniu 0 wynosi:

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

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

ta zajmuje sekundy przestępne. Chyba jeszcze bardziej przejrzysty sposób byłoby użyć -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]; 

Dzięki temu masz gwarancję, że bez względu na specjalny rzeczy -dateByAddingComponents: dba o rozlicza również.

+1

Wierzę, że twoje roszczenie dotyczące sekund przestępnych wpływające na 'timeIntervalSinceReferenceDate' nie jest prawdziwe. Podczas gdy Przewodnik programowania daty i czasu firmy Apple nie definiuje jawnie zachowania, POSIX robi to dla czasu UNIX: sekundy przestępne są ignorowane (patrz http://pl.wikipedia.org/wiki/Unix_time). Wygląda na to, że odnosi się to również do kakao. –

+1

Inna myśl: oba proponowane rozwiązania nie uwzględniają ułamków sekundy. Oblicza się liczbę (całkowitą) sekund i odejmuje je od daty pierwotnej. Wynik odnosi się do czasu z zerową sekundą, ale niezerową milisekundą, co jest nieco dziwne. –

2

Mimo że jest to stare pytanie, a Uli podał "poprawną" odpowiedź, najprostszym rozwiązaniem jest odjęcie sekund od daty, tak jak otrzymano z kalendarza. Pamiętaj, że może to pozostawiać milisekundy na miejscu.

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

Tutaj jest przedłużeniem to zrobić w Swift:

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

Oto Swift rozszerzenie dla każdego, kto jest zainteresowany:

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 
    } 
} 

Przykład użycia:

let date = Date() 
date.floorSeconds() 

Korzystanie z DateComponents jest znacznie solidniejsze niż dodanie przedziału czasowego do daty.

Powiązane problemy