Files
InvestmentTrackerApp/PortfolioJournal/Utilities/Extensions/Date+Extensions.swift
T
alexandrev-tibco 7cb5f92cf4 Remove Add Transaction feature and clean all related code
Deleted files:
- AddTransactionView.swift
- TransactionRepository.swift
- Transaction+CoreDataClass.swift

Cleaned files:
- SourceDetailViewModel: removed transactions published property,
  showingAddTransaction flag, transactionRepository dependency,
  addTransaction() and deleteTransaction() methods
- SourceDetailView: removed transactionsSection, TransactionRow struct,
  Add Transaction button from quickActions, sheet presentation
- InvestmentSource+CoreDataClass: removed transactions NSManaged property,
  transactionsArray, totalInvested, totalDividends, totalFees computed
  properties, and all transaction Core Data accessors
- SettingsViewModel: removed "Transaction" from resetAllData entity list
- SampleDataService: removed transactionRepository and sample transaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 23:04:03 +01:00

212 lines
6.2 KiB
Swift

import Foundation
extension Date {
// MARK: - Formatting
var shortDateString: String {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
return formatter.string(from: self)
}
var mediumDateString: String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
return formatter.string(from: self)
}
var longDateString: String {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
return formatter.string(from: self)
}
var monthYearString: String {
let formatter = DateFormatter()
formatter.dateFormat = "MMM yyyy"
return formatter.string(from: self)
}
var yearString: String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
return formatter.string(from: self)
}
var iso8601String: String {
ISO8601DateFormatter().string(from: self)
}
// MARK: - Components
var startOfDay: Date {
Calendar.current.startOfDay(for: self)
}
var startOfMonth: Date {
let components = Calendar.current.dateComponents([.year, .month], from: self)
return Calendar.current.date(from: components) ?? self
}
var startOfYear: Date {
let components = Calendar.current.dateComponents([.year], from: self)
return Calendar.current.date(from: components) ?? self
}
var endOfMonth: Date {
let startOfNextMonth = Calendar.current.date(
byAdding: .month,
value: 1,
to: startOfMonth
) ?? self
return Calendar.current.date(byAdding: .day, value: -1, to: startOfNextMonth) ?? self
}
// MARK: - Comparisons
func isSameDay(as other: Date) -> Bool {
Calendar.current.isDate(self, inSameDayAs: other)
}
func isSameMonth(as other: Date) -> Bool {
let selfComponents = Calendar.current.dateComponents([.year, .month], from: self)
let otherComponents = Calendar.current.dateComponents([.year, .month], from: other)
return selfComponents.year == otherComponents.year &&
selfComponents.month == otherComponents.month
}
func isSameYear(as other: Date) -> Bool {
Calendar.current.component(.year, from: self) ==
Calendar.current.component(.year, from: other)
}
var isToday: Bool {
Calendar.current.isDateInToday(self)
}
var isYesterday: Bool {
Calendar.current.isDateInYesterday(self)
}
var isThisMonth: Bool {
isSameMonth(as: Date())
}
var isThisYear: Bool {
isSameYear(as: Date())
}
// MARK: - Calculations
func adding(days: Int) -> Date {
Calendar.current.date(byAdding: .day, value: days, to: self) ?? self
}
func adding(months: Int) -> Date {
Calendar.current.date(byAdding: .month, value: months, to: self) ?? self
}
func adding(years: Int) -> Date {
Calendar.current.date(byAdding: .year, value: years, to: self) ?? self
}
func monthsBetween(_ other: Date) -> Int {
let components = Calendar.current.dateComponents([.month], from: self, to: other)
return components.month ?? 0
}
func daysBetween(_ other: Date) -> Int {
let components = Calendar.current.dateComponents([.day], from: self, to: other)
return components.day ?? 0
}
func yearsBetween(_ other: Date) -> Double {
let days = Double(daysBetween(other))
return days / 365.25
}
// MARK: - Relative Description
var relativeDescription: String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .abbreviated
return formatter.localizedString(for: self, relativeTo: Date())
}
var relativeDayDescription: String {
let calendar = Calendar.current
let days = calendar.dateComponents([.day], from: calendar.startOfDay(for: self), to: calendar.startOfDay(for: Date())).day ?? 0
if days == 0 { return String(localized: "date_today") }
if days == 1 { return "1d ago" }
if days < 31 { return "\(days)d ago" }
let months = calendar.dateComponents([.month], from: self, to: Date()).month ?? 0
if months < 12 { return "\(max(1, months))mo ago" }
let years = calendar.dateComponents([.year], from: self, to: Date()).year ?? 0
return "\(max(1, years))y ago"
}
var friendlyDescription: String {
if isToday {
return String(localized: "date_today")
} else if isYesterday {
return String(localized: "date_yesterday")
} else if isThisMonth {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, d"
return formatter.string(from: self)
} else if isThisYear {
let formatter = DateFormatter()
formatter.dateFormat = "MMM d"
return formatter.string(from: self)
} else {
return mediumDateString
}
}
}
// MARK: - Date Range
struct DateRange {
let start: Date
let end: Date
static var thisMonth: DateRange {
let now = Date()
return DateRange(start: now.startOfMonth, end: now)
}
static var lastMonth: DateRange {
let now = Date()
let lastMonth = now.adding(months: -1)
return DateRange(start: lastMonth.startOfMonth, end: lastMonth.endOfMonth)
}
static var thisYear: DateRange {
let now = Date()
return DateRange(start: now.startOfYear, end: now)
}
static var lastYear: DateRange {
let now = Date()
let lastYear = now.adding(years: -1)
return DateRange(start: lastYear.startOfYear, end: now.startOfYear.adding(days: -1))
}
static func month(containing date: Date) -> DateRange {
DateRange(start: date.startOfMonth, end: date.endOfMonth)
}
static func last(months: Int) -> DateRange {
let now = Date()
let start = now.adding(months: -months)
return DateRange(start: start, end: now)
}
func contains(_ date: Date) -> Bool {
date >= start && date <= end
}
}