ISO8601DateFormatter: แนวคิดหลักและการจัดรูปแบบ ISO 8601

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-13 เวลาอ่าน: 9 นาที

ISO8601DateFormatter เป็นคลาส Foundation ใน iOS และ macOS ที่ออกแบบมาสำหรับการจัดรูปแบบและแยกวิเคราะห์วันที่ตามมาตรฐานสากล ISO 8601 ตาม Apple Developer Documentation, 2024 ISO8601DateFormatter จะจัดการกับรูปแบบที่มีมิลลิวินาที เขตเวลา และเศษส่วนของวินาทีโดยอัตโนมัติ โดยไม่ต้องตั้งค่า DateFormat ด้วยตนเอง แตกต่างจาก DateFormatter คลาสนี้ไม่ขึ้นอยู่กับ Locale และ TimeZone — มันทำงานอย่างเคร่งครัดตามข้อกำหนด ISO 8601 ทำให้เหมาะสำหรับการแลกเปลี่ยนวันที่ระหว่างเซิร์ฟเวอร์และไคลเอ็นต์ คลาสนี้พร้อมใช้งานตั้งแต่ iOS 10 และ macOS 10.12

ประเด็นสำคัญ

  • ISO8601DateFormatter — คลาส Foundation สำหรับจัดรูปแบบวันที่ตามมาตรฐาน ISO 8601
  • ไม่ต้องใช้ DateFormat — รูปแบบถูกกำหนดโดยอัตโนมัติผ่านการตั้งค่าตัวเลือก
  • ไม่ขึ้นกับภาษา — ทำงานเหมือนกันบนทุกอุปกรณ์โดยไม่ต้องกำหนดค่า Locale
  • รองรับมิลลิวินาที — จัดการเศษส่วนของวินาทีทุกระดับความแม่นยำ (สาม, หกหรือมากกว่าหลัก)
  • ตัวเลือกการจัดรูปแบบ — withFullDate, withTime, withMilliseconds, withTimeZone และอื่นๆ ควบคุมส่วนประกอบของผลลัพธ์

ISO8601DateFormatter คืออะไร?

ISO8601DateFormatter เป็นคลาสย่อยเฉพาะของ Formatter ใน Foundation ที่ใช้การแปลงสองทิศทางระหว่าง Date และสตริงรูปแบบ ISO 8601 มาตรฐาน ISO 8601 (International Standard for the Representation of Dates and Times) กำหนดรูปแบบสากลสำหรับการแลกเปลี่ยนวันที่และเวลา: 2024-07-21T14:30:00+00:00 แตกต่างจาก DateFormatter คลาสนี้ไม่ต้องระบุ dateFormat และกำหนดโครงสร้างสตริงโดยอัตโนมัติตามตัวเลือกที่กำหนด

ข้อได้เปรียบหลักของ ISO8601DateFormatter เหนือ DateFormatter: ไม่ขึ้นกับภาษา (การแยกวิเคราะห์ทำงานเหมือนกันบนทุกอุปกรณ์), รองรับเศษส่วนของวินาทีในตัว (ด้วยจำนวนตำแหน่งทศนิยมใดๆ) และการตรวจจับรูปแบบอัตโนมัติตามตัวเลือกที่ส่งผ่าน คลาสนี้ยังจัดการกับส่วนต่อท้าย Z (การกำหนด UTC), เขตเวลาในรูปแบบ +HH:mm และความแม่นยำที่ลดลง (เฉพาะวันที่ไม่มีเวลา) ได้อย่างถูกต้อง

ตาม ข้อกำหนด ISO (ISO 8601-1:2019) มาตรฐานรองรับความแม่นยำสี่ระดับ: ปี (2024), ปี-เดือน (2024-07), วันที่เต็ม (2024-07-21) และวันที่-เวลาพร้อมเขตเวลา (2024-07-21T14:30:00+00:00) ISO8601DateFormatter ครอบคลุมทุกระดับเหล่านี้ผ่านการรวมกันของตัวเลือกการจัดรูปแบบ ช่วยให้นักพัฒนาไม่ต้องสร้างสตริง dateFormat ด้วยตนเอง

