[docs] Extensions.md: Date, Data & Files section

This commit is contained in:
Daniel Arantes Loverde
2026-08-29 19:28:35 -03:00
parent d16a42fddc
commit 4f6a83556d

View File

@@ -1389,7 +1389,288 @@ seen.insert(CGPoint(x: 1, y: 2))
## Date, Data & Files
<!-- batch 6 -->
<details>
<summary><b>Date</b> — components, comparisons, formatting, arithmetic, init</summary>
### 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>) -> 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)
```
</details>
<details>
<summary><b>Data</b> — JSON, hashing, hex, XOR, decoding</summary>
### `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: Codable & Sendable>() -> T?`
Decode JSON data to `T`, `nil` + logs on failure.
```swift
let user: User? = responseData.object()
```
</details>
<details>
<summary><b>URL</b></summary>
### `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"]
```
</details>
<details>
<summary><b>FileManager</b> — Documents-directory helpers</summary>
### `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.
</details>
<details>
<summary><b>UserDefaults</b> — Codable storage, common flags (<code>@MainActor</code>)</summary>
### `var isLoggedIn: Bool` / `var isFirstTimeOnApp: Bool`
Ready-made boolean flags (keys `"isLoggedIn"` / `"isFirstTimeOnApp"`), auto-`synchronize()` on set.
```swift
UserDefaults.standard.isFirstTimeOnApp = false
```
### `func set<T: Codable>(object: T, forKey key: String, usingEncoder: = JSONEncoder())`
Encode and store any `Codable` value.
### `func object<T: Codable>(_ 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.
</details>
## Encoding & Errors