DateComponents ساختاری از Foundation است که اجزای تاریخ تقویمی را به صورت فیلدهای جداگانه ذخیره میکند: سال، ماه، روز، ساعت، دقیقه، ثانیه و موارد دیگر. برخلاف Date که یک لحظه مطلق در زمان را نشان میدهد، DateComponents شامل مقادیر قابل خواندن برای انسان است که به تقویم و منطقه زمانی بستگی دارد. به گفته Apple Developer Documentation (2025)، DateComponents به عنوان یک رابط میانی بین Date و Calendar استفاده میشود – از طریق آن تاریخهای تقویمی استخراج و ساخته میشوند، محاسبات و جابجایی تاریخ بدون حسابدستی انجام میشوند.
نکات اصلی
DateComponents یک نوع مقداری Foundation است که برای ذخیره اجزای تقویمی زمان طراحی شده است. هر جزء به صورت یک فیلد اختیاری Int نشان داده میشود: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear و موارد دیگر.
تفاوت اصلی با Date وابستگی به تقویم است. Date زمان مطلق (تعداد ثانیهها از reference date) را ذخیره میکند، در حالی که DateComponents یک نمایش قابل خواندن برای انسان است که تنها در زمینه یک Calendar خاص معنا دارد. یک Date واحد میتواند در تقویمها و مناطق زمانی مختلف با DateComponents متفاوتی نمایش داده شود.
DateComponents یک نوع زمان مستقل نیست، بلکه یک ظرف داده است. برای تفسیر DateComponents به عنوان تاریخ، به Calendar نیاز است که بفهمد اجزاء چگونه با سیستم تقویم مرتبط هستند. Calendar.dateComponents(from: Date) استخراج اجزاء را انجام میدهد، Calendar.date(from: DateComponents) – مونتاژ معکوس را.
هر فیلد DateComponents اختیاری است (Int?) که برای کار با تاریخهای ناقص اساسی است. اگر فقط سال و ماه را مشخص کنید، Calendar فیلدهای缺失 را با مقادیر پیشفرض تکمیل میکند: روز = 1، ساعت = 0، دقیقه = 0. این برای ایجاد تاریخ شروع یک دوره مفید است – فقط باید اجزای مورد نظر را تعیین کنید.
هنگام مقایسه DateComponents با عملگر == فقط فیلدهای تنظیم شده (غیر nil) مقایسه میشوند. دو ساختار DateComponents با سال 2026 اما ماههای متفاوت، متفاوت در نظر گرفته میشوند. isEqual از NSObjectProtocol برای DateComponents استفاده نمیشود – DateComponents از NSObject ارث نمیبرد.
فیلدهای اصلی DateComponents شامل year, month, day, hour, minute, second, nanosecond هستند. هر فیلد یک مقدار عددی در واحد مربوطه ذخیره میکند: سال – 2026، ماه – 1..12، روز – 1..31، ساعت – 0..23، دقیقه – 0..59، ثانیه – 0..59. نانوثانیهها میتوانند مقادیر 0..999999999 را بپذیرند.
فیلدهای هفته – weekday (1..7، جایی که 1 = یکشنبه در تقویم گریگوری)، weekOfMonth، weekOfYear. این فیلدها به Calendar وابسته هستند و خارج از زمینه آن معنا ندارند. weekday به تنظیم firstWeekday تقویم بستگی دارد: در لوکال روسی هفته از دوشنبه شروع میشود (weekday = 2 در سیستم گریگوری)، در آمریکایی – از یکشنبه (weekday = 1).
فیلدهای تخصصی – quarter (1..4)، yearForWeekOfYear (سال مربوط به هفته)، isLeapMonth (پرچم منطقی برای ماههای کبیسه در تقویم عبری یا چینی). فیلدهای calendar و timeZone ارجاعاتی به اشیاء مربوطه را ذخیره میکنند که ساختار با آنها ایجاد شده است.
| دسته | فیلدها | محدوده |
|---|---|---|
| تقویمی | year, month, day | 1..∞, 1..12, 1..31 |
| زمانی | hour, minute, second, nanosecond | 0..23, 0..59, 0..59, 0..999999999 |
| هفتگی | weekday, weekOfMonth, weekOfYear | 1..7, 1..5, 1..53 |
| ویژه | quarter, yearForWeekOfYear | 1..4, وابسته |
هنگام استخراج اجزاء از طریق Calendar.dateComponents مهم است که برای کارایی فقط فیلدهای مورد نیاز را درخواست کنید. Calendar تمام فیلدهای درخواستی را در یک پاس استخراج میکند – این بسیار سریعتر از فراخوانی Calendar.component برای هر فیلد به صورت جداگانه است.
مقداردهی اولیه DateComponents – سادهترین روش: یک ساختار خالی ایجاد میکنید و فیلدهای مورد نیاز را پر میکنید. همه فیلدهای مشخص نشده به طور خودکار nil دریافت میکنند. تاریخ ایجاد شده از اجزای جزئی در مرحله مقداردهی اولیه اعتبارسنجی نمیشود – خطا فقط هنگام تبدیل به Date از طریق Calendar ممکن است رخ دهد.
مقداردهنده DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) امکان تنظیم همه فیلدها را در یک فراخوانی فراهم میکند. این مقداردهنده برای ایجاد تاریخ کامل از مقادیر آماده مفید است، اما به دلیل خوانایی به ندرت با بیش از 5-6 آرگومان استفاده میشود.
Calendar.dateComponents(_:from:) – روش اصلی برای دریافت DateComponents از یک Date موجود. آرگومان دوم مجموعه اجزایی است که باید استخراج شوند. Calendar محاسبات تقویمی را با در نظر گرفتن منطقه زمانی انجام میدهد و ساختاری را فقط با فیلدهای درخواستی برمیگرداند، بقیه فیلدها nil باقی میمانند.
import Foundation
// ایجاد از طریق مقداردهنده فیلدها
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21
// استخراج از Date
let now = Date()
let extracted = Calendar.current.dateComponents(
[.year, .month, .day],
from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")
// ایجاد از طریق مقداردهنده توسعهیافته
let birthday = DateComponents(
calendar: Calendar.current,
year: 1990, month: 5, day: 15
)
هنگام ایجاد DateComponents از طریق فیلدها به صورت دستی، همیشه Calendar را قبل از تبدیل به Date بررسی کنید. Calendar هنگام تبدیل date(from:) ممکن است nil برگرداند اگر اجزاء یک تاریخ ناموجود تشکیل دهند – مثلاً 31 فوریه یا 30 فوریه در سال غیرکبیسه. اعتبارسنجی تاریخ مسئولیت Calendar است، نه DateComponents.
Calendar.date(from:) – روش اصلی تبدیل DateComponents به Date. Calendar اجزاء را مطابق تقویم و منطقه زمانی خود تفسیر میکند. اگر برخی فیلدها تنظیم نشده باشند (nil)، Calendar از مقادیر پیشفرض استفاده میکند: روز = 1، ساعت = 0، دقیقه = 0، ثانیه = 0.
این متد یک Date اختیاری برمیگرداند – nil زمانی رخ میدهد که اجزاء با یکدیگر تناقض داشته باشند یا یک تاریخ نامعتبر تشکیل دهند. دلایل معمول nil: تاریخ ناموجود (32 ژانویه، 29 فوریه 2023)، فیلدهای متناقض (weekday=1، day=5 در یک مجموعه)، سال غیرممکن برای تقویم داده شده (سال 0 در تقویم گریگوری).
DateComponents با timeZone – اگر DateComponents شامل timeZone باشد، Calendar از آن هنگام تبدیل استفاده میکند. اگر timeZone مشخص نشده باشد، Calendar از timeZone جاری خود استفاده میکند. اگر Calendar.timeZone با منطقه زمانی مورد انتظار تاریخ مطابقت نداشته باشد، نتیجه ممکن است چند ساعت متفاوت باشد – اطمینان حاصل کنید که timeZone به صراحت در یکی از اشیاء تنظیم شده است.
let calendar = Calendar(identifier: .gregorian)
// ایجاد Date از DateComponents
var comps = DateComponents()
comps.year = 2026
comps.month = 12
comps.day = 25
comps.hour = 10
if let date = calendar.date(from: comps) {
print("Christmas: \(date)")
}
// ایجاد با مشخص کردن timeZone
calendar.timeZone = TimeZone(identifier: "UTC")!
let utcComps = DateComponents(
calendar: calendar, year: 2026, month: 7, day: 21,
hour: 12
)
let utcDate = calendar.date(from: utcComps)!
Calendar.dateComponents برای اختلاف تاریخها – سناریوی دیگری از استفاده DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) تفاوت در سالها، ماهها و روزها بین دو تاریخ را برمیگرداند. این روش صحیح محاسبه سن به جای تقسیم TimeInterval بر تعداد ثانیههای سال است، زیرا Calendar سالهای کبیسه را در نظر میگیرد.
Calendar – کلاس مرکزی که با DateComponents کار میکند. تمام عملیات استخراج، مونتاژ و مقایسه تاریخها از طریق Calendar انجام میشود. بدون Calendar، DateComponents فقط مجموعهای از اعداد بدون معنای زمانی است. Calendar به اجزاء تفسیر میدهد: تعیین میکند که ماه 2 فوریه است و weekday 2 دوشنبه است.
Calendar.nextDate و Calendar.enumerateDates – دو روش مبتنی بر DateComponents. nextDate(after: Date(), matching: DateComponents) تاریخ بعدی مطابق با اجزای مشخص شده را پیدا میکند – مثلاً دوشنبه بعد از امروز. enumerateDates(startingAfter:matching:matchingPolicy:using:) تمام تاریخهای مطابق با الگو را تا حد مشخص شده مرور میکند.
Calendar.dateInterval – متدی که DateInterval را برای جزء مشخص شده برمیگرداند. dateInterval(of: .month, for: Date()) شروع و پایان ماه جاری را برمیگرداند. در داخل این روش از DateComponents برای یافتن مرزهای دوره استفاده میکند: DateComponents با اولین و آخرین روز ماه ایجاد میکند، آنها را از طریق Calendar به Date تبدیل میکند.
let calendar = Calendar.current
// دوشنبه بعد
let nextMonday = calendar.nextDate(
after: Date(),
matching: DateComponents(weekday: 2),
matchingPolicy: .nextTime
)!
// تفاوت بین تاریخها بر حسب روز
let diff = calendar.dateComponents(
[.day], from: Date(), to: nextMonday
)
// بازه ماه
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end
MatchingPolicy – پارامتر مهم روشهای Calendar هنگام کار با DateComponents. strictPolicy نیاز به تطابق دقیق همه اجزاء دارد، nextTimePolicy تطابق بعدی در زمان را انتخاب میکند، nextTimePreservingSmallerComponents اجزای کوچکتر (دقیقه، ثانیه) را از تاریخ اصلی حفظ میکند. انتخاب سیاست بر نتیجه جستجوی تاریخ تأثیر میگذارد، به ویژه هنگام جابجایی با تغییر ساعت تابستانی/زمستانی.
سناریوهای عملی استفاده از DateComponents در برنامه را بررسی میکنیم. هر مثال یک وظیفه معمولی را نشان میدهد که توسعهدهنده iOS هنگام کار با تاریخهای تقویمی با آن مواجه میشود.
Calendar.nextDate با DateComponents(day: 1) اولین روز ماه بعد را پیدا میکند. Calendar به طور خودکار تعداد روزهای ماه جاری را تعیین میکند و به ماه بعد میرود. برای اعلانهای تکراری از enumerateDates یا Combine.Timer با کلید Calendar استفاده کنید.
func firstDayOfNextMonth(from date: Date) -> Date {
let calendar = Calendar.current
let comps = DateComponents(day: 1)
return calendar.nextDate(
after: date,
matching: comps,
matchingPolicy: .nextTime
)!
}
// محاسبه سن بر حسب سال
func ageInYears(from birthDate: Date) -> Int {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[.year], from: birthDate, to: Date()
)
return ageComponents.year ?? 0
}
// گروهبندی رویدادها بر اساس سال و ماه
func groupEventsByMonth(_ events: [Event]) -> [String: [Event]] {
let calendar = Calendar.current
return Dictionary(grouping: events) { event in
let comps = calendar.dateComponents(
[.year, .month], from: event.date
)
return "\(comps.year!)-\(comps.month!)"
}
}
محاسبه سن از طریق Calendar.dateComponents([.year], from:to:) – تنها روش صحیح که سالهای کبیسه را در نظر میگیرد. محاسبه مبتنی بر TimeInterval (ثانیه / 31536000) برای افراد متولد 29 فوریه خطا میدهد. Calendar به درستی تعیین میکند که آیا تولد در سال جاری بوده است یا خیر و سن دقیق را برمیگرداند.
گروهبندی بر اساس سال و ماه – وظیفه رایج برای صفحههای تاریخچه یا تقویم. DateComponents به عنوان کلید گروهبندی عمل میکند: سال و ماه را از تاریخ رویداد استخراج میکنید، یک کلید رشتهای تشکیل میدهید و از طریق Dictionary(grouping:) گروهبندی میکنید. برای نمایش از DateFormatter با الگوی «LLLL yyyy» برای نام ماه محلی استفاده کنید.
| وظیفه | متد Calendar | نقش DateComponents |
|---|---|---|
| اولین روز ماه | nextDate(after:matching:) | day: 1 |
| محاسبه سن | dateComponents(from:to:) | [.year] از تفاوت |
| گروهبندی تاریخها | dateComponents(_:from:) | year + month کلید |
| جستجوی روز هفته | nextDate(after:matching:) | weekday: N |
سوالات متداول
دلایل: تاریخ ناموجود (31 آوریل)، فیلدهای متناقض (weekday=1 با day=5)، ترکیب نامعتبر فیلدها برای تقویم انتخاب شده. Calendar سعی میکند اجزاء را در سیستم خود تفسیر کند – اگر ترکیب غیرممکن باشد، نتیجه nil است. همیشه هنگام تبدیل از guard let یا if let استفاده کنید.
بله، از طریق عملگر ==. DateComponents پروتکل Equatable را پیادهسازی میکند و همه فیلدها را مقایسه میکند. دو ساختار برابر هستند اگر همه فیلدهایشان برابر باشد (nil == nil درست در نظر گرفته میشود). برای مقایسه فقط بخشی از فیلدها – مجموعه یکسان را از طریق Calendar.dateComponents استخراج کنید.
Date – یک لحظه مطلق در زمان بدون وابستگی به تقویم. DateComponents – مجموعهای از اعداد قابل خواندن برای انسان (سال، ماه، روز) که فقط در زمینه Calendar معنا دارند. Date را میتوان مقایسه، تفریق و به ISO 8601 سریالیزه کرد. DateComponents – یک نمایش میانی برای تعامل با تقویم.
فقط فیلدهای year و month را تنظیم کنید و بقیه را nil بگذارید. هنگام تبدیل به Date از طریق Calendar.date(from:)، Calendar به طور خودکار روز = 1، ساعت = 0، دقیقه = 0 را تنظیم میکند. نتیجه – Date مربوط به اولین روز ماه مشخص شده در نیمهشب.
DateComponents اطلاعاتی درباره منطقه زمانی در فیلدها ذخیره نمیکند – مقادیر فیلدها (سال، ماه، روز) خود به timeZone که در آن استخراج شدهاند بستگی دارند. اجزای «21 جولای 2026 14:00 MSK» و «21 جولای 2026 10:00 UTC» یک Date را نشان میدهند اما فیلدهای DateComponents متفاوت هستند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید