iosswiftdate

Why does Date() and Calendar.current.startOfDay(for: Date()) produce different days?


I am trying to store Date data for user actions and set it to always be at start of the day no matter what time user performed the action i.e. User can perform 30 different actions and all of them are stored under the same Date.

However following produces weird results (it's 29th June at the moment of writing this), but for some reason calendars .startOfDay produces 28th?

print(Date())
print(Calendar.current.startOfDay(for: Date()))

// 2024-06-29 14:30:18 +0000
// 2024-06-28 21:00:00 +0000

Is there a way to ensure same day is respected?

Followup, I tried this alternative and it produces same result (28th)

let calendar = Calendar.current
var components = calendar.dateComponents([.year, .month, .day], from: date)
components.hour = 0
components.minute = 0
components.second = 0
return calendar.date(from: components) ?? .now

Solution

  • Date is a very poorly named type. It has nothing to do with dates, and its description (what you see when you print it) only makes things worse by hinting that it might. A Date is an instant in time, unrelated to location or calendar. It does not have a time zone (that requires a location). It is not "on a day" (that requires a calendar).

    .startOfDay is not returning the 28th. It's returning the 29th in your time zone. Note that the description that is printed is in UTC. You're likely running this in UTC+3.

    Your example of using .dateComponents is on the right path (this is basically what .startOfDay does). You just got in trouble by printing the Date again. Instead, you'd want to use a Calendar to fetch the component(s) you want:

    Calendar.current.component(.day, from: date)