ISO8601DateFormatter ทำงานอย่างไรใน Foundation?

หลักการทำงาน ของ ISO8601DateFormatter ขึ้นอยู่กับการรวมกันของตัวเลือกบิต (formatOptions) ซึ่งแต่ละตัวจะรวมส่วนประกอบของวันที่หรือเวลาที่เฉพาะเจาะจงในผลลัพธ์ ตัวอย่างเช่น ตัวเลือก .withFullDate รวมปี, เดือนและวัน; .withTime รวมชั่วโมง, นาทีและวินาที การรวมตัวเลือกทำให้นักพัฒนาได้รับระดับความแม่นยำที่ต้องการโดยไม่ต้องเขียนสตริง dateFormat

ภายใน ISO8601DateFormatter ใช้ไลบรารี ICU สำหรับการแยกวิเคราะห์ แต่มีกฎ ISO 8601 ที่ตายตัว ซึ่งหมายความว่ามันไม่สนใจการตั้งค่า Locale และ TimeZone บนอุปกรณ์ — ผลลัพธ์สามารถคาดเดาได้เสมอ สำหรับการตั้งค่าเขตเวลา จะใช้คุณสมบัติ timeZone ซึ่งค่าเริ่มต้นคือ UTC ถ้า timeZone ถูกตั้งค่าเป็น nil จะใช้เวลาท้องถิ่นของอุปกรณ์

ตัวเลือกคำอธิบายตัวอย่างผลลัพธ์
.withFullDateปี, เดือน, วัน2024-07-21
.withTimeชั่วโมง, นาที, วินาที14:30:00
.withMillisecondsเศษส่วนของวินาที (สูงสุด 3 หลัก).123
.withFractionalSecondsเศษส่วนของวินาที (ทุกระดับความแม่นยำ).123456
.withTimeZoneเขตเวลา+03:00
.withColonSeparatorInTimeZoneตัวคั่นทวิภาคในเขตเวลา+03:00 (เทียบกับ +0300)
.withInternetDateTimeรูปแบบเต็ม (วันที่ + เวลา + โซน)2024-07-21T14:30:00+00:00

การรวมตัวเลือก: .withInternetDateTime เทียบเท่ากับการรวม .withFullDate, .withTime และ .withTimeZone เข้าด้วยกัน สำหรับการแยกวิเคราะห์สตริงที่มีมิลลิวินาที ให้เพิ่ม .withFractionalSeconds สิ่งสำคัญที่ต้องจำคือ .withMilliseconds จำกัดเศษส่วนของวินาทีไว้ที่สามหลัก ในขณะที่ .withFractionalSeconds รองรับทุกระดับความแม่นยำ — ตั้งแต่หนึ่งถึงเก้าหลักหลังจุดทศนิยม

ตัวเลือกการจัดรูปแบบ ISO 8601

ตัวเลือกการจัดรูปแบบ ของ ISO8601DateFormatter แบ่งออกเป็นสามกลุ่ม: ส่วนประกอบวันที่ (withFullDate, withYear, withMonth, withDay, withWeekOfYear), ส่วนประกอบเวลา (withTime, withHours, withMinutes, withSeconds) และการตั้งค่าเพิ่มเติม (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime) โดยการรวมกัน คุณจะได้รับรูปแบบย่อย ISO 8601 ได้แทบทุกแบบ

การรวมตัวเลือกหลัก

  • .withFullDate — เฉพาะวันที่: 2024-07-21 สำหรับแยกวิเคราะห์สตริง YYYY-MM-DD
  • .withFullDate + .withTime — วันที่และเวลาโดยไม่มีเขตเวลา: 2024-07-21T14:30:00
  • .withInternetDateTime — รูปแบบเต็ม: 2024-07-21T14:30:00Z หรือ 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — พร้อมเศษส่วนของวินาที: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — รูปแบบเต็มโดยไม่มีทวิภาคใน tz: 2024-07-21T14:30:00+0300

