From 4f6a83556d81edeee7695017ef7dcf64a403e61e Mon Sep 17 00:00:00 2001 From: Daniel Arantes Loverde Date: Sat, 29 Aug 2026 19:28:35 -0300 Subject: [PATCH] [docs] Extensions.md: Date, Data & Files section --- Documentation/Extensions.md | 283 +++++++++++++++++++++++++++++++++++- 1 file changed, 282 insertions(+), 1 deletion(-) diff --git a/Documentation/Extensions.md b/Documentation/Extensions.md index b2e0cd9..a5c4da5 100644 --- a/Documentation/Extensions.md +++ b/Documentation/Extensions.md @@ -1389,7 +1389,288 @@ seen.insert(CGPoint(x: 1, y: 2)) ## Date, Data & Files - +
+Date — components, comparisons, formatting, arithmetic, init + +### Calendar-component accessors +Read (and, where noted, write) individual components using the user's current calendar. + +| Property | Get | Set | +|---|---|---| +| `year` | ✅ | ✅ | +| `month` | ✅ | ✅ (clamped to valid range) | +| `day` | ✅ | ✅ (clamped) | +| `hour` / `minute` / `second` | ✅ | ✅ (clamped) | +| `nanosecond` / `millisecond` | ✅ | ✅ (clamped) | +| `weekday` / `weekOfMonth` / `weekOfYear` / `quarter` / `era` | ✅ | — | +| `calendar` | ✅ (`Calendar.current`) | — | + +```swift +var d = Date() +d.year = 2030 // shifts the date to 2030, keeping everything else +d.minute = 0 +Date().weekday // 1 = Sunday (Gregorian) +``` + +### Relative checks +`isInFuture`, `isInPast`, `isInToday`, `isInYesterday`, `isInTomorrow`, +`isInWeekend`, `isWorkday`, `isInCurrentWeek`, `isInCurrentMonth`, `isInCurrentYear`. + +```swift +someDate.isInToday // Bool +someDate.isInWeekend // Bool +``` + +### `func isInCurrent(_ component: Calendar.Component) -> Bool` +Same granularity check, for an arbitrary component. + +```swift +Date().isInCurrent(.year) // true +``` + +### `var iso8601String: String` / `var unixTimestamp: Double` +`yyyy-MM-dd'T'HH:mm:ss.SSS` + `Z` (GMT); seconds since 1970. + +```swift +Date().iso8601String // "2026-08-29T14:51:29.574Z" +``` + +### Rounding +`nearestFiveMinutes`, `nearestTenMinutes`, `nearestQuarterHour`, `nearestHalfHour`, `nearestHour` — all return a new `Date`. + +```swift +var d = Date(); d.minute = 44 +d.nearestFiveMinutes // :45 +d.nearestHour // rounds up because minute ≥ 30 +``` + +### `var yesterday: Date` / `var tomorrow: Date` +±1 day. + +### `func adding(_:value:) -> Date` / `mutating func add(_:value:)` +Add multiples of a calendar component. + +```swift +Date().adding(.day, value: 7) // one week later +var d = Date(); d.add(.month, value: -1) +``` + +### `func changing(_:value:) -> Date?` +Set one component to a specific value (validated; `nil` if out of range). + +```swift +Date().changing(.hour, value: 9) // 9am today +``` + +### `func beginning(of component:) -> Date?` / `func end(of component:) -> Date?` +Start / end instant of the enclosing `.day` / `.month` / `.year` / `.hour` / week, etc. + +```swift +Date().beginning(of: .month) // 1st, 00:00:00 +Date().end(of: .day) // 23:59:59 +``` + +### Differences +`secondsSince(_:)`, `minutesSince(_:)`, `hoursSince(_:)`, `daysSince(_:)` — signed `Double`. + +```swift +endDate.hoursSince(startDate) // e.g. 3.5 +``` + +### `func isBetween(_ start: Date, _ end: Date, includeBounds: Bool = false) -> Bool` +Range check. + +### `func isWithin(_ value: UInt, _ component: Calendar.Component, of date: Date) -> Bool` +Whether two dates are within N components of each other. + +```swift +a.isWithin(3, .day, of: b) // true if ≤ 3 days apart +``` + +### Formatting +| Method | Example output | +|---|---| +| `string(withFormat: String = "dd/MM/yyyy HH:mm")` | `"29/08/2026 14:30"` | +| `dateString(ofStyle: .medium)` | `"Aug 29, 2026"` | +| `dateTimeString(ofStyle: .short)` | `"8/29/26, 2:30 PM"` | +| `timeString(ofStyle: .short)` | `"2:30 PM"` | +| `dayName(ofStyle: .full / .threeLetters / .oneLetter)` | `"Saturday"` / `"Sat"` / `"S"` | +| `monthName(ofStyle: .full / .threeLetters / .oneLetter)` | `"August"` / `"Aug"` / `"A"` | + +```swift +Date().string(withFormat: "yyyy-MM-dd") // "2026-08-29" +Date().dayName(ofStyle: .threeLetters) // "Sat" +``` + +### Random dates +`static func random(in: Range) -> Date`, plus `ClosedRange` and +`using generator:` variants. + +```swift +Date.random(in: startDate...endDate) +``` + +### Initializers +- `init?(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:)` — every field defaults to "now". +- `init?(iso8601String:)` — parse `yyyy-MM-dd'T'HH:mm:ss.SSSZ`. +- `init(unixTimestamp:)` — seconds since 1970. +- `init?(integerLiteral:)` — parse a packed `yyyyMMdd` integer. + +```swift +Date(year: 2010, month: 1, day: 12) +Date(iso8601String: "2026-01-12T16:48:00.959Z") +Date(integerLiteral: 2026_12_25) +``` + +
+ +
+Data — JSON, hashing, hex, XOR, decoding + +### `var prettyJson: String?` +Pretty-printed JSON if the data is a valid JSON value. + +```swift +responseData.prettyJson +``` + +### `var toDictionay: [String: Any]?` +Parse a JSON object to a dictionary (note the spelling — `toDictionay`). + +### `var toHexString: String` / `func toHexadecimalString() -> String` +Lower-case hex representation of the bytes. + +```swift +Data([0x0f, 0xa0]).toHexString // "0fa0" +``` + +### `var bool: Bool` +`first != 0`. + +### `init?(hexString:)` +Parse a hex string (spaces allowed) to bytes; `nil` on an invalid nibble. + +```swift +Data(hexString: "0f a0") // 2 bytes +``` + +### `func SHA256() -> Data` / `func SHA512() -> Data` +CommonCrypto digests (empty `Data` if CommonCrypto is unavailable). + +```swift +Data("abc".utf8).SHA256().toHexString +``` + +### `func HMACSHA512(key: Data) -> Data` — *iOS 13+* +CryptoKit HMAC-SHA512. + +```swift +message.HMACSHA512(key: secret) +``` + +### `func XOR(with other: Data) -> Data` +Byte-wise XOR (result length = shorter of the two). + +```swift +a.XOR(with: pad) +``` + +### `static func MD5(string:) -> Data` — *iOS 13+* +MD5 of a string (insecure — legacy interop only). Returns the hex digest **as UTF-8 bytes**. + +```swift +Data.MD5(string: "Hello").toHexString +``` + +### `func object() -> T?` +Decode JSON data to `T`, `nil` + logs on failure. + +```swift +let user: User? = responseData.object() +``` + +
+ +
+URL + +### `var params: [String: String]` +Query items as a dictionary (missing values become `""`). + +```swift +URL(string: "https://x.com?a=1&b=2")!.params // ["a": "1", "b": "2"] +``` + +
+ +
+FileManager — Documents-directory helpers + +### `func createDirectory(_ directoryName: String) -> URL?` +Create (if missing) a folder under Documents; returns its URL. + +```swift +let dir = FileManager.default.createDirectory("cache") +``` + +### `func retrieveFile(_ directoryAndFile: String) -> URL` +Build a `file://` URL under Documents for the given relative path (no existence check). + +### `func convertToURL(path: String) -> URL?` +Directory URL under Documents, or `nil` if it can't be listed. + +### `func saveFileToDirectory(_ sourceURL: URL, toPathURL: URL) -> Bool` +`moveItem(at:to:)`, returning success. + +### `func saveImageToDirectory(_ imageWithPath: String, imagem: UIImage) -> Bool` — *UIKit only* +Write a `UIImage` as PNG to an absolute path. + +```swift +FileManager.default.saveImageToDirectory(path, imagem: photo) +``` + +### `func removeFile(_ directoryAndFile: String) -> Bool` +`removeItem(atPath:)`, returning success. + +### `func retrieveAllFilesFromDirectory(directoryName: String) -> [String]?` +File names in a Documents sub-folder (`.DS_Store` filtered out). + +### `func directoryExistsAtPath(_ path: String) -> Bool` +Exists **and** is a directory. + +
+ +
+UserDefaults — Codable storage, common flags (@MainActor) + +### `var isLoggedIn: Bool` / `var isFirstTimeOnApp: Bool` +Ready-made boolean flags (keys `"isLoggedIn"` / `"isFirstTimeOnApp"`), auto-`synchronize()` on set. + +```swift +UserDefaults.standard.isFirstTimeOnApp = false +``` + +### `func set(object: T, forKey key: String, usingEncoder: = JSONEncoder())` +Encode and store any `Codable` value. + +### `func object(_ type: T.Type, with key: String, usingDecoder: = JSONDecoder()) -> T?` +Decode a stored `Codable` value. + +```swift +UserDefaults.standard.set(object: user, forKey: "user") +let user = UserDefaults.standard.object(User.self, with: "user") +``` + +### `func removeSavedObject(forKey:) -> Bool` +Remove a value **only if it is a String**; returns whether it removed anything. + +### `func removeAllSaved()` +Wipe the app's entire persistent domain. + +### `func showEverything() -> [String: Any]` +Full `dictionaryRepresentation()` — handy for debugging. + +
## Encoding & Errors