Swift: What is the exact day of 2023-01-02
Video: Swift: What is the exact day of 2023-01-02 by Taught by Celeste AI - AI Coding Coach
Swift with Copilot: Exact Day of 2023-01-02
Parse a date string with
DateFormatter, then format it back as weekday. The "what day was that?" trick. Output: Monday.
You have a date as text. You want to know what day of the week it was. Two-step pipeline: parse, then format.
The Copilot prompt
// What day of the week was 2023-01-02?
import Foundation
Copilot completes:
import Foundation
let inputFormatter = DateFormatter()
inputFormatter.dateFormat = "yyyy-MM-dd"
let date = inputFormatter.date(from: "2023-01-02")!
let outputFormatter = DateFormatter()
outputFormatter.dateFormat = "EEEE"
let weekday = outputFormatter.string(from: date)
print("2023-01-02 was a \(weekday)")
// 2023-01-02 was a Monday
Walkthrough
Parse: string → Date
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: "2023-01-02")
formatter.date(from: String) returns Date? — optional, because parsing might fail.
The format string must match the input exactly:
| Input | Format |
|---|---|
2023-01-02 |
yyyy-MM-dd |
01/02/2023 |
MM/dd/yyyy |
Jan 2, 2023 |
MMM d, yyyy |
2023-01-02T15:30:00Z |
yyyy-MM-dd'T'HH:mm:ss'Z' |
Mismatch → nil.
Force-unwrap vs safe-unwrap
The Copilot example uses !:
let date = formatter.date(from: "2023-01-02")!
For a known-correct hardcoded string, that's fine. For user input or external data, don't:
guard let date = formatter.date(from: input) else {
print("Bad date: \(input)")
return
}
guard let ... else is Swift's safe unwrap. If nil, the else block runs and exits the scope.
Format: Date → weekday string
Same DateFormatter (with a different dateFormat), or a separate one:
let weekdayFormatter = DateFormatter()
weekdayFormatter.dateFormat = "EEEE"
let weekday = weekdayFormatter.string(from: date)
EEEE is full weekday name. EEE for abbreviated.
Stable parsing: en_US_POSIX
For machine-readable formats (ISO dates from APIs), set the locale to en_US_POSIX so the parser doesn't depend on user settings:
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(identifier: "UTC")
Without these, a Japanese user might have the parser interpret format tokens differently, or the time zone shift could move a midnight UTC date to "yesterday."
ISO8601DateFormatter
For ISO 8601 specifically, Swift has a dedicated formatter:
import Foundation
let iso = ISO8601DateFormatter()
iso.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let date = iso.date(from: "2023-01-02T15:30:45.123Z")
Faster and more reliable than custom format strings for ISO inputs.
Modern API: Date.FormatStyle / parse strategies (iOS 15+)
let date = try? Date.FormatStyle.iso8601
.year().month().day()
.parse("2023-01-02")
let weekday = date?.formatted(.dateTime.weekday(.wide))
Type-safe, no string format. iOS 15+, macOS 12+ only.
Calendar-based weekday
For just the weekday number (1-7), skip the formatter:
let cal = Calendar(identifier: .gregorian)
let weekday = cal.component(.weekday, from: date)
print(weekday)
// 2 (Monday in Gregorian; Sunday=1)
To get the name for a number:
let formatter = DateFormatter()
let names = formatter.standaloneWeekdaySymbols
print(names[weekday - 1])
// "Monday"
A reusable function
import Foundation
func weekday(of dateString: String) -> String? {
let parser = DateFormatter()
parser.dateFormat = "yyyy-MM-dd"
parser.locale = Locale(identifier: "en_US_POSIX")
parser.timeZone = TimeZone(identifier: "UTC")
guard let date = parser.date(from: dateString) else {
return nil
}
let formatter = DateFormatter()
formatter.dateFormat = "EEEE"
return formatter.string(from: date)
}
print(weekday(of: "2023-01-02") ?? "invalid")
// Monday
Returns String? — nil on bad input. Caller uses ?? for default.
Common stumbles
Format mismatch returns nil. dateFormat = "yyyy-MM-dd" but input is "01/02/2023" → nil. Match exactly.
Locale issues. Without en_US_POSIX, behaviors like AM/PM parsing vary. Always set for machine-readable formats.
Time zones. "2023-01-02" parsed in user's TZ. To force UTC: formatter.timeZone = TimeZone(identifier: "UTC").
! on user input. Crash. Use guard let or if let.
Reusing one formatter for parse + format. Works, but mutating dateFormat between calls is error-prone. Use two formatters.
yyyy vs YYYY. Lowercase y is calendar year (what you want). Uppercase Y is "week-of-year year" — different at year boundaries. Use lowercase.
What's next
Episode 7: Reverse a string word by word. Splitting and joining.
Recap
DateFormatter parses string → Date (optional). Set dateFormat, locale = en_US_POSIX, timeZone = UTC for stable parsing. Then format with dateFormat = "EEEE" for weekday name. For ISO 8601, use ISO8601DateFormatter. Modern API: Date.FormatStyle. Always safely unwrap parse results — guard let, not !.
Next episode: word-by-word reverse.