Date: nó là gì, kiểu thời gian và TimeInterval trong Foundation

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

Date là một cấu trúc Foundation đại diện cho một thời điểm cụ thể, độc lập với lịch và múi giờ. Kiểu này lưu trữ số giây đã trôi qua kể từ ngày tham chiếu 1 tháng 1 năm 2001 và cung cấp các thao tác cơ bản để so sánh và tính toán khoảng thời gian. Theo tài liệu Apple Developer (2025), Date được sử dụng trong tất cả các framework của Apple: từ UIKit và SwiftUI đến CloudKit và Core Data. Hiểu cách Date hoạt động là điều cần thiết cho bất kỳ nhà phát triển iOS nào, vì nếu không có nó thì không thể quản lý thời gian trong ứng dụng.

Những điểm chính

  • Date — một cấu trúc Foundation lưu trữ một thời điểm tuyệt đối dưới dạng số giây từ ngày tham chiếu.
  • TimeInterval — kiểu Double để biểu diễn khoảng cách giữa hai thời điểm tính bằng giây.
  • Date() — một bộ khởi tạo tạo đối tượng với thời điểm hiện tại tại thời điểm gọi.
  • So sánh ngày được thực hiện qua toán tử so sánh hoặc các phương thức compare, earlierDate, laterDate.
  • DateFormatter — thành phần bắt buộc để hiển thị ngày cho người dùng ở định dạng có thể đọc được.

Date trong Foundation là gì?

Date là một kiểu giá trị từ framework Foundation ghi lại một thời điểm tuyệt đối duy nhất. Không giống như biểu diễn lịch (năm, tháng, ngày), Date không phụ thuộc vào múi giờ hay hệ thống lịch — nó là một giá trị dấu thời gian thuần số.

Biểu diễn nội bộ của Date là TimeInterval (bí danh kiểu cho Double), lưu trữ số giây tương đối so với ngày tham chiếu — 1 tháng 1 năm 2001, 00:00:00 UTC. Apple chọn ngày này thay vì kỷ nguyên Unix (1970) để tương thích với các hệ thống NeXTSTEP cũ, nơi iOS và macOS được xây dựng dựa trên.

Date được sử dụng như kiểu thời gian tiêu chuẩn trong tất cả API của Apple: UIDatePicker, DatePicker, UserDefaults, Codable, Core Data, CloudKit. Nếu không có Date, không thể làm việc với lịch trình, bộ đếm thời gian, sự kiện lịch, tuần tự hóa dữ liệu và bất kỳ thao tác nào liên quan đến thời gian.

Date so với các kiểu thời gian khác

Date khác với các kiểu lịch ở chỗ nó đại diện cho một dấu thời gian vật lý thay vì một giá trị có thể đọc được bằng con người. Cùng một Date có thể tương ứng với các ngày lịch khác nhau trong các múi giờ khác nhau. Để trích xuất thành phần (năm, tháng, ngày), Date được chuyển đổi qua CalendarDateComponents.

Date cũng khác với DispatchTime, được sử dụng để điều phối tác vụ trong Grand Central Dispatch. DispatchTime tương đối với thời điểm khởi động hệ thống, trong khi Date là dấu thời gian tuyệt đối có thể được lưu, truyền và khôi phục.

Tạo Date trong Swift

Date() là cách đơn giản nhất để tạo một đối tượng với thời điểm hiện tại. Bộ khởi tạo không tham số trả về thời gian chính xác của lệnh gọi. Để tạo ngày trong quá khứ hoặc tương lai, hãy sử dụng TimeInterval và phương thức addingTimeInterval, hoặc khởi tạo từ Date hiện có.

Để tạo ngày tùy ý từ các thành phần, hãy sử dụng cặp CalendarDateComponents. Calendar chuyển đổi các thành phần có thể đọc được (năm, tháng, ngày, giờ, phút) thành Date. Bạn cũng có thể khởi tạo Date qua ISO8601DateFormatter từ chuỗi ISO 8601, hoặc qua DateFormatter từ biểu diễn chuỗi tùy ý.

