How can I change the filename timestamp?

Solution 1:

Using python :

#!/usr/bin/env python2
import glob, re, os, datetime
os.chdir('/path/to/dir')
for f in glob.glob('*.dat'):
    ini_time = datetime.datetime.strptime(re.search(r'(?<=_)(?:\d|_)+(?=.dat$)', f).group(), '%Y_%m_%d_%H%M')
    fin_time = (ini_time + datetime.timedelta(minutes=30)).strftime('%Y_%m_%d_%H%M%S')
    os.rename(f, 'Filename_' + str(fin_time) + '.dat')
  • os.chdir('/path/to/dir') will change the current directory to the directory containing the .dat files. Replace /path/to/dir with the actual path.

  • glob.glob('*.dat') will find the files ending in .dat

  • ini_time variable will at first cut out the date-time from the original file name using re module and then sort out which entry represents what in the string that is taken out so that we can add the required time to this

  • fin_time will contain the resultant time i.e. ini_time plus 30 minutes

  • os.rename will rename the file accordingly.

Also note that, with successive file names (differed by 30 minutes) the renamed file will overwrite the next one, hence it it is better to add the seconds to the renamed file name so that it remains safe. Otherwise you need to save the renamed files to a different directory and then replace them with the original ones later.

Solution 2:

Using bash, the renamed files are in a new sub folder renamed.

Start the script in the folder where the files are located.

#!/bin/bash

mkdir -p renamed   

# loop over all dat files in the current folder
for f in *.dat; do

    # the filename without extension    
    filename="${f%%.*}"

    # your timestamp
    old_timestamp=$(echo $filename | grep -P "[0-9]{4}_[0-9]{2}_[0-9]{2}_[0-9]{4}$")

    if [ "$old_timestamp" == "" ]; then
        >&2 echo "not a valid filename: '$f', skipped."
    else
      # a valid date from the timestamp
      new_date=$(echo "$old_timestamp" | awk -F_ '{HM=NF; D=NF-1; M=NF-2; Y=NF-3; print $Y "-" $M "-" $D " " substr($HM,1,2) ":" substr($HM,3,2) ":00"}')

      # the new time stamp, 30 mins in the future
      changed_timestamp=$(date --date "$new_date 30 minutes" "+%Y_%m_%d_%H%M")

      # copy the file, ${f##*.} is the extension
      cp "$f" renamed/"${filename/$old_timestamp/$changed_timestamp.${f##*.}}"
    fi
done

example output:

% ls -og FileName*
-rw-rw-r-- 1 0 Mai 16 20:35 FileName_2015_05_16_2235.dat

% ./timestamp

% ls -og renamed/FileName*
-rw-rw-r-- 1 0 Mai 16 20:35 FileName_2015_05_16_2305.dat

Solution 3:

SCRIPT

This is the edited version of my original script. OP originally didn't provide full information about the naming format. This script adapts to what OP mentioned in the comments was the correct file naming.

*Technical notes: *

In this script we separate filename into 6 separate fields using awk, with underscore as field delimiter. First two fields , $1 and $2 are considered static text string. Fields 3,4,5, and 6 are the timestamp at which OP's data was sampled, not the file's creation date on the filesystem.

Variable COPYDIR holds name of new directory where files with updated timestamp will go. We create that directory in current working directory with mkdir $COPYDIR

Variables TEXTSTRING and DATESTRING hold static text and timestamp respectivelly. In the sample output bellow I have used two different strings to prove that script will work regardless of what text the first two fields hold.

NEWEPOCHTIME is variable that holds calculated new timestamp in unix epoch format. NEWDATE is variable that holds converted timestamp from unix epoch to YYYY-MM-DD HH:MM format. NEWAPPEND is the actual timestamp that will be added to the file in OP's desired YYYY_MM_DD_HHMM format.

cp $file "$COPYDIR"/"%TEXTSTRING""$NEWAPPEND".dat copies the old file into "converted_files" directory ( instead of moving, to prevent data loss) with the updated datastamp.

Notice, the script will work as long as the naming format is really followed, i.e., all the files are really have SomeText_123.Data_YYYY_MM_DD_HHMM.dat format.