ความละเอียดสำคัญ: .withFractionalSeconds และ .withMilliseconds เป็นแบบแยกกัน — ถ้าตั้งค่าทั้งสองอย่าง จะใช้ .withFractionalSeconds สำหรับการแยกวิเคราะห์มิลลิวินาทีจากข้อมูลเซิร์ฟเวור แนะนำให้ใช้ .withFractionalSeconds เนื่องจากเซิร์ฟเวอร์หลายแห่งส่งเศษส่วนของวินาทีด้วยสาม, หกหรือเก้าหลัก และ .withFractionalSeconds จัดการกับความยาวใดๆ

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 ใน Swift: ตัวอย่างโค้ด

การใช้งานพื้นฐาน ของ ISO8601DateFormatter เริ่มต้นด้วยการสร้างอินสแตนซ์, การตั้งค่า timeZone (แนะนำ UTC สำหรับข้อมูลเซิร์ฟเวอร์) และ formatOptions หลังจากนั้นสามารถเรียกใช้ string(from:) สำหรับการจัดรูปแบบและ date(from:) สำหรับการแยกวิเคราะห์ แตกต่างจาก DateFormatter ไม่ต้องกังวลเกี่ยวกับ Locale — คลาสไม่สนใจการตั้งค่าภูมิภาค

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)")

การแยกวิเคราะห์วันที่ที่มีเศษส่วนของวินาทีความยาวแปรผัน เป็นคุณสมบัติของ API สมัยใหม่หลายตัว เซิร์ฟเวอร์อาจส่ง 2024-07-21T14:30:00.123Z (3 หลัก) หรือ 2024-07-21T14:30:00.123456Z (6 หลัก) ISO8601DateFormatter ที่มีตัวเลือก .withFractionalSeconds จะจัดการกับทั้งสองรูปแบบได้อย่างถูกต้อง ในขณะที่ DateFormatter ที่มี dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" จะจัดการได้เฉพาะมิลลิวินาทีสามหลักเท่านั้น

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)")

การทดสอบการแยกวิเคราะห์ทุกรูปแบบ: โค้ดที่แสดงให้เห็นว่า ISO8601DateFormatter ที่มี .withFractionalSeconds จัดการเศษส่วนของวินาทีทุกระดับความยาวตั้งแต่ 1 ถึง 9 หลักได้สำเร็จ ซึ่งสำคัญสำหรับความเข้ากันได้กับแพลตฟอร์มเซิร์ฟเวอร์ต่างๆ: .NET มักสร้าง 7 หลัก (100 นาโนวินาที), Python — 6, Java — 3 หรือ 9 ขึ้นอยู่กับเวอร์ชัน

การเปรียบเทียบกับ DateFormatter สำหรับ ISO 8601

DateFormatter สามารถแยกวิเคราะห์ ISO 8601 ได้เช่นกัน แต่ต้องกำหนดค่า dateFormat, locale และ timeZone ด้วยตนเอง ปัญหาหลักคือ DateFormatter ขึ้นอยู่กับ Locale และถ้าไม่ได้ตั้งค่า en_US_POSIX การแยกวิเคราะห์อาจล้มเหลวสำหรับผู้ใช้จากภูมิภาคที่มีรูปแบบวันที่ไม่เป็นมาตรฐาน ISO8601DateFormatter แก้ปัญหานี้ในระดับสถาปัตยกรรม: มันไม่ใช้ Locale

พารามิเตอร์ISO8601DateFormatterDateFormatter
การกำหนดค่า Localeไม่ต้อง (ไม่สนใจ)จำเป็นต้องใช้ en_US_POSIX
DateFormatอัตโนมัติ (ผ่านตัวเลือก)สตริงรูปแบบที่กำหนดเอง
เศษส่วนของวินาทีทุกระดับความแม่นยำ (.withFractionalSeconds)SSS ตายตัว
ส่วนต่อท้าย Zจัดการอย่างถูกต้องผ่าน dateFormat
ประสิทธิภาพสูงกว่า (เฉพาะทาง)ต่ำกว่า (ทั่วไป)
มาตรฐานเฉพาะ ISO 8601ทุกรูปแบบ
เวอร์ชัน iOSiOS 10+iOS 2+

