Help with touch: bad time specification

Here is the part of the script: I have modified the file name.:slight_smile:

SSFILE=${My_HOME_DIR}/log/my_file_ss.log
export MM=`date '+%m'`
export DD=`date '+%d'`
export HH=`date '+%H'`
export MIN=`date '+%M'`
export HOURAGO=`echo ${HH} -1 |bc `
echo $HOURAGO
export TTIME=${MM}${DD}${HOURAGO}00
echo $TTIME
touch -t ${TTIME} ${SSFILE}
export MIN=`date '+%M'`
export HOURAGO=`echo ${HH} -1 |bc `
echo $HOURAGO
export TTIME=${MM}${DD}${HOURAGO}00
echo $TTIME
touch -t ${TTIME} ${SSFILE}
 

I get this message in error log file: touch: bad time specification
I have solaris 10 and this is .ksh file.

Can anyone tell me what is wrong with this commands?

Can you show us the output from

echo ${TTIME}

You could also adjust the timezone value $TZ This will adjust your current session to give you a variation of the clock based on the real time your server holds (actually against GMT / UTC / Zulu depending how you see it)

So if your time zone is:-

echo $TZ
GMT0BST

You can set it to:-

TZ=GMT1BST

Then run your date commands to get the values and then reset the original TZ before running touch. You will probably have a different TZ to mine, but add one to the number early on.

Orig_TZ="$TZ"
TZ=GMT1BST               # Adjust to suit, of course
date '+%m %d %H'|read MM DD HH
TZ=$Orig_TZ
touch -t ${MM}${DD}${HH}00 ${SSFILE}

I hope that this helps

Robin
Liverpool/Blackburn
UK

touch needs the year!
I suggest to run date once with shell style format, and get all variables with eval

eval `
date +'YY=%Y MM=%m DD=%d HH=%H MIN=%M'
`
HOURAGO=`echo ${HH}-1 | bc `
echo $HOURAGO
TTIME=$YY$MM$DD${HOURAGO}00
echo $TTIME
1 Like

touch does not require a year:

           [[CC]YY]MMDDhhmm[.SS]

And your solution does not work if hour is "00".

$ date +'YY=%Y MM=%m DD=%d HH="00" MIN=%M'
...
$ echo $TTIME
0723-100
1 Like

It is worse than that. Using:

HOURAGO=`echo ${HH}-1 | bc `

to set HOURAGO turns a 2 digit hour string into a single digit hour string for any time before 11am (thereby producing a -t option string in the wrong format). And even if HOURAGO was set to 23 instead of -1, the HH and possibly DD and MM values will be off as well. And, if the code is fixed to set HOURAGO to 23 and 00 through 09 (rather than -1 and 0 through nine), it needs to use CCYY in case the script is run in the 1st hour of New Year's day by a cron job (or some poor operator stuck in the office on New Year's Day's early morning shift) or the touch (after adjusting MM and DD will set the timestamps to the 11pm hour of December 31st in the new year instead of in the previous year).

And, using multiple calls to the date utility to get individual portions of the desired date is a recipe for generating wrong times that are difficult to diagnose. If the calls to date happen during different seconds on the clock, the minute, hour, day, month, and year could all be off. For example, if the first of the calls to date in this example starts just before midnight on December 31th, the resulting calculated date (before subtracting 1 from the hour) could be any of:

12312359
01312359
01012359
01010059
   or
01010000

With scheduling delays the differences could be even more unpredictable. (In other words; NEVER use multiple calls to date to get various pieces of what is supposed to be a single timestamp.)

Robin's (rbatte1) proposal will work in the US except for a couple of hours twice a year (on days when we switch to and from daylight savings time). Using TZ=GMT1BST will be off not only on daylight savings time switch days, but will also be off by an hour all day on days between the switch to daylight savings time in the UK and the switch to daylight savings time in the US. This can be fixed outside the US by using the full capabilities of the TZ variable format stdoffset[dst[offset[,start[/time],end[/time]]] which can specify not only the names of the standard and daylight savings time zone abbreviations ( std and dst , respectively, and the offset from Greenwich, but also the start and end dates for daylight savings time, and the time s at which the shift takes place; but it still leaves you with a result that is an hour off for a couple of hours around the switchover two times per year in areas that observe daylight savings time.

To accurately get the time one hour ago at all times of the day every day of the year on Solaris systems that don't have the GNU date utility installed when you are in an area of the world where daylight savings time is observed, you can either use perl (as has been shown in these forums many times before) or write a simple C program to get the current number of seconds since the Epoch, subtract 3600 (the number of seconds in an hour) and format that value using a function to print a seconds since the Epoch value that adjusts for the current system default timezone as modified by the setting of TZ. In C, the following should work:

#include <libgen.h>
#include <stdio.h>
#include <time.h>

int
main(int argc, char *argv[]) {
        time_t          modtime;        // modified seconds since the Epoch
        char            out[1024];      // output buffer
        struct tm       *timep;         // broken down adjusted local time

        // Verify number of arguments
        if(argc != 3) {
                (void)fprintf(stderr, "Usage: %s offset fmt\n",
                        basename(argv[0]));
                return 1;
        }

        // Get desired time as a value in seconds since the Epoch as
        // specified by the "offset" operand.
        modtime = time(NULL) + atol(argv[1]);

        // Convert that time to a struct tm as adjusted by current $TZ setting.
        timep = localtime(&modtime);

        // Format the output as specified by the given "fmt" operand.
        (void)strftime(out, sizeof(out) - 1, argv[2], timep);
        (void)printf("%s", out);
}

although the above code doesn't check for errors (other than wrong number of arguments. For this to be put into a production environment; at the least, the calls to atol(), localtime(), and strftime() should be checked for errors. The output is also unspecified if the fmt operand given causes strftime() to produce more that 1024 bytes of output (including the terminating NUL byte).

If you compile the above code and mv the a.out to a file named timeoffset , the following commands will create files with timestamps set to the time one day ago and one hour ago, respectively:

touch -t $(timeoffset $((-24*60*60)) "%Y%m%d%H%M") now-1d
touch -t $(timeoffset -3600 "%Y%m%d%H%M") now-1h

Are we having fun yet?

1 Like

Thanks Scott and Don for pointing out the problems with date calculations!
Another thanks to Don for a general C solution!
Here is a (not so general) native Perl solution

TTIME=`perl -e '
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time-3600);
printf "%04d%02d%02d%02d%02d\n",$year+1900,$mon+1,$mday,$hour,$min;
'`
echo $TTIME