Script to adjust system time

Hello everyone,

I am trying to write a script that will accomplish the following:

  • query current system time and store result into a variable
  • wait for some amount of time, say 300 seconds
  • reset system time to earlier queried time + 1 second

I did some basic shell scripting (CSH mainly) and took an intro to perl class in 2000 but have not touched either since, and as a result I really have no idea how to accomplish this task. I'm also not really sure how to do the math on the time since the systemsetup -settime requires hh:mm:ss, so at 59 seconds I'll run into a problem :confused:

I'm currently using OS X 10.6.6 and /bin says I have access to bash, csh, ksh, tcsh, and zsh. I have no preference for which shell the script runs in, although echo $SHELL says my current default is bash, if that makes any difference.

I would also like to use argv (or something similar) to define how many cycles I'd like to process to repeat and possibly to define the wait time as well instead of hard coding these into the script.

Thanks in advance!

Xaiu

The right way to ajust the system time is to configure NTP
also see pool.ntp.org

1 Like

Sounds like the OP wants to slow down the system clock, not keep it accurate. NTP would keep it accurate.

1 Like

KevinGB is on the right track - the script isn't meant to adjust the system time to a reference time source to keep it accurate. I have an application that references the system time and I want to run that application for a set period of time, from say 12:00:00 to 12:05:00, tabulate the output, and then reset the system clock to 12:00:01 and run the application from 12:00:01 to 12:05:01 and compare the output to the previous run.

Actually, since I originally posted I realized that I don't need to query the current time at all. Instead I can just pass a clock time, wait period (in seconds), next cycle increment (in seconds), and an exit time into the script. This should get me around quite a number of the problems I was initially having and will hopefully simply the script down to something I can muddle my way through. Anyhow, I could do something like:

> script 12:00:00 300 1 12:00:05

which would hopefully:

  • set the system time to 12:00:00
  • wait for n seconds
  • increment the input system time by increment (in this case 1 second)
  • compare the result to the end time (passed in from script) and if new system time is less end time
  • reset system time and loop to wait for n seconds

so in this scenario I should get 5 cycles that lasted for 5 minutes each and my timestamp on the data that is being collected would show:

1st cycle: 12:00:00 - 12:05:00

2nd cycle: 12:00:01 - 12:05:01

3rd cycle: 12:00:02 - 12:05:02

Thanks for your responses!

It is not advisible to change the system time in the manner proposed in post #1. Hard setting the date/time should only be done in single user mode armed with full knowledge of the effects on programs such as System Accounting and any Database Engines you may have.

What are you trying to do? We seem to have a proposed solution without knowing the problem.

If your system clock is a little bit fast, there should be a clock drift function (see "man date"). Or if you have access to a Time Server, use NTP as ctsgnb advises.

(Post drafted before seeing post #4). There has to be a better way which does not involve messing with the system clock.

1 Like

Methyl, yes, great point.

This is a single user stand alone system running a custom simulation application for which I am collecting results at 1 second intervals. The application takes into account the time of day, which it gets from the system time. IE my data output from 12:00:00 - 12:59:59 will be different than the data output from 13:00:00 - 13:59:59, even though I have not changed any of the application parameters.

Since I can't change the behavior of the application (it getting it's simulation time from the system clock) I have been running the application for a set period of time and then re-adjusting the system clock by hand. I'm looking for a way to let the application run continuously, but appear as if it had been run for a set number of cycles with each cycle lasting a set period of time, and each cycle beginning from an incremental offset.

Hope that helps clarify the problem I'm trying to solve with the script.

Woudn't it be possible to play with the Timezone ?
Something like

TZ=$(($TZ+1)) && ./appli

or (FreeBSD)

$ export TZ=/usr/share/zoneinfo/Etc/UTC
$ date
Sun Feb 27 08:07:58 UTC 2011
$ export TZ=/usr/share/zoneinfo/Etc/GMT+1
$ date
Sun Feb 27 07:08:14 GMT+1 2011

---------- Post updated at 09:18 AM ---------- Previous update was at 09:11 AM ----------

[ctsgnb@shell ~/sand]$ export TZ=/usr/share/zoneinfo/Etc/UTC

$ date +'%H:%M:%S' && export TZ=/usr/share/zoneinfo/Etc/GMT+1 && date +'%H:%M:%S'
08:18:08
07:18:08
$
1 Like

More relaxed about this now.

Be careful. As you appear to be only changing the time (not the date) there is likely to be less impact. The unix "date" command will accept just a time parameter. Be aware of post-dated files.

During Y2K testing I had to set up a "Groundhog Day" system which repeated the same given day again-and-again and needed to save and reset (or replace) system accounting files, system logs, software licence files etc. etc. and deal with timestamps on post-dated files (or remove them as appropriate). This was not trivial.

