DateComponents configuration for x months

I'm writing an app that needs to present repeating notifications on a schedule. The schedule will be every x months, where x is a number 1-72. So, it could be every 1 month, every 7 months, every 45 months, etc..

This is my first venture into user notifications, and I'm struggling with the DateComponents piece.

I see the documentation says DateComponents.month = a month or count of months. I interpret that to mean that the value could be an Int to represent a specific month (like 1 = January) or an Int to represent the number of months used for repetition (ex: 2 = every 2 months).

For my test, I wanted to manually create a user notification trigger that would repeat every 1 month on the first day of the month at 7:00am.

 var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.month = 1
dateComponents.day = 1
dateComponents.hour = 7

let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)

That didn't work as expected. It created the notification for January 1st at 7:00am, rather than the 1st of each month. I expect it would have repeated on the next calendar year.

What am I doing wrong? What is needed to achieve my goal of repeating every x months?

I see the documentation says DateComponents.month = a month or count of months. 

Where exactly did you read this ?

You may misinterpret it. AFAIU, this means that month may be the month value or a number of months to add to a date

Day, week, weekday, month, and year numbers are generally 1-based, but there may be calendar-specific exceptions. Ordinal numbers, where they occur, are 1-based. Some calendars may have to map their basic unit concepts into the year/month/week/day/… nomenclature. The particular values of the unit are defined by each calendar and are not necessarily consistent with values for that unit in another calendar.

Listing 4 shows how you can create a date components object that you can use to create the date where the year unit is 2004, the month unit is 5, and the day unit is 6 (in the Gregorian calendar this is May 6th, 2004). You can also use it to add 2004 year units, 5 month units, and 6 day units to an existing date. The value of weekday is undefined since it is not otherwise specified.

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtCalendars.html#//apple_ref/doc/uid/TP40003470

What is needed to achieve my goal of repeating every x months?

I would try to skip the month:

var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
// REMOVE THIS dateComponents.month = 1
dateComponents.day = 1
dateComponents.hour = 7


Hi @Claude31, here is where I read the definition of DateComponents.month. [https://developer.apple.com/documentation/foundation/datecomponents/1780256-month]

If I remove the month component, how would I configure for schedules that repeat on an unusual number of months? For example, a notification that repeats every 13 months - I'm not sure how to do that. Should it be DateComponents.day = 386 ?

Thanks. The explanation in doc is not very clear. But seems coherent with my understanding.

And the Xcode doc for UNCalendarNotificationTrigger confirms

Overview

Create a UNCalendarNotificationTrigger object when you want to schedule the delivery of a local notification at the specified date and time. You specify the temporal information using an NSDateComponents object, which lets you specify only the time values that matter to you. The system uses the provided information to determine the next date and time that matches the specified information.

Listing 1 creates a trigger that delivers its notification every morning at 8:30. The repeating behavior is achieved by specifying true for the repeats parameter when creating the trigger.

Listing 1 Creating a trigger that repeats at a specific time

var date = DateComponents()
date.hour = 8
date.minute = 30 
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)

 

I don't know how to do directly what you want.

A workaround would be to create multiple notifications, as described here:

https://stackoverflow.com/questions/50027190/uncalendarnotificationtrigger-every-3rd-day

@Claude31 thanks for your help. I think I'll have the app check for pending notifications, and make sure the next one is always scheduled. The user won't benefit from having multiple notifications queued for the same event - it only matters that the next scheduled notification appears when it should.

The code will be a bit more work, but it will get the job done.

Thanks again.

DateComponents configuration for x months
 
 
Q