diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift index b2666ccbc..901e39f1c 100644 --- a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift +++ b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift @@ -155,7 +155,7 @@ extension stat { var creationDate: Date { #if canImport(Darwin) - Date(seconds: TimeInterval(st_ctimespec.tv_sec), nanoSeconds: TimeInterval(st_ctimespec.tv_nsec)) + Date(seconds: TimeInterval(st_birthtimespec.tv_sec), nanoSeconds: TimeInterval(st_birthtimespec.tv_nsec)) #else Date(seconds: TimeInterval(st_ctim.tv_sec), nanoSeconds: TimeInterval(st_ctim.tv_nsec)) #endif diff --git a/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift b/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift index 44893c17e..982a77d2d 100644 --- a/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift +++ b/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift @@ -1093,6 +1093,24 @@ private struct FileManagerTests { } #endif + @Test(.enabled(if: isDarwin, "Birth time is only exposed on Darwin")) + func creationDateUsesBirthTime() async throws { + try await FilePlayground { + File("file") + }.test { fileManager in + let attrs1 = try fileManager.attributesOfItem(atPath: "file") + let creation1 = try #require(attrs1[.creationDate] as? Date) + + // Mutate metadata to advance ctime without touching birth time + try fileManager.setAttributes([.posixPermissions: 0o600], ofItemAtPath: "file") + + let attrs2 = try fileManager.attributesOfItem(atPath: "file") + let creation2 = try #require(attrs2[.creationDate] as? Date) + + #expect(creation1 == creation2, "Creation date should remain stable when metadata changes (uses birth time, not ctime)") + } + } + #if canImport(Darwin) @Test func SearchPathsWithoutExpandingTilde() async throws { for path in _DarwinSearchPaths(for: .libraryDirectory, in: .userDomainMask, expandTilde: false) {