I'm trying to pick a future date based on the current date. I want to use some sort of time interval ie: day, month, year etc.
I wrote code and recurrence function. I get the right number of recurring dates but they are all the same: Date.now See the resulting view below: iPhone preview screenshot
Can someone please tell me about Calendar and how to advance date and time correctly in Apple products?
import SwiftUI
import SwiftData
var payFrequencies = [ "once", "daily", "weekly", "biweekly", "monthly", "quarterly", "semiannually", "annually"]
struct PayPeriodCalculation: View {
enum Recurrence {
case daily, weekly, biweekly, monthly, quarterly, semiannually, annually
}
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var context
@State private var budgetPayDate: Date = .now
@State private var budgetPayPurpose: String = ""
@State private var budgetPayCounterpart: String = ""
@State private var budgetPayDirection: String = ""
@State private var budgetPayAmount: Double = 0.00
@State private var budgetPayMethod: String = "cash"
@State private var budgetPayFrequency: String = "once"
@State private var budgetPayControl: String = "at will"
@State private var budgetPayPurposeCategory: String = "miscellaneous"
@State private var budgetIsBudgetTransaction: Bool = true
var budgetTransaction: Transaction
func saveBudgetTransaction(budgetTransaction: Transaction, context: ModelContext) {
let trxToSave = Transaction(payDate: budgetPayDate, payPurpose: budgetPayPurpose, payCounterpart: budgetPayCounterpart, payDirection: budgetPayDirection, payAmount: budgetPayAmount, payMethod: budgetPayMethod, payFrequency: budgetPayFrequency, payControl: budgetPayControl, payPurposeCategory: budgetPayPurposeCategory, isBudgetTransaction: budgetIsBudgetTransaction)
context.insert(trxToSave)
}
func oneDay() -> TimeInterval {
let oneDay: TimeInterval = 24*60*60
return oneDay
}
func oneWeek() -> TimeInterval {
let oneWeek: TimeInterval = 7*24*60*60
return oneWeek
}
func twoWeeks() -> TimeInterval{
let twoWeeks: TimeInterval = 14*24*60*60
return twoWeeks
}
func oneMonth() -> TimeInterval {
let oneMonth: TimeInterval = 30*24*60*60
return oneMonth
}
func oneQuarter() -> TimeInterval {
let oneQuarter: TimeInterval = 3*30*24*60*60
return oneQuarter
}
func halfYear() -> TimeInterval {
let halfYear: TimeInterval = 6*30*24*60*60
return halfYear
}
func thisTrxSave() {
let budgetTransaction = Transaction(payDate: budgetPayDate, payPurpose: budgetPayPurpose, payCounterpart: budgetPayCounterpart, payDirection: budgetPayDirection, payAmount: budgetPayAmount, payMethod: budgetPayMethod, payFrequency: budgetPayFrequency, payControl: budgetPayControl, payPurposeCategory: budgetPayPurposeCategory, isBudgetTransaction: budgetIsBudgetTransaction)
saveBudgetTransaction(budgetTransaction: budgetTransaction, context: context)
}
func calculateNumberOfBudgetTransactions() -> [Date] {
var budgetPayDates: [Date] = []
switch budgetPayFrequency {
case "daily" :
thisTrxSave()
budgetPayDates.append(budgetPayDate)
for _ in 0...363 {
budgetPayDate = budgetPayDate + oneDay()
thisTrxSave()
budgetPayDates.append(budgetPayDate)
}
case "weekly" :
thisTrxSave()
budgetPayDates.append(budgetPayDate)
for _ in 0...50 {
budgetPayDate = budgetPayDate + oneWeek()
thisTrxSave()
budgetPayDates.append(budgetPayDate)
}
case "biweekly" :
thisTrxSave()
budgetPayDates.append(budgetPayDate)
for _ in 0...24 {
budgetPayDate = budgetPayDate + twoWeeks()
thisTrxSave()
budgetPayDates.append(budgetPayDate)
}
case "quarterly" :
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
for _ in 0...2 {
budgetPayDate = budgetPayDate + oneQuarter()
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
}
case "semiannually" :
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
budgetPayDate = budgetPayDate + halfYear()
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
case "annually" :
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
default :
// monthly
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
for _ in 0...10 {
budgetPayDate = budgetPayDate + oneMonth()
thisTrxSave()
budgetPayDates.append(budgetTransaction.payDate)
}
}
return budgetPayDates
}
var getDateParts = Date.getDateParts(.now)
var body: some View {
Form {
Section {
Section {
Picker("Recur", selection: $budgetPayFrequency){
ForEach(payFrequencies, id: \.self) {
Text($0)
}
}.frame(maxWidth: .infinity)
}
}
}
List {
VStack{
let budPayDates = calculateNumberOfBudgetTransactions()
if budgetPayFrequency != "once" {
Text("\(budPayDates.count)")
ForEach(budPayDates, id: \.self) {payDate in
Text("\(payDate)")
}
} else {
Text("nothing")
}
}
}
}
}
struct PayPeriodCalculationContainer: View {
@Query(sort: \Transaction.payPurpose) private var transactions: [Transaction]
// MARK: *BUDGET*
private var budgetTransactions: [Transaction] {
transactions.filter{ $0.isBudgetTransaction == true }
}
var body: some View {
PayPeriodCalculation(budgetTransaction: budgetTransactions[0])
}
}
#Preview {
NavigationStack {
PayPeriodCalculationContainer()
.modelContainer(previewContainer)
}
}
Dates are very hard to work with directly as dates are kept differently around the world. You need to be using Calendar when advancing date and time inside of Apple Frameworks.
example:
Calendar.autoupdatingCurrent.date(byAdding: .day, value: 1, to: .now, wrappingComponents: true)
Check out the docs here Calendar
The code above creates a new Date by adding 1 day to now using the calendar provided by the system for the users device.