One awful database crash I attended was caused by someone changing the system clock by a couple of minutes.

1 Like

So I've been making some progress on my question and I was actually playing around with the date command before I saw your response. On mac OS I have been using the command:

systemsetup -gettime which returns Time: HH:MM:SS

so I've been trying to figure out how to strip Time: and assign hours=HH minutes=MM seconds=SS. I could then:

sh script.sh 300 1 10

  • get current system time with systemsetup -gettime
  • strip Time: and convert the system time to seconds
  • initialize cycle count to 1 and
  • while count less than 10 (passed in from command line as $3) do
  • wait for 300 seconds (passed in from command line as $1)
  • add the increment 1 (passed in from command line as $2) to system time converted to seconds as new_systemtime
  • convert new_systemtime back to HH:MM:SS format
  • reset system time to new_systemtime by systemsetup -settime $new_systemtime
  • increment cycle_count by 1

I was able to use awk -F: to print each number independently. It's ugly, but:

systemsetp -gettime ; a=$(systemsetup -gettime) ; echo $a | awk -F: '{print $2":"$3":"$4}'
Time: 22:32:59
22:32:59

but then I got stuck at how to shove $2 $3 and $4 into the variables hours, minutes, and seconds instead of printing them.

Anyhow, any tips would be greatly appreciated on how to go about each of those steps, or if I'm just going about it all the wrong way, that'd be good to know too :slight_smile:

Maybe try saving the current time in a file in a private directory with the name of the file the value of HHMMSS . Then (after 300 seconds or whatever) use the name of the file in a unix "date" command to reset the time as required.
When working with Groundhog Day software testing the advantage of using a file instead of a Shell environment variable is that it survives system reboots. Also, you can alter the name of the file to whatever you want.

1 Like

Okay,

So I fumbled through it and I've managed to get my script running, all except re-setting the system time. I have $h $m $s and I'm trying to make a single variable $set_time that takes the form $h:$m:$s. Everything I've tried I just end up with $h $m $s. How do I get a colon included in the variable?

Thanks! Here's the whole thing, in case it helps.

# Call this script with parameters for wait_time, increment, and cycle_count
#
# example sh test.sh 300 1 10
# this will sleep for 300 seconds, increment the start time by 1 second, and run
# for 10 cycles

# Saving variables passed in from command line for later use
wait_time=$1
echo "Wait time in seconds: "$wait_time
increment=$2
echo "Increment in seconds: "$increment
cycle_count=$3
echo "Itteration cycles: "$cycle_count

# Turning network clock off
systemsetup -setusingnetworktime off

# getting on with it
read -p  "Hit any key when ready to begin"
init_time=$(systemsetup -gettime)
echo "Reference time will be set as: "$init_time

# converting current system time to seconds
d=$init_time
IFS=":"
set -- $d
hr=$2
min=$3
sec=$4

# strip leading white space from hr
hr=$(echo $hr | tr -d " ")

# echo "IFS time in seconds: $(((hr*3600)+(min*60)+sec))"
ref_time=$(((hr*3600)+(min*60)+sec))
# echo "\$ref_time set to: "$ref_time

#inserting while loop
COUNTER=0
while [  $COUNTER -lt $cycle_count ]; do
echo Cycle count: $COUNTER
echo "sleeping for $wait_time seconds"

# Don't want to sleep while testing
# sleep $wait_time

# Adding $increment to $ref_time
new_time=$((ref_time+increment))
# echo "old ref_time was: "$ref_time
ref_time=$new_time
# echo "new ref_time is: "$new_time

# Converting new_time to HH:MM:SS for set_time
secs=$new_time
# echo "\$secs set to: "$new_time

h=$(( secs / 3600 ))
m=$(( ( secs / 60 ) % 60 ))
s=$(( secs % 60 ))

echo "system time will be sets as: systemsetup -settime $h":"$m":"$s"
set_time=$h:$m:$s
echo $set_time
# systemsetup -settime $h":"$m":"$s"

let COUNTER=COUNTER+1
done

# Turning network clock on
systemsetup -setusingnetworktime on

---------- Post updated at 02:51 PM ---------- Previous update was at 02:32 PM ----------

Bugger!

I found the problem. line 25

IFS=":"

So I added

IFS=":"
set -- $d
hr=$2
min=$3
sec=$4

# Adding this as a wild hair, what if IFS above is causing problems?
IFS=";"

I have never used IFS, but I suspect that I should unset it, rather than setting to a semi-colon to solve the problem.

Thanks to everyone for all your help!

Best bet is to store IFS in OLDIFS before you change it and then rest it back after:

OLD_IFS=$IFS
IFS=:
# your commands here
IFS=$OLD_IFS

Or set it explicitly to the shell default:

IFS=$' \t\n'