2012-06-30 17 views
9

Próbuję użyć NSDateFormatter w mojej aplikacji, która pobiera ciąg daty i formatuje go do NSDate, dzięki czemu mogę wykonywać porównania dat, jednak znajduję, gdy używam dateFromString i formatuję datę tracąc jeden dzień.NSDateFormatter dateFromString zwraca niepoprawną datę

NSString *dateString = @"02-06-2012"; 
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
[dateFormatter setDateFormat:@"dd-MM-yyyy"]; 
NSDate *dateFromString = [[NSDate alloc] init]; 
dateFromString = [dateFormatter dateFromString:dateString]; 
NSLog(@"My Date = %@", dateFromString); 
[dateFormatter release]; 

Ten wysyła do konsoli:

My Date = 2012-06-01 23:00:00 +0000

Odpowiedz

19

I nie wierz, że odpowiedź Dhruva jest prawidłowa. W rzeczywistości nie jest jasne, czy jest jakiś problem. Wydaje się, że masz niewłaściwe oczekiwanie na to, co powinno się wydarzyć i/lub interpretacja tego, co się dzieje.

NSDate reprezentuje moment w czasie. Ta chwila nie ma jednoznacznej nazwy. Będzie znany pod różnymi nazwami w różnych miejscach i pod różnymi systemami nazewnictwa (strefy czasowe, kalendarze). NSDate nie zajmuje się tym, z wyjątkiem lamely w jego metodzie -description, gdzie musi utworzyć reprezentację łańcuchową tego momentu.

Po drugie, ciąg znaków taki jak "02-06-2012" nie określa dokładnego momentu w czasie. Przede wszystkim jest to tylko data bez informacji o czasie, więc domyślnie jest to pierwszy moment dla tej daty. Po drugie, nie określa strefy czasowej. Pierwsza chwila dnia kalendarzowego to inny moment w każdej strefie czasowej. Jeśli nie określisz strefy czasowej z -setTimeZone: lub sam ciąg niesie informację o strefie czasowej, NSDateFormatter zakłada, że ​​wszystkie ciągi dat, które poprosisz o ich zanalizowanie, znajdują się w bieżącej strefie czasowej.

Twój obiekt dateFromString reprezentuje pierwszą chwilę określonej daty, 02-06-2012, w Twojej strefie czasowej. Spodziewam się, że tego właśnie chcesz. Jednakże, jesteś zdezorientowany przez sposób, w jaki NSDate opisuje się po zalogowaniu. Jak już powiedziałem, NSDate musi wybrać "nazwę" (reprezentację ciągów znaków) na chwilę, którą reprezentuje i jaką nazwę wybiera, jest dość arbitralne. W dzisiejszych czasach wybiera nazwę, o której jest znana godzina w UTC. Z danych wyjściowych dziennika pokazanych w Twoim pytaniu wynika, że ​​znajdujesz się w UTC + 0100. Tak więc data może wyglądać tak, jakby to było dzień wcześniej, ale tak naprawdę jest w tym samym momencie, który podałeś. Innymi słowy, "2012-06-01 23:00:00 +0000" i "2012-06-02 00:00:00 +0100" to dwie równoważne nazwy dokładnie w tym samym momencie. Po prostu nie jesteś przyzwyczajony do tego pierwszego i źle go zinterpretowałeś.

Lekcja polega na tym, że musisz przestać polegać na własnym samopisaniu z, aby znaleźć się w jakiejkolwiek określonej strefie czasowej. Naprawdę, nie musisz polegać na niczym, ponieważ nie jest to udokumentowane. W rzeczywistości dokumentacja dla stanu -[NSDate description] stwierdza: "Reprezentacja nie ma zagwarantowanej stałej wartości w różnych wersjach systemu operacyjnego."

rozwiązanie Dhruv za wydaje pomóc tylko dlatego powoduje to NSDateFormatter i -[NSDate description] uzgodnić strefy czasowej. Ale to niewiarygodne. Na przykład Snow Leopard nie zadziałałby, ponieważ -[NSDate description] używał lokalnej strefy czasowej zamiast UTC w tej wersji frameworków.

Co ważniejsze, zmienia to rzeczywisty moment reprezentowany przez obiekt NSDate, który otrzymujesz z interpretacji twojego ciągu dat z NSDateFormatter. Podejrzewam, że naprawdę chcesz, aby miało to określone znaczenie - chcesz, aby ciąg znaków był interpretowany jako znajdujący się w lokalnej strefie czasowej - a jego rozwiązanie zniechęca twoją intencję.

tl; dr: otrzymywałeś datę, której chciałaś przez cały czas; nie polegaj na -[NSDate description]; nie używaj rozwiązania Dhruva

+0

Cześć Ken, Dzięki za szczegółową odpowiedź, co poleciłbym zrobić lub użyć? W mojej aplikacji muszę sprawdzić jest równy lub większy niż konkretna data zakodowana na sztywno, którą muszę umieścić w mojej aplikacji. Dzięki – MonkeyBlue

+1

Musisz zdecydować, o której naprawdę myślisz. Czy zakodowana data powinna być interpretowana jako konkretna, stała strefa czasowa (jak w domowym biurze twojej firmy)? Czy ma być interpretowany jako znajdujący się w strefie czasowej użytkownika? W pierwszym przypadku należy ustawić stałą strefę czasową w edytorze daty. Jeśli to drugie, możesz zostawić go jako domyślny lub możesz jawnie ustawić go na "[NSTimeZone defaultTimeZone]' (lub '+ systemTimeZone'). –

+0

Dzięki Ken Podam, że to się udaje - ustalony czas jest w zasadzie konkretną datą, więc jeśli otworzysz aplikację i oprzesz ją w dowolnym miejscu na świecie, powinna użyć konkretnej daty i sprawdzić, czy dzisiaj jest większa czy równa, robimy to ponieważ musimy wyświetlać różne informacje w naszej aplikacji od określonej daty. Twoje wyjaśnienie ma również większy sens, więc zaznaczę twoją odpowiedź. Dzięki – MonkeyBlue

49

Spróbuj dodać ten linie w kodzie,

[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+0:00"]]; 

lub

[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; 

SWIFT zmiana:

Kod z quetion,

let dateString = "02-06-2012" 
var dateFormatter = NSDateFormatter() 
dateFormatter.dateFormat = "dd-MM-yyyy" 
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)! 
println("My Date \(dateFromString)") 

i rozwiązanie,

dateFormatter.timeZone = NSTimeZone(name: "GMT") 

LUB

dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00") 
+0

Dzięki, że to jest doskonałe. – MonkeyBlue

+0

Czy nie byłoby to rozwiązanie ogólne? Co się stanie, jeśli urządzenie nie jest w GMT? – Stavash

+4

@stavash Taki jest sens, GMT jest taki sam jak UTC lub Universal Time. Jest to jedna standardowa strefa czasowa, z której każdy może korzystać i nigdy się nie zmienia (ze względu na czas letni itp.). W ten sposób iOS przechowuje daty/czasy .... – lnafziger

Powiązane problemy