Date.distantPastDate.distantFuture là hai thuộc tính tĩnh đại diện cho những thời điểm xa vô hạn trong quá khứ và tương lai. Chúng được sử dụng làm giá trị biên để lọc và sắp xếp ngày trong các thuật toán.

swift
import Foundation

// Tạo Date với thời gian hiện tại
let now = Date()
print("Current time: \(now)")

// Ngày trong 1 giờ (3600 giây)
let inOneHour = now.addingTimeInterval(3600)

// Ngày từ các thành phần
var components = DateComponents()
components.year = 2025
components.month = 12
components.day = 25
let christmas = Calendar.current.date(from: components)!

Ví dụ cho thấy ba cách tạo Date: thời gian hiện tại, thêm khoảng thời gian và tạo qua DateComponents. Cả ba cách đều trả về giá trị kiểu Date với độ chính xác đến mili giây. Calendar.current sử dụng lịch hệ thống của người dùng — trên thiết bị Apple, đây thường là lịch Gregory.

TimeInterval và so sánh ngày

TimeInterval là bí danh kiểu cho Double đại diện cho số giây giữa hai thời điểm. Độ chính xác của TimeInterval đạt đến phần nhỏ của mili giây, đủ cho hầu hết các tác vụ thực tế. TimeInterval âm chỉ quá khứ so với điểm tham chiếu.

Date hỗ trợ tất cả các toán tử so sánh tiêu chuẩn: ==, <, >, <=, >=. Swift tự động so sánh các giá trị TimeInterval nội bộ. Phương thức compare trả về ComparisonResult với các tùy chọn .orderedSame, .orderedAscending, .orderedDescending để so sánh rõ ràng hơn.

Date.distance(to:) là phương thức trả về TimeInterval đến ngày được chỉ định. Nếu ngày mục tiêu ở quá khứ, kết quả là âm. advanced(by:) tạo ngày mới bằng cách thêm TimeInterval được chỉ định vào ngày hiện tại. Các phương thức này triển khai giao thức Strideable, cho phép sử dụng Date trong RangeClosedRange.

swift
let start = Date()
let end = start.addingTimeInterval(86400)

// So sánh bằng toán tử
if start < end {
    print("start is earlier")
}

// TimeInterval giữa hai ngày
let interval: TimeInterval = end.timeIntervalSince(start)
print("Seconds: \(Int(interval / 60)) minutes")

// Sử dụng Date trong phạm vi
let range = start...end
let mid = start.addingTimeInterval(43200)
if range.contains(mid) {
    print("mid is between start and end")
}

TimeInterval 86400 tương ứng với một ngày. Đối với khoảng thời gian phức tạp hơn — tuần, tháng, năm — hãy sử dụng Calendar và DateComponents, vì các đơn vị này có độ dài thay đổi (năm nhuận, giờ mùa hè). TimeInterval chỉ áp dụng cho khoảng thời gian cố định tính bằng giây.

Calendar và DateComponents

Calendar là cầu nối giữa Date và các thành phần có thể đọc được. Calendar chuyển đổi Date thành DateComponents (năm, tháng, ngày, giờ, phút, giây) có tính đến múi giờ và ngôn ngữ địa phương. Không có Calendar, không thể trích xuất năm hoặc tháng từ Date — Date không chứa thông tin này do bản chất tuyệt đối của nó.

Phương thức Calendar.component trích xuất một thành phần duy nhất từ Date: năm, tháng, ngày, giờ, phút, giây, thứ trong tuần, quý. Phương thức Calendar.dateComponents trích xuất một tập hợp các thành phần trong một lần gọi — điều này hiệu quả hơn gọi component cho từng trường riêng lẻ.

Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday là các phương thức tiện lợi để kiểm tra ngày tương đối. Calendar.dateInterval trả về đầu và cuối của khoảng thời gian được chỉ định (ngày, tuần, tháng, năm). Calendar.compare so sánh ngày với độ chính xác đến thành phần được chỉ định — ví dụ: năm mà không xét tháng và ngày.

swift
let calendar = Calendar.current

// Trích xuất thành phần
let year = calendar.component(.year, from: Date())
let month = calendar.component(.month, from: Date())