เมื่อใดควรใช้ DateFormatter: ถ้าคุณต้องจัดรูปแบบวันที่ในรูปแบบที่ไม่ใช่ ISO 8601 (เช่น "21 กรกฎาคม 2024" สำหรับ UI) หรือถ้าคุณต้องรองรับ iOS 9 และเก่ากว่า สำหรับงานแลกเปลี่ยนวันที่ระหว่างเซิร์ฟเวอร์และไคลเอ็นต์ทั้งหมด ให้ใช้ ISO8601DateFormatter — มันปลอดภัยกว่า มีประสิทธิภาพมากกว่าและต้องการโค้ดน้อยกว่า DateFormatter สำหรับ ISO 8601 เป็นแหล่งของข้อบกพร่องที่อาจเกิดขึ้นเกี่ยวกับภาษาและการตั้งค่าภูมิภาค

การย้ายจาก DateFormatter ไปยัง ISO8601DateFormatter: แทนที่การสร้าง DateFormatter + การกำหนดค่า dateFormat + locale + timeZone ด้วยการสร้าง ISO8601DateFormatter + การกำหนดค่า formatOptions + timeZone การแยกวิเคราะห์สตริงยังคงไม่เปลี่ยนแปลงผ่าน date(from:) สำหรับความเข้ากันได้ย้อนหลัง คุณสามารถใช้ #available(iOS 10, *) พร้อมกับ fallback ไปยัง DateFormatter

ข้อผิดพลาดทั่วไปเมื่อแยกวิเคราะห์ ISO 8601

การลืมกำหนดค่า formatOptions ทำให้ตัวจัดรูปแบบใช้ค่าเริ่มต้น — .withInternetDateTime ถ้าเซิร์ฟเวอร์ส่งวันที่โดยไม่มีเวลา (2024-07-21) การแยกวิเคราะห์จะคืนค่า nil ตรวจสอบเสมอว่า formatOptions ครอบคลุมทุกรูปแบบที่เป็นไปได้ที่อาจมาจากเซิร์ฟเวอร์ สำหรับ API ที่มีรูปแบบแปรผัน ให้ใช้ความพยายามแบบ fallback ด้วยการรวมตัวเลือกต่างๆ

ความสับสนระหว่าง withMilliseconds และ withFractionalSeconds เป็นข้อผิดพลาดทั่วไปเมื่อแยกวิเคราะห์วันที่ที่มีเศษส่วนของวินาที withMilliseconds คาดหวัง 3 หลักหลังจุดทศนิยมพอดี ถ้าเซิร์ฟเวอร์ส่ง 6 หลัก (ไมโครวินาที) การแยกวิเคราะห์ด้วย withMilliseconds จะล้มเหลว ใช้ .withFractionalSeconds สำหรับความเข้ากันได้กับจำนวนหลักใดๆ .withFractionalSeconds พร้อมใช้งานใน iOS 13; สำหรับเวอร์ชันเก่า ให้ใช้ DateFormatter พร้อมกับ dateFormat

การไม่สนใจเขตเวลา เป็นอีกปัญหาที่พบบ่อย ถ้าเซิร์ฟเวอร์ส่งวันที่พร้อมกับเขตเวลา (+03:00) และตัวจัดรูปแบบถูกตั้งค่าเป็น UTC การแยกวิเคราะห์จะไม่ล้มเหลว แต่ผลลัพธ์จะอยู่ใน UTC นักพัฒนามักคาดหวังให้ Date เก็บรักษาเขตเวลาไว้ แต่ Date เป็นช่วงเวลาสัมบูรณ์ — มันไม่เก็บข้อมูลเขตเวลา สำหรับการแสดงผลที่ถูกต้อง ให้บันทึกเขตเวลาแยกต่างหากหรือใช้ ISO8601DateFormatter พร้อมกับ timeZone ที่ถูกต้อง

