How to Find File Creation Date in Linux: Complete Technical Guide
Linux does not natively expose file birth time through most standard user-space tools, but the underlying data often exists — the challenge is knowing exactly where to look and which filesystem and kernel version you are running. On ext4, btrfs, xfs, and tmpfs filesystems with Linux kernel 4.11+, true birth timestamps (crtime) are stored in the inode and are retrievable through specific low-level utilities. On older filesystems or kernels, you must use a combination of inode metadata, system logs, and filesystem-specific debuggers to approximate creation time.
This guide covers every reliable method available in 2024, including their technical prerequisites, exact command syntax, known failure modes, and when each approach is appropriate for production system administration.
Why Linux File Creation Time Is Not Straightforward
Every file in Linux is described by an inode — a data structure storing metadata such as permissions, ownership, size, and timestamps. The POSIX standard historically defined three timestamps:
- atime — last access time
- mtime — last modification time (content changed)
- ctime — inode change time (metadata or content changed)
Critically, ctime is not creation time. This is one of the most common misconceptions among administrators migrating from Windows environments. ctime updates whenever permissions change, ownership changes, or the file is renamed — it has nothing to do with when the file was first created.
True creation time, known as birth time or crtime, was added to the ext4 inode structure and is exposed via the statx() system call introduced in Linux kernel 4.11. However, many distributions shipped tools that did not surface this data until relatively recently, which is why the confusion persists.
Filesystem and Kernel Prerequisites
Before attempting any method, verify your environment:
# Check kernel version
uname -r
# Check filesystem type for a specific path
df -T /path/to/your/file
# Check filesystem mount options
findmnt -o TARGET,FSTYPE,OPTIONS /path/to/your/file| Filesystem | Birth Time Stored | Retrieval Method | Notes |
|---|---|---|---|
| ext4 | Yes | stat, debugfs | Requires kernel 4.11+ for stat |
| btrfs | Yes | stat | Full support, no extra tools needed |
| xfs | Yes (kernel 5.10+) | stat | Requires xfs_db on older kernels |
| tmpfs | No | N/A | In-memory, no persistent inode |
| ext2 / ext3 | No | N/A | No birth time field in inode |
| NFS | Depends on server | stat | Inherited from server filesystem |
| FAT32 / exFAT | Yes | stat | Stored natively in directory entry |
If you are running a VPS Hosting environment, the underlying filesystem is almost always ext4 or btrfs, meaning birth time data is available — you just need the right tools to surface it.
Method 1: Using the stat Command (Recommended Starting Point)
The stat command is the correct first tool to try. On modern systems with kernel 4.11+ and a supporting filesystem, it will directly display the Birth field.
stat /path/to/your/fileExample output on a modern ext4 system:
File: /home/deploy/app/config.yml
Size: 4096 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 2883591 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ deploy) Gid: ( 1000/ deploy)
Access: 2024-03-15 09:22:14.812345678 +0000
Modify: 2024-03-10 14:05:33.123456789 +0000
Change: 2024-03-10 14:05:33.123456789 +0000
Birth: 2024-03-08 11:47:02.987654321 +0000If the Birth field shows - (a dash) instead of a timestamp, one of the following is true:
- The filesystem does not store birth time (ext2/ext3)
- The kernel is older than 4.11
- The
statbinary is outdated and does not callstatx() - The file was created before the filesystem was upgraded from ext3 to ext4
Extracting only the birth timestamp programmatically:
stat --format="%w" /path/to/your/file
# Returns '-' if unavailable, or ISO 8601 timestamp if available
stat --format="%W" /path/to/your/file
# Returns Unix epoch integer (0 if unavailable)The %W format returning 0 is a reliable programmatic check for whether birth time is genuinely unavailable.
Method 2: Using debugfs for ext4 Filesystems
debugfs is the definitive low-level tool for ext4 inode inspection. It reads the raw inode structure and can expose crtime even when stat fails due to an older userspace binary.
Step 1: Identify the inode number of your file
ls -i /path/to/your/file
# Output example: 2883591 /path/to/your/fileStep 2: Identify the block device hosting the filesystem
df /path/to/your/file
# Output shows the device, e.g., /dev/sda1 or /dev/vda1Step 3: Query debugfs with the inode number
sudo debugfs -R 'stat <2883591>' /dev/vda1Replace 2883591 with your actual inode number and /dev/vda1 with your actual device. The output will include a crtime field:
Inode: 2883591 Type: regular Mode: 0644 Flags: 0x80000
Generation: 3421897654 Version: 0x00000000:00000001
User: 1000 Group: 1000 Project: 0 Size: 4096
File ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x65ee1f4d:1d4c5800 -- Sun Mar 10 14:05:33 2024
atime: 0x65f4a1ae:c6b5c000 -- Fri Mar 15 09:22:14 2024
mtime: 0x65ee1f4d:1d4c5800 -- Sun Mar 10 14:05:33 2024
crtime: 0x65e4b2c6:eb851400 -- Thu Mar 08 11:47:02 2024
Size of extra inode fields: 28Important operational note: debugfs opens the filesystem in read-only mode by default when using -R, but you should still avoid running it on a heavily active filesystem without first unmounting or using a snapshot. On production Dedicated Servers, always prefer running debugfs against a filesystem snapshot or a quiesced volume to avoid reading inconsistent inode state.
Alternative syntax using filename directly:
sudo debugfs -R "stat /path/to/your/file" /dev/vda1Note that the path here must be relative to the filesystem root, not the system root. If /dev/vda1 is mounted at /, then /path/to/your/file works as-is.
Method 3: Using xfs_db for XFS Filesystems
On XFS filesystems (common on RHEL/CentOS/Rocky Linux systems), the equivalent of debugfs is xfs_db.
# Get inode number first
ls -i /path/to/your/file
# Unmount or use read-only mode
sudo xfs_db -r /dev/sda1 -c "inode <inode_number>" -c "print"Look for the v3.crtime field in the output. XFS v5 (the default since RHEL 7) stores birth time natively. XFS v4 does not.
Method 4: Using btrfs Subvolume and File Inspection
On btrfs, stat with a modern kernel is sufficient and fully reliable. However, for deeper inspection:
sudo btrfs inspect-internal dump-tree /dev/sdb | grep -A 20 "inode ref"For practical purposes on btrfs, the stat output Birth field is authoritative.
Method 5: Querying statx() Directly via Python
When shell tools give inconsistent results, calling the statx() syscall directly from Python provides a definitive answer:
import os
import stat
result = os.stat("/path/to/your/file")
# st_birthtime is available on systems where statx() returns it
if hasattr(result, 'st_birthtime'):
import datetime
birth = datetime.datetime.fromtimestamp(result.st_birthtime)
print(f"Birth time: {birth}")
else:
print("Birth time not available on this platform/filesystem")For more precise nanosecond resolution, use the ctypes module to call statx() directly — this is useful in forensic scripts where timestamp precision matters.
Method 6: Searching System Logs
When filesystem-level birth time is unavailable — for example, on ext3 filesystems or files that predate a filesystem conversion — system logs become the fallback.
Search systemd journal:
journalctl --since="2024-01-01" | grep "your_filename"Search traditional syslog:
grep "your_filename" /var/log/syslog
grep "your_filename" /var/log/messagesSearch audit log (if auditd is configured):
sudo ausearch -f /path/to/your/fileThe audit subsystem is the most reliable log-based method because it records openat(), creat(), and rename() syscalls with precise timestamps. However, it must be configured in advance — you cannot retroactively audit file creation events that occurred before auditd was enabled.
Enable file creation auditing for a directory:
sudo auditctl -w /var/www/html -p w -k web_file_creationThis watches /var/www/html for write events, tagging them with the key web_file_creation for easy retrieval.
Method 7: Using ls — Understanding Its Limitations
The ls command is frequently cited in guides as a way to check creation time, but this requires significant qualification.
ls -l --time=birth /path/to/your/file
ls -l --time=creation /path/to/your/file # synonym on some systemsCritical caveat: ls --time=birth only works on GNU coreutils 8.25+ and only when the underlying filesystem and kernel support birth time. If birth time is unavailable, ls silently falls back to mtime without any warning. This silent fallback is a significant operational hazard — you may believe you are reading creation time while actually reading modification time.
Always verify with stat first. Use ls for display purposes only, not for scripted logic.
# Safer: check stat output explicitly before relying on ls
BIRTH=$(stat --format="%W" /path/to/your/file)
if [ "$BIRTH" -eq 0 ]; then
echo "Birth time unavailable, falling back to mtime"
stat --format="%y" /path/to/your/file
else
echo "Birth time: $(date -d @$BIRTH)"
fiMethod Comparison and Decision Matrix
| Method | Accuracy | Filesystem Requirement | Root Required | Works Without Prior Setup |
|---|---|---|---|---|
stat (Birth field) | Exact | ext4, btrfs, xfs v5 | No | Yes |
debugfs | Exact | ext4 only | Yes | Yes |
xfs_db | Exact | XFS v5 only | Yes | Yes |
statx() via Python | Exact | Same as stat | No | Yes |
journalctl / syslog | Approximate | Any | No | Depends on log retention |
auditd | Exact | Any | Yes (setup) | No (requires prior config) |
ls --time=birth | Exact or silent fallback | ext4, btrfs, xfs v5 | No | Yes (unreliable fallback) |
Real-World Edge Cases and Pitfalls
File copied vs. moved: When a file is copied (cp), the destination gets a new inode with a new birth time. When a file is moved within the same filesystem (mv), the inode is preserved and birth time is unchanged. Cross-filesystem mv behaves like cp + rm, creating a new inode.
Filesystem conversion from ext3 to ext4: Files that existed before the conversion will have a crtime of zero in their inode, because ext3 never populated that field. debugfs will show crtime: 0x00000000:00000000. In this case, mtime at the time of conversion is the best approximation.
Docker and container environments: Container filesystems (overlay2, aufs) may not propagate birth time correctly. Files inside containers may show birth time as the container start time rather than actual file creation time.
NFS mounts: Birth time availability depends entirely on the NFS server's filesystem. The client has no independent birth time data.
Backup restoration: Files restored from tar archives typically get a new inode and thus a new birth time reflecting the restoration date, not the original creation date. Use tar --preserve-permissions and check mtime for the closest approximation to original creation time.
For administrators managing web applications on VPS with cPanel, file timestamp integrity is particularly important during migrations — always verify inode metadata after restoring from backup.
Enabling Birth Time Support: Filesystem Tuning
If you are setting up a new server and want guaranteed birth time support, ensure the following:
For ext4 — verify inode size is 256 bytes (required for crtime field):
sudo tune2fs -l /dev/vda1 | grep "Inode size"
# Should return: Inode size: 256If inode size is 128, birth time cannot be stored. This requires reformatting — it cannot be changed on an existing filesystem.
Create new ext4 filesystem with 256-byte inodes (default since e2fsprogs 1.41):
sudo mkfs.ext4 -I 256 /dev/vdb1Verify kernel supports statx():
uname -r # Must be >= 4.11When provisioning new infrastructure — whether Shared Web Hosting or bare-metal Dedicated Servers — confirm the filesystem inode size before deploying applications that depend on birth time metadata.
Practical Checklist for Determining File Creation Time
Use this decision tree when you need to find a file's creation date:
- Check kernel version first:
uname -r— must be 4.11+ forstatto show Birth - Check filesystem type:
df -T /path/to/file— ext4, btrfs, or xfs v5 required - Run
staton the file: If Birth field shows a timestamp, you have your answer - If Birth shows
-: Rundebugfs(ext4) orxfs_db(xfs) with the inode number - If filesystem is ext3 or ext2: Fall back to
mtimeas best approximation - If you need audit-grade accuracy going forward: Configure
auditdnow - If the file was recently created: Check
journalctlfor corroborating log entries - In scripts: Always check
stat --format="%W"for0before trusting the value - After migrations or restores: Treat birth time as suspect; cross-reference with
mtimeand backup manifests
For environments where file integrity and timestamp accuracy are security requirements — such as applications handling SSL Certificates and cryptographic key files — combining auditd with filesystem-level birth time gives you a two-layer verification approach that is defensible in security audits.
FAQ
Does Linux always store file creation time?
No. Only filesystems with 256-byte inodes (ext4, btrfs, xfs v5) store birth time. ext2 and ext3 do not have a birth time field in their inode structure. Even on supporting filesystems, files created before a filesystem upgrade from ext3 to ext4 will have a zero birth time.
What is the difference between ctime and birth time in Linux?
ctime is the inode change time — it updates whenever file metadata (permissions, ownership, link count) or content changes. It is not creation time. Birth time (crtime) is set once when the file is first created and never changes. Many administrators confuse these two, which leads to incorrect audit conclusions.
Can I recover file creation time after it has been lost?
If the inode's crtime field is zero or the filesystem does not support it, the original creation time cannot be recovered from the filesystem alone. Your best options are: check auditd logs if they were configured, search application logs, or consult backup manifests that recorded file metadata at backup time.
Why does ls --time=creation show the wrong time?
ls silently falls back to mtime when birth time is unavailable, without displaying any warning. This is a known behavioral issue in GNU coreutils. Always use stat --format="%W" to programmatically verify whether birth time is genuinely available before relying on ls output.
Which command gives the most reliable file creation time on ext4?
debugfs -R 'stat <inode_number>' /dev/device is the most reliable method on ext4 because it reads the raw inode structure directly, bypassing any userspace tool limitations. For day-to-day use on kernel 4.11+, stat filename with the Birth field is equivalent and far more convenient.