// Kiểm tra ngày tương đối
if calendar.isDateInToday(someDate) {
    print("Today!")
}

// Đầu và cuối ngày
let dayInterval = calendar.dateInterval(of: .day, for: Date())!
print("Day start: \(dayInterval.start)")
print("Day end: \(dayInterval.end)")

Calendar.current sử dụng cài đặt hệ thống của người dùng — lịch, múi giờ và ngôn ngữ địa phương. Để kiểm thử hoặc tính toán cụ thể, bạn có thể tạo Calendar với các tham số cụ thể qua Calendar(identifier: .gregorian) và đặt múi giờ mong muốn qua thuộc tính timeZone.

DateFormatter và hiển thị ngày

DateFormatter là thành phần bắt buộc nếu Date cần được hiển thị cho người dùng. DateFormatter chuyển đổi Date thành chuỗi theo định dạng và ngôn ngữ địa phương được chỉ định. Chuyển đổi Date trực tiếp thành chuỗi qua String(describing:) trả về biểu diễn kỹ thuật với ngày tham chiếu và TimeInterval — không dành cho người dùng.

Cách tiếp cận cơ bản là sử dụng các kiểu được đặt sẵn dateStyletimeStyle. iOS hỗ trợ bốn kiểu: .short, .medium, .long, .full. Sự kết hợp giữa kiểu ngày và giờ cho phép cấu hình hiển thị linh hoạt. DateFormatter tự động áp dụng bản địa hóa: đối với ngôn ngữ địa phương tiếng Nga, ngày sẽ được hiển thị ở định dạng “21 tháng 7, 2026”.

ISO8601DateFormatter là bộ định dạng chuyên dụng cho ISO 8601, định dạng phổ biến nhất cho API và trao đổi dữ liệu. Bộ định dạng này hoạt động nhanh hơn DateFormatter và không phụ thuộc vào ngôn ngữ địa phương, khiến nó trở nên ưu tiên để tuần tự hóa ngày trong JSON.

swift
// Kiểu đặt sẵn
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let userString = formatter.string(from: Date())

// ISO 8601 cho API
let isoFormatter = ISO8601DateFormatter()
let apiString = isoFormatter.string(from: Date())

// Phân tích từ chuỗi
let parsed = isoFormatter.date(from: "2026-07-21T10:30:00Z")!

Khi làm việc với DateFormatter, điều quan trọng là nhớ đến hiệu suất: tạo một bộ định dạng mới là một thao tác tốn kém. Nên lưu bộ định dạng vào bộ nhớ đệm hoặc tạo một lần và tái sử dụng. Các thuộc tính của bộ định dạng cho phép đặt timeZone — mặc định, múi giờ hệ thống được sử dụng, nhưng đối với ngày máy chủ, thường cần TimeZone(identifier: “UTC”).

Ví dụ sử dụng Date

Hãy xem xét các kịch bản điển hình khi làm việc với Date trong ứng dụng iOS. Kịch bản đầu tiên là tính tuổi từ ngày sinh của người dùng. Kịch bản thứ hai là bộ đếm thời gian đếm ngược đến một sự kiện. Kịch bản thứ ba là nhóm bản ghi theo ngày để hiển thị dưới dạng các phần trong bảng.

Tính tuổi từ ngày sinh

Calendar.dateComponents với cờ [.year] tính toán sự khác biệt giữa hai ngày. Việc đặt đúng múi giờ rất quan trọng — nếu bạn không chỉ định timeZone trong Calendar, kết quả có thể chênh lệch một ngày do vượt qua nửa đêm ở múi giờ khác.

swift
func calculateAge(from birthDate: Date) -> Int {
    let calendar = Calendar.current
    let now = Date()
    let components = calendar.dateComponents(
        [.year], from: birthDate, to: now
    )
    return components.year ?? 0
}

Bộ đếm thời gian đếm ngược được triển khai bằng TimeInterval. Tính toán sự khác biệt giữa ngày mục tiêu và ngày hiện tại, lấy phần dư tính bằng giây và chuyển đổi thành ngày, giờ, phút. Để cập nhật định kỳ, hãy sử dụng Timer với khoảng thời gian 1 giây. Một ObservableObject với thuộc tính @Published cho phép SwiftUI tự động cập nhật giao diện.

