Bagaimana cara menghasilkan cap waktu tanggal, menggunakan standar format untuk ISO 8601 dan RFC 3339 ?
Tujuannya adalah string yang terlihat seperti ini:
"2015-01-01T00:00:00.000Z"
Format:
- tahun, bulan, hari, sebagai "XXXX-XX-XX"
- huruf "T" sebagai pemisah
- jam, menit, detik, milidetik, sebagai "XX: XX: XX.XXX".
- huruf "Z" sebagai penunjuk zona untuk zero offset, alias UTC, GMT, waktu Zulu.
Kasus terbaik:
- Kode sumber cepat yang sederhana, pendek, dan mudah.
- Tidak perlu menggunakan kerangka kerja tambahan, sub proyek, cocoapod, kode C, dll.
Saya telah mencari StackOverflow, Google, Apple, dll. Dan belum menemukan jawaban Swift untuk ini.
Kelas-kelas yang tampaknya paling menjanjikan adalah NSDate
, NSDateFormatter
, NSTimeZone
.
T&J terkait: Bagaimana cara mendapatkan tanggal ISO 8601 di iOS?
Inilah yang terbaik yang saya hasilkan sejauh ini:
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))
Jawaban:
Swift 4 • iOS 11.2.1 atau lebih baru
Pemakaian:
iOS 9 • Swift 3 atau lebih baru
dan strategi pengkodean
Pengujian Playground
encoding
decoding
sumber
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
menyederhanakan prosesnya. Saya telah mengeluarkan laporan bug (27242248) kepada Apple, meminta mereka untuk memperluas formatter baru ini untuk menawarkan kemampuan untuk menentukan milidetik juga (karena formatter baru ini tidak berguna bagi banyak dari kita tanpa milidetik).T
misalnya:2016-09-21 21:05:10+00:00
?Ingatlah untuk mengatur lokal ke
en_US_POSIX
seperti yang dijelaskan dalam Tanya Jawab Teknis . Dalam Swift 3:Masalahnya adalah bahwa jika Anda menggunakan perangkat yang menggunakan kalender non-Gregorian, tahun tersebut tidak akan sesuai dengan RFC3339 / ISO8601 kecuali Anda menentukan
locale
serta dantimeZone
dandateFormat
string.Atau Anda dapat menggunakan
ISO8601DateFormatter
untuk mengeluarkan Anda dari gulma pengaturanlocale
dantimeZone
diri Anda sendiri:Untuk rendisi Swift 2, lihat revisi sebelumnya dari jawaban ini .
sumber
en_US_POSIX
. Ini adalah lingua franca untuk bertukar tanggal di web. Dan Anda tidak bisa salah mengartikan tanggal jika satu kalender digunakan pada perangkat saat menyimpan string tanggal dan lainnya ketika string dibaca kembali nanti. Juga, Anda memerlukan format yang dijamin tidak akan pernah berubah (itulah sebabnya Anda menggunakanen_US_POSIX
dan tidaken_US
). Lihat Tanya Jawab Teknis 1480 atau standar RFC / ISO tersebut untuk informasi lebih lanjut.Jika Anda ingin menggunakan
ISO8601DateFormatter()
dengan tanggal dari Rails 4+ JSON feed (dan tentu saja tidak perlu milis), Anda perlu mengatur beberapa opsi pada formatter agar berfungsi dengan benar jikadate(from: string)
fungsi tidak akan mengembalikan nol. Inilah yang saya gunakan:Inilah hasil dari penggunaan ayat-ayat pilihan bukan di tangkapan layar taman bermain:
sumber
.withFractionalSeconds
tetapi saya sudah mencobanya dan itu terus melontarkan kesalahanlibc++abi.dylib: terminating with uncaught exception of type NSException
..deferredToDate
saat menggunakan protokol CodableCepat 5
Jika Anda menargetkan iOS 11.0+ / macOS 10.13+, Anda cukup menggunakan
ISO8601DateFormatter
denganwithInternetDateTime
danwithFractionalSeconds
opsi, seperti:sumber
Penggunaan
ISO8601DateFormatter
pada iOS10 atau yang lebih baru.Penggunaan
DateFormatter
pada iOS9 atau lebih.Cepat 4
sumber
Untuk lebih lanjut memuji Andrés Torres Marroquín dan Leo Dabus, saya memiliki versi yang mempertahankan pecahan detik. Saya tidak dapat menemukannya didokumentasikan di mana pun, tetapi Apple memotong fraksional detik ke mikrodetik (presisi 3 digit) pada input dan output (meskipun ditentukan menggunakan SSSSSSS, bertentangan dengan Unicode tr35-31 ).
Saya harus menekankan bahwa ini mungkin tidak perlu untuk kebanyakan kasus penggunaan . Tanggal online biasanya tidak memerlukan ketepatan milidetik, dan ketika mereka melakukannya, seringkali lebih baik menggunakan format data yang berbeda. Tetapi kadang-kadang seseorang harus beroperasi dengan sistem yang sudah ada sebelumnya dengan cara tertentu.
Xcode 8/9 dan Swift 3.0-3.2
sumber
Dalam kasus saya, saya harus mengubah kolom DynamoDB - lastUpdated (Unix Timestamp) ke Waktu Normal.
Nilai awal lastUpdated adalah: 1460650607601 - dikonversi ke 2016-04-14 16:16:47 +0000 melalui:
sumber
Di masa depan format mungkin perlu diubah yang bisa menjadi sakit kepala kecil yang memiliki date.dateFromISO8601 panggilan di mana-mana dalam aplikasi. Gunakan kelas dan protokol untuk membungkus implementasi, mengubah panggilan format waktu tanggal di satu tempat akan lebih sederhana. Gunakan RFC3339 jika memungkinkan, itu representasi yang lebih lengkap. DateFormatProtocol dan DateFormat sangat bagus untuk injeksi ketergantungan.
sumber
Ada
ISO8601DateFormatter
kelas baru yang memungkinkan Anda membuat string hanya dengan satu baris. Untuk kompatibilitas mundur saya menggunakan C-library lama. Saya harap ini bermanfaat bagi seseorang.Swift 3.0
sumber
Untuk melengkapi versi Leo Dabus, saya menambahkan dukungan untuk proyek yang ditulis Swift dan Objective-C, juga menambahkan dukungan untuk milidetik opsional, mungkin bukan yang terbaik tetapi Anda akan mendapatkan intinya:
Xcode 8 dan Swift 3
sumber
Tanpa beberapa topeng String manual atau TimeFormatters
sumber
.iso8601
tidak akan mencakup milidetik.Berdasarkan jawaban yang dapat diterima dalam paradigma objek
tempat panggilan
sumber