ตาม Apple Forum (2024) ประมาณ 20% ของคำถามเกี่ยวกับ ISO8601DateFormatter เกี่ยวข้องกับรูปแบบที่วินาทีเป็นตัวเลือก มาตรฐาน ISO 8601 อนุญาตรูปแบบที่ไม่มีวินาที: 2024-07-21T14:30+03:00 ISO8601DateFormatter ที่มี .withInternetDateTime ไม่รองรับรูปแบบนี้ — สำหรับการแยกวิเคราะห์จะต้องใช้ DateFormatter ที่มี dateFormat = "yyyy-MM-dd'T'HH:mmZ" ข้อจำกัดนี้สำคัญที่ต้องพิจารณาเมื่อทำงานกับ API ที่ใช้รูปแบบเวลาย่อ

คำถามที่พบบ่อย

ISO8601DateFormatter คืออะไร?

ISO8601DateFormatter — คลาส Foundation เฉพาะทางสำหรับการจัดรูปแบบและแยกวิเคราะห์วันที่ในรูปแบบ ISO 8601 พร้อมใช้งานตั้งแต่ iOS 10 จัดการรูปแบบมาตรฐานโดยอัตโนมัติโดยไม่ต้องตั้งค่า dateFormat ด้วยตนเอง

ISO8601DateFormatter แตกต่างจาก DateFormatter อย่างไร?

ISO8601DateFormatter ไม่ขึ้นอยู่กับ Locale ใช้ตัวเลือกแทน dateFormat และจัดการเศษส่วนของวินาทีทุกระดับความยาวได้อย่างถูกต้อง DateFormatter เป็นสากล แต่ต้องกำหนดค่าด้วยตนเองและมีแนวโน้มที่จะเกิดข้อบกพร่องเกี่ยวกับการตั้งค่าภูมิภาค

วิธีจัดการกับเศษส่วนของวินาทีความยาวแปรผัน?

ใช้ตัวเลือก .withFractionalSeconds — รองรับตั้งแต่ 1 ถึง 9 หลักหลังจุดทศนิยม อย่าใช้ .withMilliseconds ถ้าความแม่นยำอาจเปลี่ยนแปลงได้ .withFractionalSeconds พร้อมใช้งานตั้งแต่ iOS 13

ISO8601DateFormatter ใช้เขตเวลาใด?

ค่าเริ่มต้นคือ UTC เมื่อต้องการเปลี่ยน ให้ตั้งค่าคุณสมบัติ timeZone ถ้า timeZone = nil จะใช้เวลาท้องถิ่นของอุปกรณ์ เมื่อแยกวิเคราะห์สตริงที่มีเขตเวลาชัดเจนในรูปแบบ +HH:MM ตัวจัดรูปแบบจะพิจารณาโดยอัตโนมัติ

ทำไมการแยกวิเคราะห์วันที่ที่ไม่มีเวลาถึงคืนค่า nil?

เพราะค่าเริ่มต้นของ formatOptions คือ .withInternetDateTime ซึ่งคาดหวังวันที่ + เวลา + เขตเวลา สำหรับการแยกวิเคราะห์เฉพาะวันที่ ให้ตั้งค่า formatOptions = [.withFullDate] เพื่อรองรับทั้งสองรูปแบบ ให้ใช้ fallback ด้วยตัวเลือกที่แตกต่างกัน

สรุป

  • ISO8601DateFormatter — คลาสเฉพาะทางสำหรับ ISO 8601 ปลอดภัยและง่ายกว่า DateFormatter
  • ตัวเลือกการจัดรูปแบบ แทนที่ dateFormat ด้วยตนเอง — รวม .withFullDate, .withTime, .withTimeZone
  • ไม่ขึ้นกับ Locale — การแยกวิเคราะห์ทำงานเหมือนกันบนทุกอุปกรณ์โดยไม่ต้องกำหนดค่า locale
  • .withFractionalSeconds จัดการเศษส่วนของวินาทีทุกระดับความแม่นยำ (1–9 หลัก)
  • DateFormatter ด้อยกว่า ในด้านประสิทธิภาพ ความปลอดภัยและความเรียบง่ายสำหรับงาน ISO 8601
  • ความสับสนของตัวเลือก — withMilliseconds และ withFractionalSeconds ไม่สามารถใช้แทนกันได้
  • รูปแบบที่ไม่มีวินาที (2024-07-21T14:30+03:00) ไม่รองรับ — ต้องใช้ DateFormatter

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม