/** * DailyNotificationDataConversions.swift * * Data type conversion helpers for Core Data operations * Handles conversions between Swift types and Core Data types, * especially for time (Date ↔ Long/Int64) and numeric types. * * @author Matthew Raymer * @version 1.0.0 * @created 2025-12-08 */ import Foundation import CoreData /** * Data conversion utilities for Core Data operations * * This module provides helper functions for converting between: * - Date ↔ Int64 (epoch milliseconds) * - Int ↔ Int32 * - Long ↔ Int64 * - Optional string handling */ class DailyNotificationDataConversions { // MARK: - Constants private static let TAG = "DNP-DATA-CONVERSIONS" // MARK: - Time Conversions (Section 6.1) /** * Convert epoch milliseconds (Int64) to Date * * @param epochMillis Milliseconds since epoch (1970-01-01 00:00:00 UTC) * @return Date object */ static func dateFromEpochMillis(_ epochMillis: Int64) -> Date { return Date(timeIntervalSince1970: Double(epochMillis) / 1000.0) } /** * Convert Date to epoch milliseconds (Int64) * * @param date Date object * @return Milliseconds since epoch (1970-01-01 00:00:00 UTC) */ static func epochMillisFromDate(_ date: Date) -> Int64 { return Int64(date.timeIntervalSince1970 * 1000.0) } /** * Convert optional epoch milliseconds to optional Date * * @param epochMillis Optional milliseconds since epoch * @return Optional Date object */ static func dateFromEpochMillis(_ epochMillis: Int64?) -> Date? { guard let millis = epochMillis else { return nil } return dateFromEpochMillis(millis) } /** * Convert optional Date to optional epoch milliseconds * * @param date Optional Date object * @return Optional milliseconds since epoch */ static func epochMillisFromDate(_ date: Date?) -> Int64? { guard let dateValue = date else { return nil } return epochMillisFromDate(dateValue) } // MARK: - Numeric Conversions (Section 6.2) /** * Convert Int to Int32 (for Core Data Integer 32) * * @param value Int value * @return Int32 value */ static func int32FromInt(_ value: Int) -> Int32 { return Int32(value) } /** * Convert Int32 to Int * * @param value Int32 value * @return Int value */ static func intFromInt32(_ value: Int32) -> Int { return Int(value) } /** * Convert Int64 to Int32 (with clamping if needed) * * @param value Int64 value * @return Int32 value (clamped if out of range) */ static func int32FromInt64(_ value: Int64) -> Int32 { if value > Int64(Int32.max) { return Int32.max } else if value < Int64(Int32.min) { return Int32.min } return Int32(value) } /** * Convert Int32 to Int64 * * @param value Int32 value * @return Int64 value */ static func int64FromInt32(_ value: Int32) -> Int64 { return Int64(value) } /** * Convert Long (Int64) to Int64 (no-op, but explicit) * * @param value Int64 value * @return Int64 value */ static func int64FromLong(_ value: Int64) -> Int64 { return value } /** * Convert Boolean to Bool (direct, but explicit) * * @param value Boolean value * @return Bool value */ static func boolFromBoolean(_ value: Bool) -> Bool { return value } // MARK: - String Conversions (Section 6.3) /** * Safely convert optional String to String * * @param value Optional String * @return String (empty string if nil) */ static func stringFromOptional(_ value: String?) -> String { return value ?? "" } /** * Safely convert String to optional String * * @param value String value * @return Optional String (nil if empty) */ static func optionalStringFromString(_ value: String) -> String? { return value.isEmpty ? nil : value } /** * Convert JSON dictionary to JSON string * * @param dict Dictionary to encode * @return JSON string or nil if encoding fails */ static func jsonStringFromDictionary(_ dict: [String: Any]?) -> String? { guard let dict = dict else { return nil } guard let data = try? JSONSerialization.data(withJSONObject: dict), let jsonString = String(data: data, encoding: .utf8) else { return nil } return jsonString } /** * Convert JSON string to dictionary * * @param jsonString JSON string to decode * @return Dictionary or nil if decoding fails */ static func dictionaryFromJsonString(_ jsonString: String?) -> [String: Any]? { guard let jsonString = jsonString, let data = jsonString.data(using: .utf8), let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil } return dict } }