Nhóm theo ngày được triển khai bằng từ điển với Date làm khóa. Calendar.dateInterval(of: .day, for:) chuẩn hóa ngày về đầu ngày, cho phép bạn nhóm các bản ghi thuộc cùng một ngày. Cách tiếp cận tương tự hoạt động cho tuần, tháng và năm — chỉ cần thay đổi thành phần trong dateInterval thành .weekOfYear hoặc .month.

Kịch bảnAPI chínhGhi chú
Tính tuổiCalendar.dateComponentsTính đến timeZone
Đếm ngượcDate.timeIntervalSinceTimer+Combine
Nhóm ngàyCalendar.dateIntervalChuẩn hóa theo ngày
Tuần tự hóa JSONISO8601DateFormatterLocale không ảnh hưởng

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

Date khác với chuỗi ngày như thế nào?

Date là biểu diễn nội bộ của thời gian không gắn với lịch và ngôn ngữ địa phương. Chuỗi là hiển thị được định dạng phụ thuộc vào cài đặt người dùng. Date có thể được so sánh, tuần tự hóa và xử lý toán học với độ chính xác 100%, trong khi biểu diễn chuỗi luôn yêu cầu phân tích qua bộ định dạng.

Tại sao Date không chứa thông tin múi giờ?

Date là dấu thời gian tuyệt đối (số giây từ ngày tham chiếu) không phụ thuộc vào múi giờ. Múi giờ là ngữ cảnh hiển thị. Cùng một Date ở UTC và ở Moscow đại diện cho cùng một thời điểm vật lý nhưng hiển thị dưới dạng thời gian lịch khác nhau.

Nên sử dụng kiểu nào để lưu trữ thời gian trong Core Data?

Date được Core Data hỗ trợ nguyên bản như một kiểu thuộc tính. Core Data tự động tuần tự hóa Date vào bộ lưu trữ. Đối với truy vấn có lọc theo ngày, hãy sử dụng NSPredicate với các toán tử so sánh — Core Data xử lý múi giờ chính xác ở cấp SQLite.

Sự khác biệt giữa Date và CFAbsoluteTime là gì?

CFAbsoluteTime là kiểu Core Foundation sử dụng cùng ngày tham chiếu (1 tháng 1 năm 2001). Date và CFAbsoluteTime có thể hoán đổi qua chuyển đổi trực tiếp. Date(timeIntervalSinceReferenceDate:) chấp nhận CFAbsoluteTime, và Date.timeIntervalSinceReferenceDate trả về CFAbsoluteTime.

Có thể sử dụng Date cho đo lường độ chính xác cao không?

Date có độ chính xác đến mili giây nhưng không đảm bảo độ chính xác nano giây do giới hạn phần cứng iOS/macOS. Đối với đo lường độ chính xác cao, hãy sử dụng mach_absolute_time hoặc ContinuousClock từ Swift 5.7+, hoạt động trên bộ đếm chu kỳ bộ xử lý phần cứng.

Tóm tắt

  • Date — kiểu giá trị Foundation để lưu trữ thời điểm tuyệt đối dưới dạng TimeInterval từ ngày tham chiếu 1 tháng 1 năm 2001.
  • TimeInterval (Double) — số giây giữa hai ngày, cung cấp so sánh và số học với Date.
  • CalendarDateComponents — cách duy nhất để trích xuất năm, tháng, ngày và các thành phần lịch khác từ Date.
  • DateFormatterISO8601DateFormatter — công cụ cần thiết để hiển thị và tuần tự hóa ngày ở định dạng chuỗi.
  • Date.distantPastDate.distantFuture — giá trị biên để lọc và sắp xếp trong thuật toán.
  • Date không chứa timezone — múi giờ được thêm ở cấp Calendar khi trích xuất thành phần để hiển thị.
  • Core Data và Codable hỗ trợ Date nguyên bản, đơn giản hóa việc lưu trữ và truyền ngày mà không cần chuyển đổi thêm.

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