Part of Swift with Copilot

Swift: What is the exact day of 2023-01-02

Sandy LaneSandy Lane

Video: Swift: What is the exact day of 2023-01-02 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

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.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.