435

Is there a way to change the date when a file was modified/created (which is shown in Nautilus or with the ls -l command)? Ideally I am looking for a command which can change the date/time stamps of a whole bunch of files to a certain amount of time earlier or later (e.g. +8 hours or -4 days etc.).

david6
  • 14,499
snej
  • 4,351

6 Answers6

557

As long as you are the owner of the file (or root), you can change the modification time of a file using the touch command:

touch filename

By default this will set the file's modification time to the current time, but there are a number of flags, such as the -d flag to pick a particular date. So for example, to set a file as being modified two hours before the present, you could use the following:

touch -d "2 hours ago" filename

If you want to modify the file relative to its existing modification time instead, the following should do the trick:

touch -d "$(date -R -r filename) - 2 hours" filename

If you want to modify a large number of files, you could use the following:

find DIRECTORY -print | while read filename; do
    # do whatever you want with the file
    touch -d "$(date -R -r "$filename") - 2 hours" "$filename"
done

You can change the arguments to find to select only the files you are interested in. If you only want to update the file modification times relative to the present time, you can simplify this to:

find DIRECTORY -exec touch -d "2 hours ago" {} +

This form isn't possible with the file time relative version because it uses the shell to form the arguments to touch.

As far as the creation time goes, most Linux file systems do not keep track of this value. There is a ctime associated with files, but it tracks when the file metadata was last changed. If the file never has its permissions changed, it might happen to hold the creation time, but this is a coincidence. Explicitly changing the file modification time counts as a metadata change, so will also have the side effect of updating the ctime.

  • 6
    To mention the simpler case when all files are in the same folder: touch -d "2 hours ago" /path/*.txt, for example. – enzotib Sep 22 '11 at 07:05
  • 4
    I'd also add that changing the ctime is not possible in any standard way. – arrange Sep 22 '11 at 07:40
  • Is this all POSIX ? – user1011471 Sep 10 '15 at 16:42
  • 2
    The information about ctime as a metadata change time is from POSIX. I don't know if the shell fragments in my answer would work with strict POSIX shell utilities. But they definitely work on Ubuntu, which is the context for answers on this site. – James Henstridge Sep 15 '15 at 22:27
  • 2
    touch: illegal option -- d – User Jan 15 '16 at 14:55
  • 5
    On OSX, you may want to use gtouch via brew install coreutils. – Nobu May 23 '16 at 22:50
  • 1
    For ctime change there is a solution here that worked for me. set system date. chmod file. (also other solutions involving umount file system and modify) http://stackoverflow.com/questions/16126992/setting-changing-the-ctime-or-change-time-attribute-on-a-file/17066309 – gaoithe May 25 '16 at 10:16
  • 1
    Wow, this doesn't work: touch -d "$(date -R -r "$filename") - 2 hours" "$filename", at least not on Red Hat Enterprise Linux ES release 4. I know this is an Ubuntu forum but this is really a generic unix question and it ought to work the same on redhat. But if I use "- 8 days" as the time component, touch sets the date AHEAD 8 days! Very annoying. And "+ 8 days" also sets it ahead 8 days. – Steve Cohen Oct 27 '16 at 18:48
  • 1
    Lot of solutions around for modification, but how about changing creation date + time stamp? – Olivier Pons Oct 31 '18 at 09:40
  • 1
    macOS: touch -r source.file target.file – Quinn Comendant Dec 06 '18 at 18:54
  • 1
    @JamesHenstridge Lets say I have 10 file with same timestamp, in such case neither of the above is working. – Govinda Sakhare Jan 08 '19 at 12:05
  • 1
    touch -t can be used to set the time and date. Not sure why this answer said it's not possible with "file time relative" – LifeBoy Nov 14 '19 at 08:30
  • I had no idea touch was so versatile – Matt Feb 20 '24 at 10:38
141

Easiest way - accessed and modified will be the same:

touch -a -m -t 201512180130.09 fileName.ext

Where:

-a = accessed
-m = modified
-t = timestamp - use [[CC]YY]MMDDhhmm[.ss] time format

If you wish to use NOW just drop the -t and the timestamp.

To verify they are all the same: stat fileName.ext

See: man touch

Jadeye
  • 2,032
  • 1
    I tried to verify it using stat, but neither of the touch flags lead to a correct result. Modification date is adjusted, but changed and accessed date are actually changed to NOW – xeruf Mar 19 '18 at 20:51
  • It didn't work for me, it changed only the "Change" time – Revious Dec 05 '18 at 16:42
  • 1
    @Revious , Xerus What's the difference between the changed time and the modified timestamps? – ijoseph May 26 '19 at 20:49
  • @ljoseph, take a look here: https://www.howtogeek.com/517098/linux-file-timestamps-explained-atime-mtime-and-ctime/#:~:text=%E2%80%9CModified%E2%80%9D%20means%20something%20inside%20the,will%20update%20the%20changed%20timestamp. – Jadeye Mar 07 '21 at 10:52
  • 2
    Using "-a" and "-m" together is probably unnecessary, "-a" is "change only the access time", and "-m" is "change only the modification time". If you want to update both, you don't need to use any option. – Dario Seidl Oct 13 '21 at 08:57
  • This worked for me but note that it will not change the creation and modification date present in metadata, for example in PDF files. – baptx Nov 08 '22 at 16:49
64

Thanks for the help. This worked for me:

In the terminal go to the directory for date-edit. Then type:

find -print | while read filename; do
    # do whatever you want with the file
    touch -t 201203101513 "$filename"
done

You wil see a ">" after you hit enter, exept for the last time -> "done".

Note: You may want to change "201203101513"

"201203101513" = is the date you want for all the files in this directory.

boroboris
  • 101
EFL
  • 741
  • it doesn't work as expected if a file name contains blank spaces – Angel Aug 02 '16 at 07:56
  • 1
    Webpage is no longer, albeit it is 6 years later. Nonetheless, this is the answer I was looking for. For those who want to include seconds in their time, use .ss where ss is the number of seconds. (Note: this does not seem to control sub-second timings such as nanoseconds or milliseconds, which for me just appeared as zeros; however, this difference was permissible for my use-case.) – Spencer D Dec 09 '18 at 19:32
21

Touch can reference a file's date all by itself, no need to call date or use command substitution. Here's a bit from touch's info page:

`-r FILE' `--reference=FILE'
     Use the times of the reference FILE instead of the current time.
     If this option is combined with the `--date=TIME' (`-d TIME')
     option, the reference FILE's time is the origin for any relative
     TIMEs given, but is otherwise ignored.  For example, `-r foo -d
     '-5 seconds'' specifies a time stamp equal to five seconds before
     the corresponding time stamp for `foo'.  If FILE is a symbolic
     link, the reference timestamp is taken from the target of the
     symlink, unless `-h' was also in effect.

For example, to add 8 hours to a file's date (filename of file quoted just in case of spaces, etc):

touch -r "file" -d '+8 hour' "file"

Using a loop over all files in the current dir:

for i in *; do touch -r "$i" -d '+8 hour' "$i"; done

I've heard that using a * and letting for pick the filenames itself is safer, but using find -print0 | xargs -0 touch ... should handle most crazy characters like newlines, spaces, quotes, backslashes in a filename. (PS. try not to use crazy characters in filenames in the first place).

For example, to find all files in thatdir whose filenames start with an s, and add one day to those file's modified timestamp, use:

find thatdir -name "s*" -print0 | xargs -0 -I '{}' touch -r '{}' -d '+1 day' '{}'
Xen2050
  • 8,705
5

This little script at least works for me:

#!/bin/bash

find specific files

files=$(find . -type f -name '*.JPG')

use newline as file separator (handle spaces in filenames)

IFS=$'\n'

for f in ${files} do

read file modification date using stat as seconds

adjust date backwards (1 month) using date and print in correct format

change file time using touch

touch -t $(date -v -1m -r $(stat -f %m "${f}") +%Y%m%d%H%M.%S) "${f}" done

Pablo Bianchi
  • 15,657
joakim
  • 51
  • 1
  • 1
  • 3
    Adjusting the date of images based on meta info in the image would be pretty useful. ImageMagick's identify can be used. e.g. 'identify -verbose |grep -i date', 'identify -format %[exif:DateTime] ' might show '2015:01:08 10:19:10' (not all images have exif data). This works(using sed to convert date to format touch can handle): 'touch -d $(identify -format %[exif:DateTime] $f|sed -r 's/:/-/;s/:/-/;') $f' – gaoithe May 24 '16 at 11:30
  • 1
    @gaoithe could you answer this question based on your comments? – user68186 Feb 20 '23 at 14:49
3

It's been a long time since I wrote any kind of Unix program, but I accidentally set the year incorrectly on a bunch of Christmas photos, and I knew if I didn't change the date from 2015 to 2014 it would be a problem later on.

Maybe, this is an easy task, but I didn't find any simple way to do it.

I modified a script I found here, which originally was used to modify the date by minus one month.

Here's the original script:

#!/bin/bash

# find specific files
files=$(find . -type f -name '*.JPG')

# use newline as file separator (handle spaces in filenames)
IFS=$'\n'

for f in ${files}
do
 # read file modification date using stat as seconds
 # adjust date backwards (1 month) using date and print in correct format 
 # change file time using touch
 touch -t $(date -v -1m -r $(stat -f %m  "${f}") +%Y%m%d%H%M.%S) "${f}"
done

Here's my modified script that forced the date to the year "2014":

#!/bin/bash 

# find specific files
#files=$(find . -type f -name '*.JPG')

# use newline as file separator (handle spaces in filenames)
IFS=$'\n'

for f in $*
do
 # read file modification date using stat as seconds
 # adjust date backwards (1 month) using date and print in correct format 
 # change file time using touch
 touch -t $(date -v +1y -r $(stat -f %m  "${f}") +2014%m%d%H%M.%S) "${f}"
done

I now realize I could have done a more generic version:

#!/bin/bash 

# find specific files
#files=$(find . -type f -name '*.JPG')

# use newline as file separator (handle spaces in filenames)
IFS=$'\n'

for f in $*
do
 # read file modification date using stat as seconds
 # adjust date backwards (1 month) using date and print in correct format 
 # change file time using touch (+1y adds a year "-1y" subtracts a year)
 # Below line subtracts a year
 touch -t $(date -v -1y -r $(stat -f %m  "${f}") +%Y%m%d%H%M.%S) "${f}"
 # Below line adds a year
 # touch -t $(date -v +1y -r $(stat -f %m  "${f}") +%Y%m%d%H%M.%S) "${f}"
done

To use this file you would need to write it and

chmod +x fn

to execute:

./fn files-to-change

fn=your-file-name-that-is-your-command

Example

./fn *.JPG

will change the date by minus one year in the directory where you are.

Eric Carvalho
  • 54,385
RickK
  • 31
  • 2
    Same as above comment. Most .jpg files will have date embedded in meta data aded by camera. This works(using sed to convert date to format touch can handle): 'touch -d $(identify -format %[exif:DateTime] $f|sed -r 's/:/-/;s/:/-/;') $f' – gaoithe May 25 '16 at 09:49