The Problem
Sometimes you need to create a file with a timestamp from the past - perhaps for testing backup systems, simulating old logs, or recreating a timeline of events. The natural instinct might be to change the system date, touch the file, then change it back. But that approach has serious problems:
- Requires root privileges
- Can confuse running services and daemons
- Messes up log timestamps
- Can trigger cron jobs at wrong times
- May corrupt databases that depend on timestamps
- Could cause SSL certificate validation issues
The Solution: Use the touch command's -d or -t options to set timestamps directly - no system clock manipulation needed!
Complete Script - backdate-touch.sh
backdate-touch.sh
#!/bin/bash
# backdate-touch.sh - Create or modify file with backdated timestamp
#
# Usage: ./backdate-touch.sh filename days_back
# Example: ./backdate-touch.sh myfile.txt 30
#
# This script creates or modifies a file with a timestamp from N days ago
# WITHOUT changing the system clock - safe for non-root users!
# Check for correct number of arguments
if [ $# -ne 2 ]; then
echo "Usage: $0 <filename> <days_back>"
echo ""
echo "Examples:"
echo " $0 oldfile.txt 30 # Create file dated 30 days ago"
echo " $0 lastweek.log 7 # Create file dated 7 days ago"
echo " $0 lastyear.dat 365 # Create file dated 1 year ago"
exit 1
fi
FILENAME="$1"
DAYS_BACK="$2"
# Validate that days_back is a number
if ! [[ "$DAYS_BACK" =~ ^[0-9]+$ ]]; then
echo "Error: days_back must be a positive number"
exit 1
fi
# Calculate the date N days ago in touch format (YYYYMMDDhhmm.ss)
BACKDATE=$(date -d "$DAYS_BACK days ago" "+%Y%m%d%H%M.%S")
# Check if date command succeeded
if [ $? -ne 0 ]; then
echo "Error: Unable to calculate date"
exit 1
fi
# Touch the file with that date
touch -t "$BACKDATE" "$FILENAME"
# Check if touch succeeded
if [ $? -eq 0 ]; then
echo "✓ Success!"
echo ""
echo "File: $FILENAME"
echo "Timestamp set to: $(date -d "$DAYS_BACK days ago" "+%Y-%m-%d %H:%M:%S")"
echo "That was $DAYS_BACK days ago"
echo ""
echo "File details:"
ls -lh "$FILENAME"
else
echo "Error: Failed to create/modify file"
exit 1
fi
Quick Command
# Simple version using -d option (often more intuitive) touch -d "30 days ago" myfile.txt # With specific date touch -d "2024-12-15" myfile.txt # With relative dates touch -d "last Monday" myfile.txt touch -d "2 weeks ago" myfile.txt touch -d "6 months ago" myfile.txt
backdate-advanced.sh
#!/bin/bash
# backdate-advanced.sh - Advanced file backdating with multiple options
show_usage() {
cat <<EOF
Usage: $0 [OPTIONS] filename
Create or modify a file with a backdated timestamp.
OPTIONS:
-d DAYS Set date to DAYS days ago (default: 7)
-s DATE Set specific date (format: YYYY-MM-DD or "2 weeks ago")
-k Keep existing file content (don't truncate)
-v Verbose output
-h Show this help message
EXAMPLES:
$0 -d 30 oldfile.txt # 30 days ago
$0 -s "2024-12-25" christmas.log # Specific date
$0 -s "last year" old.dat # Relative date
$0 -d 7 -k existing.txt # Keep existing content
$0 -d 90 -v backup.tar # Verbose output
EOF
exit 1
}
# Default values
DAYS_BACK=""
SPECIFIC_DATE=""
KEEP_CONTENT=false
VERBOSE=false
FILENAME=""
# Parse options
while getopts "d:s:kvh" opt; do
case $opt in
d)
DAYS_BACK="$OPTARG"
;;
s)
SPECIFIC_DATE="$OPTARG"
;;
k)
KEEP_CONTENT=true
;;
v)
VERBOSE=true
;;
h)
show_usage
;;
\?)
echo "Invalid option: -$OPTARG" >&2
show_usage
;;
esac
done
shift $((OPTIND-1))
FILENAME="$1"
# Validate filename provided
if [ -z "$FILENAME" ]; then
echo "Error: No filename provided"
show_usage
fi
# Determine which date method to use
if [ -n "$SPECIFIC_DATE" ]; then
DATE_STRING="$SPECIFIC_DATE"
[ "$VERBOSE" = true ] && echo "Using specific date: $SPECIFIC_DATE"
elif [ -n "$DAYS_BACK" ]; then
DATE_STRING="$DAYS_BACK days ago"
[ "$VERBOSE" = true ] && echo "Using relative date: $DAYS_BACK days ago"
else
DATE_STRING="7 days ago"
[ "$VERBOSE" = true ] && echo "Using default: 7 days ago"
fi
# Create/modify file
if [ "$KEEP_CONTENT" = true ] && [ -f "$FILENAME" ]; then
[ "$VERBOSE" = true ] && echo "Preserving existing file content"
# Just change timestamp, don't truncate
touch -d "$DATE_STRING" "$FILENAME"
else
[ "$VERBOSE" = true ] && echo "Creating new file or truncating existing"
# Create new or truncate existing
: > "$FILENAME"
touch -d "$DATE_STRING" "$FILENAME"
fi
# Check result
if [ $? -eq 0 ]; then
echo "✓ Success: $FILENAME"
# Get the actual timestamp that was set
ACTUAL_DATE=$(stat -c %y "$FILENAME" 2>/dev/null || stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$FILENAME" 2>/dev/null)
if [ -n "$ACTUAL_DATE" ]; then
echo "Timestamp: $ACTUAL_DATE"
fi
[ "$VERBOSE" = true ] && ls -lh "$FILENAME"
else
echo "✗ Error: Failed to create/modify file"
exit 1
fi
Usage Examples
Basic Script Usage
# Make script executable chmod +x backdate-touch.sh # Create file dated 30 days ago ./backdate-touch.sh oldfile.txt 30 # Create file dated 7 days ago ./backdate-touch.sh lastweek.log 7 # Create file dated 1 year ago ./backdate-touch.sh lastyear.dat 365
Advanced Script Usage
# Using specific dates ./backdate-advanced.sh -s "2024-01-01" newyear.txt # Using relative dates ./backdate-advanced.sh -s "last Monday" weekly.log ./backdate-advanced.sh -s "3 months ago" quarterly.dat # Keep existing file content ./backdate-advanced.sh -d 60 -k important.txt # Verbose output ./backdate-advanced.sh -d 90 -v backup.tar
Direct touch Command Examples
# Simple relative dates touch -d "30 days ago" file1.txt touch -d "2 weeks ago" file2.txt touch -d "6 months ago" file3.txt touch -d "1 year ago" file4.txt # Specific dates touch -d "2024-12-25" christmas.log touch -d "2024-01-01 00:00:00" newyear.txt # Relative date expressions touch -d "last Monday" weekly-report.txt touch -d "yesterday" yesterday.log touch -d "last year" old-backup.tar
Using -t Option (Precise Timestamp Format)
# Format: [[CC]YY]MMDDhhmm[.ss] # Examples: # January 15, 2024, 14:30:00 touch -t 202401151430.00 file.txt # December 25, 2024, 12:00:00 touch -t 202412251200.00 christmas.log # Using date command to generate format TIMESTAMP=$(date -d "30 days ago" "+%Y%m%d%H%M.%S") touch -t "$TIMESTAMP" oldfile.txt
Understanding Touch Options
| Option | Description | Example |
|---|---|---|
| -d STRING | Use date described by STRING (human-readable) | touch -d "3 days ago" file.txt |
| -t STAMP | Use [[CC]YY]MMDDhhmm[.ss] format | touch -t 202401151430.00 file.txt |
| -r FILE | Use timestamp from another FILE | touch -r oldfile.txt newfile.txt |
| -c | Do not create file if it doesn't exist | touch -c -d "yesterday" file.txt |
| -a | Change only access time | touch -a file.txt |
| -m | Change only modification time | touch -m file.txt |
Real-World Use Cases
Create files with various ages to test whether your backup system correctly identifies and processes files based on their timestamps.
# Create test files of different ages ./backdate-touch.sh daily-backup.txt 1 ./backdate-touch.sh weekly-backup.txt 7 ./backdate-touch.sh monthly-backup.txt 30 ./backdate-touch.sh yearly-backup.txt 365
Generate historical log files for testing log rotation, archival, or analysis tools.
# Create historical log files
for i in {1..30}; do
./backdate-touch.sh "app-$(date -d "$i days ago" +%Y%m%d).log" $i
echo "Log entry for day $i" > "app-$(date -d "$i days ago" +%Y%m%d).log"
done
Test scripts that delete or archive files older than a certain age.
# Create files of various ages ./backdate-touch.sh old-file-30days.txt 30 ./backdate-touch.sh old-file-60days.txt 60 ./backdate-touch.sh old-file-90days.txt 90 # Test your cleanup script ./cleanup-old-files.sh 45 # Should delete files older than 45 days
Reconstruct file timestamps when recovering from backup or investigating incidents.
# Recreate timeline of incident ./backdate-touch.sh incident-start.log 5 ./backdate-touch.sh incident-peak.log 4 ./backdate-touch.sh incident-resolved.log 3
Important Notes
Most filesystems have timestamp limitations:
- ext4: Supports dates from Dec 14, 1901 to May 10, 2446
- XFS: Supports dates from Dec 13, 1901 to July 2, 2486
- FAT32: Limited to 1980-2107 range
- NTFS: Supports dates from 1601 to beyond year 30000
Attempting to set dates outside these ranges may fail or produce unexpected results.
Linux files actually have three timestamps:
- mtime (modification time): When file contents were last changed
- atime (access time): When file was last read
- ctime (change time): When file metadata was last changed
The touch command by default changes both mtime and atime. You cannot directly set ctime - it's automatically updated by the filesystem.
# Show all three timestamps stat filename.txt # Show just modification time ls -l filename.txt # Show access time ls -lu filename.txt # Show change time ls -lc filename.txt # Detailed stat output stat -c "Access: %x%nModify: %y%nChange: %z" filename.txt
The date -d option accepts many formats:
# Relative dates date -d "3 days ago" date -d "2 weeks ago" date -d "6 months ago" date -d "1 year ago" date -d "yesterday" date -d "tomorrow" # Specific dates date -d "2024-12-25" date -d "Dec 25 2024" date -d "25 Dec 2024" # Relative to specific dates date -d "2024-01-01 + 30 days" date -d "last Monday" date -d "next Friday" date -d "first day of last month"
Comparison: Why NOT Change System Date
| Method | Pros | Cons |
|---|---|---|
| touch -d (Recommended) |
• No root required • Safe - no system impact • Fast • Precise control • Can set any date in range |
• Only affects single file • Limited by filesystem |
| Change system date (Not Recommended) |
• All new files get that timestamp • Affects all operations |
• Requires root • Messes up logs • Confuses cron jobs • Can break databases • SSL cert issues • NTP will fight you • System instability • Not scriptable safely |
Quick Reference
# Basic usage touch -d "N days ago" filename # Specific date touch -d "YYYY-MM-DD" filename # Copy timestamp from another file touch -r oldfile newfile # Don't create if doesn't exist touch -c -d "yesterday" filename # Change only modification time touch -m -d "1 week ago" filename # Precise timestamp touch -t YYYYMMDDhhmm.ss filename # Check result stat filename ls -l filename