ISO8601DateFormatter: các khái niệm chính và định dạng ISO 8601

Tác giả: IT Sectr Đã đăng: 2026-07-13 Thời gian đọc: 9 phút

ISO8601DateFormatter là một lớp Foundation trong iOS và macOS được thiết kế để định dạng và phân tích ngày tháng theo tiêu chuẩn quốc tế ISO 8601. Theo Apple Developer Documentation, 2024, ISO8601DateFormatter tự động xử lý các định dạng với mili giây, múi giờ và phần nhỏ của giây mà không cần thiết lập DateFormat thủ công. Không giống như DateFormatter, lớp này không phụ thuộc vào Locale và TimeZone — nó hoạt động nghiêm ngặt theo đặc tả ISO 8601, khiến nó trở nên lý tưởng để trao đổi ngày tháng giữa máy chủ và máy khách. Lớp này khả dụng từ iOS 10 và macOS 10.12.

Những điểm chính

  • ISO8601DateFormatter — lớp Foundation để định dạng ngày tháng theo tiêu chuẩn ISO 8601
  • Không yêu cầu DateFormat — định dạng được xác định tự động qua cài đặt tùy chọn
  • Độc lập với ngôn ngữ — hoạt động giống nhau trên tất cả thiết bị mà không cần cấu hình Locale
  • Hỗ trợ mili giây — xử lý phần nhỏ của giây với bất kỳ độ chính xác nào (ba, sáu hoặc nhiều chữ số hơn)
  • Tùy chọn định dạng — withFullDate, withTime, withMilliseconds, withTimeZone và các tùy chọn khác điều khiển thành phần đầu ra

ISO8601DateFormatter là gì?

ISO8601DateFormatter là một lớp con chuyên biệt của Formatter trong Foundation thực hiện chuyển đổi hai chiều giữa Date và chuỗi định dạng ISO 8601. Tiêu chuẩn ISO 8601 (International Standard for the Representation of Dates and Times) định nghĩa một định dạng quốc tế để trao đổi ngày và giờ: 2024-07-21T14:30:00+00:00. Không giống như DateFormatter, lớp này không yêu cầu chỉ định dateFormat và tự động xác định cấu trúc chuỗi dựa trên các tùy chọn được cung cấp.

Các ưu điểm chính của ISO8601DateFormatter so với DateFormatter: không phụ thuộc vào ngôn ngữ (phân tích hoạt động giống nhau trên mọi thiết bị), hỗ trợ tích hợp cho phần nhỏ của giây (với bất kỳ số chữ số thập phân nào) và tự động phát hiện định dạng dựa trên các tùy chọn được truyền vào. Lớp này cũng xử lý chính xác hậu tố Z (ký hiệu UTC), múi giờ ở định dạng +HH:mm và độ chính xác giảm (chỉ ngày không có giờ).

Theo Đặc tả ISO (ISO 8601-1:2019), tiêu chuẩn hỗ trợ bốn mức độ chính xác: năm (2024), năm-tháng (2024-07), ngày đầy đủ (2024-07-21) và ngày-giờ với múi giờ (2024-07-21T14:30:00+00:00). ISO8601DateFormatter bao phủ tất cả các mức này thông qua sự kết hợp của các tùy chọn định dạng, giải phóng nhà phát triển khỏi việc xây dựng thủ công chuỗi dateFormat.

ISO8601DateFormatter hoạt động như thế nào trong Foundation?

Nguyên lý hoạt động của ISO8601DateFormatter dựa trên sự kết hợp của các tùy chọn bit (formatOptions), mỗi tùy chọn bao gồm một thành phần ngày hoặc giờ cụ thể trong đầu ra. Ví dụ, tùy chọn .withFullDate bao gồm năm, tháng và ngày; .withTime bao gồm giờ, phút và giây. Bằng cách kết hợp các tùy chọn, nhà phát triển đạt được mức độ chính xác mong muốn mà không cần viết chuỗi dateFormat.

Bên trong, ISO8601DateFormatter sử dụng thư viện ICU để phân tích, nhưng với các quy tắc ISO 8601 cố định. Điều này có nghĩa là nó bỏ qua cài đặt Locale và TimeZone trên thiết bị — kết quả luôn có thể dự đoán được. Để thiết lập múi giờ, sử dụng thuộc tính timeZone, mặc định là UTC. Nếu timeZone được đặt thành nil, thời gian địa phương của thiết bị được sử dụng.

