feat(ios): implement calculateNextRunTime method

Implemented schedule calculation utility method:

calculateNextRunTime():
- Calculates next run time from cron expression or HH:mm time string
- Supports cron format: "minute hour * * *" (e.g., "30 9 * * *" = 9:30 AM daily)
- Supports time format: "HH:mm" (e.g., "09:30" = 9:30 AM daily)
- Handles same-day vs next-day scheduling
- Returns nextRunAt timestamp in milliseconds
- Fallback to 24 hours from now if parsing fails

calculateNextRunTimeFromSchedule():
- Private helper method for schedule parsing
- Parses both cron and time formats
- Uses Calendar for date calculations
- Handles timezone-aware calculations

iOS Adaptations:
- Uses Calendar.current for date calculations
- TimeInterval conversion (Date to milliseconds)
- Handles edge cases (invalid formats, past times)

Progress: 48/52 methods implemented (92% complete)
This commit is contained in:
Matthew Raymer
2025-11-11 02:20:50 -08:00
parent 9d5ffcfdb5
commit a8d92291e9

View File

@@ -858,6 +858,95 @@ public class DailyNotificationPlugin: CAPPlugin {
call.resolve()
}
/**
* Calculate next run time
*
* Calculates the next run time from a cron expression or HH:mm time string.
*
* Equivalent to Android's calculateNextRunTime method.
*/
@objc func calculateNextRunTime(_ call: CAPPluginCall) {
guard let schedule = call.getString("schedule") else {
call.reject("Schedule expression is required")
return
}
print("DNP-PLUGIN: Calculating next run time: schedule=\(schedule)")
let nextRunAt = calculateNextRunTimeFromSchedule(schedule)
let result: [String: Any] = [
"nextRunAt": Int64(nextRunAt)
]
print("DNP-PLUGIN: Next run time calculated: \(nextRunAt)")
call.resolve(result)
}
/**
* Calculate next run time from schedule string
*
* Supports both cron format ("minute hour * * *") and HH:mm format ("09:30").
*/
private func calculateNextRunTimeFromSchedule(_ schedule: String) -> TimeInterval {
let calendar = Calendar.current
let now = Date()
// Try to parse as HH:mm first
if schedule.contains(":") {
let parts = schedule.split(separator: ":")
if parts.count == 2,
let hour = Int(parts[0]),
let minute = Int(parts[1]),
hour >= 0 && hour <= 23,
minute >= 0 && minute <= 59 {
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: now)
components.hour = hour
components.minute = minute
components.second = 0
if let targetDate = calendar.date(from: components) {
// If time has passed today, schedule for tomorrow
if targetDate <= now {
if let tomorrow = calendar.date(byAdding: .day, value: 1, to: targetDate) {
return tomorrow.timeIntervalSince1970 * 1000
}
}
return targetDate.timeIntervalSince1970 * 1000
}
}
}
// Try to parse as cron expression: "minute hour * * *"
let parts = schedule.trimmingCharacters(in: .whitespaces).split(separator: " ")
if parts.count >= 2,
let minute = Int(parts[0]),
let hour = Int(parts[1]),
minute >= 0 && minute <= 59,
hour >= 0 && hour <= 23 {
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: now)
components.hour = hour
components.minute = minute
components.second = 0
if let targetDate = calendar.date(from: components) {
// If time has passed today, schedule for tomorrow
if targetDate <= now {
if let tomorrow = calendar.date(byAdding: .day, value: 1, to: targetDate) {
return tomorrow.timeIntervalSince1970 * 1000
}
}
return targetDate.timeIntervalSince1970 * 1000
}
}
// Fallback: 24 hours from now
print("DNP-PLUGIN: Invalid schedule format, defaulting to 24h from now")
return (now.addingTimeInterval(24 * 60 * 60).timeIntervalSince1970 * 1000)
}
// MARK: - Permission Methods
/**