Jak wygenerować znacznik daty i godziny przy użyciu standardów formatu ISO 8601 i RFC 3339 ?
Celem jest ciąg znaków, który wygląda następująco:
"2015-01-01T00:00:00.000Z"
Format:
- rok, miesiąc, dzień jako „XXXX-XX-XX”
- litera „T” jako separator
- godzina, minuta, sekundy, milisekundy, jako „XX: XX: XX.XXX”.
- litera „Z” jako oznaczenie strefy dla zerowego przesunięcia, czyli UTC, GMT, czas Zulu.
Najlepszy przypadek:
- Szybki kod źródłowy, który jest prosty, krótki i bezpośredni.
- Nie trzeba używać żadnych dodatkowych ram, podprojektu, cocoapod, kodu C itp.
Przeszukałem StackOverflow, Google, Apple itp. I nie znalazłem szybkiej odpowiedzi na to pytanie.
Klasy, które wydają się najbardziej obiecujące są NSDate
, NSDateFormatter
,NSTimeZone
.
Powiązane pytania i odpowiedzi: Jak uzyskać datę ISO 8601 w systemie iOS?
Oto najlepsze, jakie do tej pory wymyśliłem:
var now = NSDate()
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
println(formatter.stringFromDate(now))
Odpowiedzi:
Swift 4 • iOS 11.2.1 lub nowszy
Stosowanie:
iOS 9 • Swift 3 lub nowszy
i strategia kodowania
Testowanie placu zabaw
kodowanie
rozszyfrowanie
źródło
extension String { var dateFormattedISO8601: NSDate? {return NSDate.Date.formatterISO8601.dateFromString(self)} }
let now = NSDate() let stringFromDate = now.iso8601 let dateFromString = stringFromDate.dateFromISO8601! XCTAssertEqual(now.timeIntervalSince1970, dateFromString.timeIntervalSince1970)
ISO8601DateFormatter
upraszcza ten proces. Wysłałem raport o błędzie (27242248) do Apple, prosząc ich o rozwinięcie tego nowego formatyzatora, aby oferował także możliwość określania milisekund (ponieważ ten nowy formatyzator nie jest użyteczny dla wielu z nas bez milisekund).T
np .:2016-09-21 21:05:10+00:00
?Pamiętaj, aby ustawić ustawienia regionalne
en_US_POSIX
zgodnie z opisem w Technicznych pytaniach i pytaniach A1480 . W Swift 3:Problem polega na tym, że jeśli korzystasz z urządzenia, które korzysta z kalendarza innego niż gregoriański, rok nie będzie zgodny z RFC3339 / ISO8601, chyba że określisz
locale
zarówno, jaktimeZone
idateFormat
ciąg, ciąg.Lub możesz użyć,
ISO8601DateFormatter
aby wydostać się z chwastów otoczenialocale
itimeZone
siebie:Wersja Swift 2 znajduje się w poprzedniej wersji tej odpowiedzi .
źródło
en_US_POSIX
. To lingua franca do wymiany dat w Internecie. I nie możesz mieć błędnej interpretacji dat, jeśli jeden kalendarz był używany na urządzeniu podczas zapisywania ciągu daty, a drugi, gdy ciąg jest odczytywany później. Potrzebujesz także formatu, który gwarantuje, że nigdy się nie zmieni (dlatego używasz go,en_US_POSIX
a nieen_US
). Aby uzyskać więcej informacji, zobacz Pytania techniczne 1480 lub te normy RFC / ISO.Jeśli chcesz użyć
ISO8601DateFormatter()
z datą z kanału JSON w Railsach 4+ (i oczywiście nie potrzebujesz millis), musisz ustawić kilka opcji na formatorze, aby działało poprawnie, w przeciwnym raziedate(from: string)
funkcja zwróci zero. Oto, czego używam:Oto wynik użycia wierszy opcji, których nie ma na zrzucie ekranu placu zabaw:
źródło
.withFractionalSeconds
ale już to wypróbowałem i wciąż pojawia się błądlibc++abi.dylib: terminating with uncaught exception of type NSException
..deferredToDate
gdy używasz protokołu CodableSzybki 5
Jeśli celujesz w iOS 11.0+ / macOS 10.13+, po prostu korzystaj
ISO8601DateFormatter
z opcjiwithInternetDateTime
iwithFractionalSeconds
, takich jak:źródło
Aby dodatkowo pochwalić Andrésa Torresa Marroquína i Leo Dabusa, mam wersję, która zachowuje ułamkowe sekundy. Nie mogę go nigdzie udokumentować, ale Apple skraca ułamkowe sekundy do mikrosekundy (3 cyfry precyzji) zarówno na wejściu, jak i na wyjściu (nawet jeśli określono to za pomocą SSSSSSS, w przeciwieństwie do Unicode tr35-31 ).
Powinienem podkreślić, że prawdopodobnie nie jest to konieczne w większości przypadków użycia . Daty online zazwyczaj nie wymagają milisekundowej precyzji, a kiedy to robią, często lepiej jest użyć innego formatu danych. Ale czasami trzeba w określony sposób współpracować z istniejącym systemem.
Xcode 8/9 i Swift 3.0-3.2
źródło
Używa
ISO8601DateFormatter
na iOS10 lub nowszym.Używa
DateFormatter
na iOS9 lub starszym.Szybki 4
źródło
W moim przypadku muszę przekonwertować kolumnę DynamoDB - lastUpdated (Unix Timestamp) na czas normalny.
Początkowa wartość lastUpdated wyniosła: 1460650607601 - skonwertowana do 14.04.2016 16:16:47 +0000 poprzez:
źródło
W przyszłości może być konieczna zmiana formatu, co może być niewielkim bólem głowy po wywołaniach date.dateFromISO8601 wszędzie w aplikacji. Użyj klasy i protokołu, aby owinąć implementację, zmiana wywołania formatu daty i godziny w jednym miejscu będzie prostsza. Jeśli to możliwe, użyj RFC3339, jest to pełniejsza reprezentacja. DateFormatProtocol i DateFormat doskonale nadają się do wstrzykiwania zależności.
źródło
Istnieje nowa
ISO8601DateFormatter
klasa, która pozwala ci utworzyć ciąg z tylko jedną linią. Dla kompatybilności wstecznej użyłem starej biblioteki C. Mam nadzieję, że jest to przydatne dla kogoś.Swift 3.0
źródło
Aby uzupełnić wersję Leo Dabusa, dodałem wsparcie dla projektów napisanych Swift i Objective-C, a także dodałem wsparcie dla opcjonalnych milisekund, prawdopodobnie nie jest najlepsze, ale dostaniesz sens:
Xcode 8 i Swift 3
źródło
Bez niektórych ręcznych masek ciągów lub formantów czasu
źródło
.iso8601
nie obejmie milisekund.Na podstawie dopuszczalnej odpowiedzi w paradygmacie obiektu
strona wywoławcza
źródło