Tùy chọnMô tảVí dụ đầu ra
.withFullDateNăm, tháng, ngày2024-07-21
.withTimeGiờ, phút, giây14:30:00
.withMillisecondsPhần nhỏ của giây (tối đa 3 chữ số).123
.withFractionalSecondsPhần nhỏ của giây (mọi độ chính xác).123456
.withTimeZoneMúi giờ+03:00
.withColonSeparatorInTimeZoneDấu hai chấm trong múi giờ+03:00 (so với +0300)
.withInternetDateTimeĐịnh dạng đầy đủ (ngày + giờ + múi)2024-07-21T14:30:00+00:00

Kết hợp tùy chọn: .withInternetDateTime tương đương với việc kết hợp .withFullDate, .withTime và .withTimeZone. Để phân tích chuỗi có mili giây, thêm .withFractionalSeconds. Điều quan trọng cần nhớ là .withMilliseconds giới hạn phần nhỏ của giây ở ba chữ số, trong khi .withFractionalSeconds hỗ trợ mọi độ chính xác — từ một đến chín chữ số sau dấu thập phân.

Tùy chọn định dạng ISO 8601

Tùy chọn định dạng của ISO8601DateFormatter được chia thành ba nhóm: thành phần ngày (withFullDate, withYear, withMonth, withDay, withWeekOfYear), thành phần giờ (withTime, withHours, withMinutes, withSeconds) và cài đặt bổ sung (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Bằng cách kết hợp chúng, bạn có thể có được hầu như bất kỳ định dạng con ISO 8601 nào.

Các kết hợp tùy chọn chính

  • .withFullDate — chỉ ngày: 2024-07-21. Để phân tích chuỗi YYYY-MM-DD
  • .withFullDate + .withTime — ngày và giờ không có múi giờ: 2024-07-21T14:30:00
  • .withInternetDateTime — định dạng đầy đủ: 2024-07-21T14:30:00Z hoặc 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — với phần nhỏ của giây: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — định dạng đầy đủ không có dấu hai chấm trong tz: 2024-07-21T14:30:00+0300

Sắc thái quan trọng: .withFractionalSeconds và .withMilliseconds loại trừ lẫn nhau — nếu cả hai được đặt, .withFractionalSeconds được áp dụng. Để phân tích mili giây từ dữ liệu máy chủ, nên sử dụng .withFractionalSeconds, vì nhiều máy chủ gửi phần nhỏ của giây với ba, sáu hoặc chín chữ số và .withFractionalSeconds xử lý mọi độ dài.

swift
import Foundation

// Configure ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// Different format option combinations
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Date: \(dateOnly)")

formatter.formatOptions = [.withFullDate, .withTime]
let dateTime = formatter.string(from: Date())
print("DateTime: \(dateTime)")

formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let full = formatter.string(from: Date())
print("Full: \(full)")

// Parse string with milliseconds
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("Parsed: \(parsed)")
}

ISO8601DateFormatter trong Swift: ví dụ mã

Sử dụng cơ bản ISO8601DateFormatter bao gồm việc tạo một thực thể, thiết lập timeZone (UTC được khuyến nghị cho dữ liệu máy chủ) và formatOptions, sau đó có thể gọi string(from:) để định dạng và date(from:) để phân tích. Không giống như DateFormatter, không cần lo lắng về Locale — lớp bỏ qua cài đặt khu vực.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// Parse different ISO 8601 formats
let strings: [String] = [
    "2024-07-21T14:30:00Z",
    "2024-07-21T14:30:00+03:00",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21"
]