#!/usr/bin/env bash
#
# Author: Serg Kolo
# Description: this script takes timestamp within the filename
# (which may be different from file's actual creation date)
# converts that date and time to unix's epoch time
# adds 30 minutes to it and renames it

COPYDIR="converted_files"
mkdir $COPYDIR

for file in *.dat; do
        TEXTSTRING=$(stat -c %n $file | awk -F'_' '{print $1"_"$2"_"}' )
        DATESTRING=$( stat -c %n $file | awk -F'_' '{gsub(".dat","");  print $3"-"$4"-"$5" "$6}' )
        NEWEPOCHTIME=$( expr $( date --date="$DATESTRING" +%s ) + 1800 )
        NEWDATE=$(date --date=@"$NEWEPOCHTIME" +%F"_"%R)
        NEWAPPEND=$(echo $NEWDATE | awk '{gsub("-","_");gsub(":","");print}')
        cp $file "$COPYDIR"/"$TEXTSTRING""$NEWAPPEND".dat
done

SCRIPT IN ACTION

The demonstration bellow is direct copy from my terminal. Notice that I've created original files with two different strings in the first two fields. So this script should work no matter what is in the beginning of the filename, as long as there are really only two strings separated by underscore

The script was named notes-conversion because I developed the script from the notes I took while working on this question.

Notice that filenames which have HHMM part as 2345 (which is 15 minutes before midnight) get updated to 0015, and DD part is updated to next day. 24 hour format preserved.

In addition, because for loop only looks for .dat files, we avoid renaming other files or directories that may happen to be in the working directory, thus avoiding any potential data loss. In the example bellow, original directory holds 11 items, 3 of which are *.txt files for testing, so we only work with 8 .dat files. In the directory where updated files go, we see 8 files, all .dat and no other files. Data is safe, script does its job.

[68 ]SERGIY@UBUNTU_[/home/xieerqi/testdir/conversion/convert2]
***********************************************
85 $ ls
FileName_123.Dat_2015_05_31_1245.dat  Test.txt
FileName_123.Dat_2015_05_31_2345.dat  YoloSwag_123.Dat_2015_05_31_1245.dat
FileName_Foo.Bar_2015_05_31_1245.dat  YoloSwag_123.Dat_2015_05_31_2345.dat
FileName_Foo.Bar_2015_05_31_2345.dat  YoloSwag_Foo.Bar_2015_05_31_1245.dat
File.txt                              YoloSwag_Foo.Bar_2015_05_31_2345.dat
Random.txt

[68 ]SERGIY@UBUNTU_[/home/xieerqi/testdir/conversion/convert2]
***********************************************
86 $ ls | wc -l
11

[68 ]SERGIY@UBUNTU_[/home/xieerqi/testdir/conversion/convert2]
***********************************************
87 $ notes-conversion                                                                                

[68 ]SERGIY@UBUNTU_[/home/xieerqi/testdir/conversion/convert2]
***********************************************
88 $ ls converted_files/; ls converted_files/ | wc -l                                                
FileName_123.Dat_2015_05_31_1315.dat  YoloSwag_123.Dat_2015_05_31_1315.dat
FileName_123.Dat_2015_06_01_0015.dat  YoloSwag_123.Dat_2015_06_01_0015.dat
FileName_Foo.Bar_2015_05_31_1315.dat  YoloSwag_Foo.Bar_2015_05_31_1315.dat
FileName_Foo.Bar_2015_06_01_0015.dat  YoloSwag_Foo.Bar_2015_06_01_0015.dat
8

[67 ]SERGIY@UBUNTU_[/home/xieerqi/testdir/conversion/convert2]
***********************************************
89 $ 

EXPLANATION (from original post)

*) Today I've learned that Unix-Linux systems count time in Epoch time, or simply put seconds.

*) the script takes each file name, extracts date, converts it to epoch , adds 1800 seconds (which is exactly 30 minutes), and saves the file with than new timestamp.

*) This script addresses what OP wanted - change timestamp in filename, not update creation time of the file itself

Tools used:

  • ubuntu 15.04

  • GNU bash 4.3.30

  • GNU awk 4.1.1

  • date (GNU coreutils) 8.23