How many days are there in the month of December in the year 2023?
Video: How many days are there in the month of December in the year 2023? by Taught by Celeste AI - AI Coding Coach
Swift with Copilot: How Many Days in December 2023?
Calendar.range(of: .day, in: .month, for: date)?.countreturns 31 for December, 28/29 for February, etc. Don't hardcode "30 days hath September..." — let the calendar handle it.
A practical date question that shows up in scheduling and reporting code.
The Copilot prompt
// How many days are in December 2023?
import Foundation
Copilot completes:
import Foundation
var components = DateComponents()
components.year = 2023
components.month = 12
let date = Calendar.current.date(from: components)!
let range = Calendar.current.range(of: .day, in: .month, for: date)!
print("December 2023: \(range.count) days")
// December 2023: 31 days
Walkthrough
Build a Date for the month
var components = DateComponents()
components.year = 2023
components.month = 12
let date = Calendar.current.date(from: components)!
DateComponents is "I want to specify some calendar fields, you fill in the rest." With just year and month, the resulting Date is the start of that month (Dec 1, midnight).
Calendar.current.date(from:) returns Date?. For valid components, it's never nil — but force-unwrap with ! is acceptable for hardcoded values.
Range of days in the month
let range = Calendar.current.range(of: .day, in: .month, for: date)!
range(of:in:for:) answers "what values can the smaller unit have within the larger unit, for this specific date?"
Here: "days within month, for December 2023" → range is 1..<32 (32 exclusive). The .count is 31.
For February 2024: 1..<30 → 29 days.
For February 2023: 1..<29 → 28 days.
Other ranges
let cal = Calendar.current
// Months in a year
cal.range(of: .month, in: .year, for: date)?.count
// 12
// Hours in a day (24, except DST transitions)
cal.range(of: .hour, in: .day, for: date)?.count
// 24
// Minutes in an hour
cal.range(of: .minute, in: .hour, for: date)?.count
// 60
Days in any month
import Foundation
func daysInMonth(year: Int, month: Int) -> Int {
var c = DateComponents()
c.year = year; c.month = month
let cal = Calendar.current
guard let date = cal.date(from: c),
let range = cal.range(of: .day, in: .month, for: date) else {
return 0
}
return range.count
}
print(daysInMonth(year: 2023, month: 12)) // 31
print(daysInMonth(year: 2024, month: 2)) // 29 — leap year
print(daysInMonth(year: 2023, month: 2)) // 28
print(daysInMonth(year: 2023, month: 4)) // 30
Generic, works for any year/month, handles leap years automatically.
Why use Calendar instead of a hard-coded array
// Hard-coded — works for Gregorian, fails for non-Gregorian calendars
let daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
This works for Gregorian and you have to special-case February. For Islamic, Hebrew, Persian, Buddhist calendars: different. Calendar handles them all:
let cal = Calendar(identifier: .islamic)
// ... rest of code unchanged ...
For business code dealing with international dates, always use Calendar.
Days between two dates
let cal = Calendar.current
let start = cal.date(from: DateComponents(year: 2023, month: 12, day: 1))!
let end = cal.date(from: DateComponents(year: 2024, month: 1, day: 1))!
let days = cal.dateComponents([.day], from: start, to: end).day!
print(days) // 31
dateComponents([.day], from:to:) returns the difference in those units.
For "days between any two dates":
func daysBetween(_ d1: Date, _ d2: Date) -> Int {
Calendar.current.dateComponents([.day], from: d1, to: d2).day ?? 0
}
First and last day of month
let cal = Calendar.current
let date = Date() // any date in the month
let comps = cal.dateComponents([.year, .month], from: date)
let firstDay = cal.date(from: comps)!
let range = cal.range(of: .day, in: .month, for: date)!
var lastComps = comps
lastComps.day = range.count
let lastDay = cal.date(from: lastComps)!
Useful for monthly reports.
Today's day-of-month
let cal = Calendar.current
let day = cal.component(.day, from: Date())
print("Today is the \(day)th")
component(_:from:) extracts a single component as Int.
Common stumbles
! on date(from:). Mostly safe for valid components, but for user input prefer guard let. Same for range(...).
Calendar identity. Calendar.current follows the user's settings. For storage/server, use Calendar(identifier: .gregorian) explicitly.
Time zone. DateComponents without time zone uses the calendar's default (usually current). For UTC consistency, set c.timeZone = TimeZone(identifier: "UTC") and use Calendar.current (or set the calendar's timeZone).
.range returns Range.count on the range.
Year 0. Gregorian has no year 0; Swift's calendar handles it correctly. For astronomical numbering, you'd need different math.
February 29 + 1 year. Calendar.date(byAdding:value:to:) returns Feb 28 (since 2025 has no Feb 29). Aware of leap years; you don't need to be.
What's next
Episode 12: Sum an array with reduce. Functional aggregation.
Recap
Calendar.range(of: .day, in: .month, for: date)?.count returns the number of days. Build the date with DateComponents and Calendar.current.date(from:). Works across calendars (Islamic, Hebrew, etc.). For "days between dates": dateComponents([.day], from: a, to: b).day. Don't hardcode "30 days hath September" — use the calendar.
Next episode: reduce.