for str in strings {
    if let autoParsed = formatter.date(from: str) {
        print("Parsed '\(str)': \(autoParsed)")
    } else {
        // Use withFullDate for date-only strings
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("Fallback parsed '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// Serialize to RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

Phân tích ngày tháng với phần nhỏ của giây có độ dài thay đổi là tính năng của nhiều API hiện đại. Máy chủ có thể gửi 2024-07-21T14:30:00.123Z (3 chữ số) hoặc 2024-07-21T14:30:00.123456Z (6 chữ số). ISO8601DateFormatter với tùy chọn .withFractionalSeconds sẽ xử lý chính xác cả hai biến thể, trong khi DateFormatter với dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" chỉ xử lý mili giây ba chữ số.

swift
import Foundation

let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withFractionalSeconds
]

// Different fractional second precision
let variants: [String] = [
    "2024-07-21T14:30:00.1Z",
    "2024-07-21T14:30:00.12Z",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21T14:30:00.123456Z",
    "2024-07-21T14:30:00.123456789Z"
]

for variant in variants {
    if let parsed = variantFormatter.date(from: variant) {
        print("OK: \(variant) -> \(parsed)")
    } else {
        print("FAIL: \(variant)")
    }
}

// Use withMilliseconds (3 digits only)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("With milliseconds: \(milliParsed)")

Kiểm tra phân tích tất cả các biến thể: mã được hiển thị chứng minh rằng ISO8601DateFormatter với .withFractionalSeconds xử lý thành công phần nhỏ của giây với bất kỳ độ dài nào từ 1 đến 9 chữ số. Điều này quan trọng cho khả năng tương thích với các nền tảng máy chủ khác nhau: .NET thường tạo 7 chữ số (tích 100 nano giây), Python — 6, Java — 3 hoặc 9 tùy thuộc vào phiên bản.

So sánh với DateFormatter cho ISO 8601

DateFormatter cũng có thể phân tích ISO 8601, nhưng yêu cầu cấu hình thủ công dateFormat, locale và timeZone. Vấn đề chính là DateFormatter phụ thuộc vào Locale và nếu không đặt en_US_POSIX, việc phân tích có thể thất bại đối với người dùng từ các khu vực có định dạng ngày không chuẩn. ISO8601DateFormatter giải quyết vấn đề này ở cấp độ kiến trúc: nó không sử dụng Locale.

Tham sốISO8601DateFormatterDateFormatter
Cấu hình LocaleKhông yêu cầu (bỏ qua)en_US_POSIX bắt buộc
DateFormatTự động (qua tùy chọn)Chuỗi định dạng thủ công
Phần nhỏ của giâyMọi độ chính xác (.withFractionalSeconds)SSS cố định
Hậu tố ZXử lý chính xácQua dateFormat
Hiệu suấtCao hơn (chuyên biệt)Thấp hơn (tổng quát)
Tiêu chuẩnChỉ ISO 8601Mọi định dạng
Phiên bản iOSiOS 10+iOS 2+

Khi nào sử dụng DateFormatter: nếu bạn cần định dạng ngày tháng ở định dạng không phải ISO 8601 (ví dụ: "21 tháng 7, 2024" cho giao diện người dùng) hoặc nếu bạn cần hỗ trợ iOS 9 trở về trước. Đối với tất cả các tác vụ trao đổi ngày tháng giữa máy chủ và máy khách, hãy sử dụng ISO8601DateFormatter — nó an toàn hơn, hiệu quả hơn và yêu cầu ít mã hơn. DateFormatter cho ISO 8601 là nguồn gốc của các lỗi tiềm ẩn liên quan đến ngôn ngữ và cài đặt khu vực.

Di chuyển từ DateFormatter sang ISO8601DateFormatter: thay thế việc tạo DateFormatter + cấu hình dateFormat + locale + timeZone bằng việc tạo ISO8601DateFormatter + cấu hình formatOptions + timeZone. Việc phân tích chuỗi không thay đổi qua date(from:). Để tương thích ngược, bạn có thể sử dụng #available(iOS 10, *) với dự phòng sang DateFormatter.

Lỗi thường gặp khi phân tích ISO 8601

Quên cấu hình formatOptions khiến bộ định dạng sử dụng giá trị mặc định — .withInternetDateTime. Nếu máy chủ gửi ngày không có giờ (2024-07-21), việc phân tích sẽ trả về nil. Luôn kiểm tra rằng formatOptions bao phủ tất cả các định dạng có thể có từ máy chủ. Đối với API có định dạng thay đổi, hãy sử dụng các lần thử dự phòng với các kết hợp tùy chọn khác nhau.

Nhầm lẫn giữa withMilliseconds và withFractionalSeconds là lỗi phổ biến khi phân tích ngày tháng có phần nhỏ của giây. withMilliseconds mong đợi chính xác 3 chữ số sau dấu thập phân. Nếu máy chủ gửi 6 chữ số (micro giây), việc phân tích với withMilliseconds sẽ thất bại. Sử dụng .withFractionalSeconds để tương thích với bất kỳ số chữ số nào. .withFractionalSeconds có sẵn từ iOS 13; đối với các phiên bản cũ hơn, sử dụng DateFormatter với dateFormat.

Bỏ qua múi giờ là một vấn đề phổ biến khác. Nếu máy chủ gửi ngày có múi giờ (+03:00) và bộ định dạng được đặt thành UTC, việc phân tích sẽ không thất bại, nhưng kết quả sẽ ở UTC. Các nhà phát triển thường mong đợi Date giữ lại múi giờ, nhưng Date là một thời điểm tuyệt đối — nó không lưu trữ thông tin múi giờ. Để hiển thị chính xác, hãy lưu múi giờ riêng biệt hoặc sử dụng ISO8601DateFormatter với timeZone phù hợp.

Theo Apple Forum (2024), khoảng 20% câu hỏi về ISO8601DateFormatter liên quan đến định dạng nơi giây là tùy chọn. Tiêu chuẩn ISO 8601 cho phép định dạng không có giây: 2024-07-21T14:30+03:00. ISO8601DateFormatter với .withInternetDateTime không hỗ trợ định dạng này — để phân tích nó, bạn sẽ cần DateFormatter với dateFormat = "yyyy-MM-dd'T'HH:mmZ". Giới hạn này cần được xem xét khi làm việc với các API sử dụng định dạng giờ rút gọn.

Các câu hỏi thường gặp

ISO8601DateFormatter là gì?

ISO8601DateFormatter là một lớp Foundation chuyên biệt để định dạng và phân tích ngày tháng ở định dạng ISO 8601, khả dụng từ iOS 10. Tự động xử lý các định dạng tiêu chuẩn mà không cần thiết lập dateFormat thủ công.

ISO8601DateFormatter khác DateFormatter như thế nào?

ISO8601DateFormatter không phụ thuộc vào Locale, sử dụng tùy chọn thay vì dateFormat và xử lý chính xác phần nhỏ của giây với bất kỳ độ dài nào. DateFormatter phổ quát, nhưng yêu cầu cấu hình thủ công và dễ gặp lỗi liên quan đến cài đặt khu vực.

Làm thế nào để xử lý phần nhỏ của giây có độ dài thay đổi?

Sử dụng tùy chọn .withFractionalSeconds — nó hỗ trợ từ 1 đến 9 chữ số sau dấu thập phân. Không sử dụng .withMilliseconds nếu độ chính xác có thể thay đổi. .withFractionalSeconds khả dụng từ iOS 13.

ISO8601DateFormatter sử dụng múi giờ nào?

UTC theo mặc định. Để thay đổi, hãy thiết lập thuộc tính timeZone. Nếu timeZone = nil, thời gian địa phương của thiết bị được sử dụng. Khi phân tích chuỗi có múi giờ rõ ràng ở định dạng +HH:MM, bộ định dạng tự động tính đến nó.

Tại sao phân tích ngày không có giờ trả về nil?

Bởi vì formatOptions mặc định là .withInternetDateTime, mong đợi ngày + giờ + múi giờ. Để phân tích chỉ ngày, đặt formatOptions = [.withFullDate]. Để hỗ trợ cả hai biến thể, sử dụng dự phòng với các tùy chọn khác nhau.

Tổng kết

  • ISO8601DateFormatter — lớp chuyên biệt cho ISO 8601, an toàn và đơn giản hơn DateFormatter
  • Tùy chọn định dạng thay thế dateFormat thủ công — kết hợp .withFullDate, .withTime, .withTimeZone
  • Độc lập với Locale — việc phân tích hoạt động giống nhau trên tất cả thiết bị không cần cấu hình locale
  • .withFractionalSeconds xử lý phần nhỏ của giây với mọi độ chính xác (1–9 chữ số)
  • DateFormatter kém hơn về hiệu suất, an toàn và đơn giản cho các tác vụ ISO 8601
  • Nhầm lẫn tùy chọn — withMilliseconds và withFractionalSeconds không thể thay thế cho nhau
  • Định dạng không có giây (2024-07-21T14:30+03:00) không được hỗ trợ — cần DateFormatter

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm