12 January 2012

File timestamps in batch files

PublishedActual
Birmingham New Street 06:50 06:54
London Euston 08:14 08:23

This is a strange one as it is useful to only a small sub-set of computer users, namely those which write batch files in Windows to optimise their workflows. One of my recent workflows has been to take a file with name XYZ.txt in directory A and move it to directory B ready for a file with the same name (XYZ.txt) to be placed in directory A. So that I can keep a backup of the files I needed to add a timestamp to the filename, this means that directory B contains 1 or more files with the name yyyyMMdd_hhmmss_XYZ.txt where:

  • yyyy = full year
  • MM = month in year
  • dd = date in month
  • hh = hour in day
  • mm = minute in hour
  • ss = seconds in minute

Example names could be 20111225_120027_XYZ.txt or 20120111_180653_XYZ.txt etc.

Initially it seemed like a simple problem to solve, I figured that I’d be able to use the system %DATE% and %TIME% properties. To test this theory I decided to use the command line to rename a file following this process:

  1. Click Start> Run
  2. Type cmd and hit enter
  3. Enter the following commands:

    Z:> mkdir test
    Z:> cd test
    Z:test> notepad XYZ
  4. Save the file using Notepad, this doesn’t have to have any content.
  5. Rename the file with the following:

    Z:test> ren XYZ.txt %DATE%_%TIME%_XYZ.txt

At this point DOS reported an error as apparently The syntax of the command is incorrect.. Knowing that the syntax is correct I guessed that there must be characters returned in %DATE% or %TIME% that cause issues. To test these variables I entered the following commands at the command line receiving the corresponding results:

Z:test> echo %TIME%
18:35:42.98
Z:test> echo %DATE%
12/01/2012

This simple test shows that both %DATE and %TIME% contain characters that are not valid for file names, i.e. / and :. My next plan of attack was to process the values to see if I could remove the reserved characters so I went to Google and searched. Eventually I came across what looked like a good solution in a post on StackOverflow which gave a full command, this command used syntax I’ve never seen before (like %DATE:~6,4%) so when it didn’t work first time I had to find out how to fix it. Essentially the StackOverflow answer assumed the American locale whereas my machine is using GB dates and times, some further searching gave the pointer to look at the help for the set command:

Z:test> set /?

The help file gave me exactly the detail I needed. I never knew that it was possible to affect the value returned by an environment variable but apparently it is and the help on set gives a few details. The operations that are supported are string substitution and sub-string.

String substitution is where some text in the original string is replaced with other text, this takes the form

%DATE:str1=str2%


Using the above example the value of %DATE% will be returned with all instances of str1 being replaced with str2. This can be tested as follows:

Z:test> echo Original date %DATE% becomes %DATE:/=;%
Original date 12/01/2012 becomes 12;01;2012


As can be seen, all instances of / have been replaced with ; in the output text.

The second string operation which can be performed is sub-stringing, this is where a series of characters are extracted from the original text based on their positions. The syntax for sub-stringing takes the form:

%PATH:~offset[,length]%


Offset indicates the number of characters to pass over before starting the sub-string so an offset value of 3 means that the sub-string will start with the character at position 4. Length is optional and indicates how long the sub-string will be, if this value is not supplied then the remainder of the value is returned, if the length is greater than the value length then, again, the remainder of the word is returned. The values for offset and length can be negative, this adds complexity to the expression and can make it look awkward. If the offset is negative then the starting position is that number of character from the right of the value, for instance XYZ with an offset of -1 means the sub-string will start at Z. If the length is negative then the length of the substring is taken to be the remaining length of the value minus the negative length, for instance XYZ with an offset of -2 and length of -1 would return Y. It’s worth noting with negative indices that if the remaining length of the value is less than the number of negative characters then nothing will be returned. String substitution is a reasonably complex concept and is probably best illustrated with some examples:

Z:test> echo Original date %DATE% becomes %DATE:~0%
Original date 12/01/2012 becomes 12/01/2012

Z:test> echo Original date %DATE% becomes %DATE:~3%
Original date 12/01/2012 becomes 01/2012

Z:test> echo Original date %DATE% becomes %DATE:~3,2%
Original date 12/01/2012 becomes 01

Z:test> echo Original date %DATE% becomes %DATE:~3,7%
Original date 12/01/2012 becomes 01/2012

Z:test> echo Original date %DATE% becomes %DATE:~3,100%
Original date 12/01/2012 becomes 01/2012

Z:test> echo Original date %DATE% becomes %DATE:~3,-5%
Original date 12/01/2012 becomes 01

Z:test> echo Original date %DATE% becomes %DATE:~3,-10%
Original date 12/01/2012 becomes

Z:test> echo Original date %DATE% becomes %DATE:~3,-2%
Original date 12/01/2012 becomes 01/20

Z:test> echo Original date %DATE% becomes %DATE:~-7%
Original date 12/01/2012 becomes 01/2012

Z:test> echo Original date %DATE% becomes %DATE:~-7,2%
Original date 12/01/2012 becomes 01

Z:test> echo Original date %DATE% becomes %DATE:~-7,100%
Original date 12/01/2012 becomes 01/2012

Z:test> echo Original date %DATE% becomes %DATE:~-7,-5%
Original date 12/01/2012 becomes 01

Z:test> echo Original date %DATE% becomes %DATE:~-7,-10%
Original date 12/01/2012 becomes

Taking all the above into consideration I finally came up with the sub-stringing required to create the timestamp I wanted in the format I wanted, here is how I achieved the timestamp rename:

Z:test> set STAMP=%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%%TIME:~0,2%%TIME:~3,2%%time:~6,2%_XYZ.txt

Z:test> echo rename XYZ.txt with name %STAMP%
rename XYZ.txt with name 20120112_ 80809_XYZ.txt

Z:test> set STAMP=%STAMP: =0%

Z:test> echo rename XYZ.txt with name %STAMP%
rename XYZ.txt with name 20120112_080809_XYZ.txt

Z:test> ren XYZ.txt %STAMP%

Z:test> dir
Volume in drive Z is XP MP 2.21w

Directory of Z:test

12/01/2012 08:12 <DIR> .
12/01/2012 08:12 <DIR> ..
12/01/2012 08:08 0 20120112_080809_XYZ.txt
1 File(s) 0 bytes
2 Dir(s) 9,771,372,544 bytes free

05 January 2012

iTunes

PublishedActual
Birmingham New Street 07:10 07:10
London Euston 08:30 09:06

After a recent iTunes update, I have had problems receiving the Answer me This podcast, this caused much consternation as it’s one of my favourite podcasts.

Part way through trying to figure out what was wrong I became conscious of the problem solving order and techniques that I was applying, this is something I’ve noticed before and I find it quite interesting. Broadly speaking, problem solving is my job, whether that be a piece of code to fix a bug, a solution design or a full blown system architecture, all of these solve a problem in some way. When I have a problem to solve I usually draw on knowledge and experience to create a number of hypotheses which I can test, one by one, until I have an answer; if all are unsuccessful then I will resort to searching to see if there are any resolutions out there.

I usually base the order of testing on the order that I understand things to happen or on the order of obviousness, for example if a computer doesn’t turn on I’d check it plugged in, check the power lead with another computer, check the PSU in the computer, check motherboard, check components etc. Each time I test a hypothesis there will be one of three results, success, fail or perceived improvement. Based on the previous flow, if computer is not plugged in plug it in and turn it on - success, if the computer was plugged in but the lead doesn’t work on my computer or another computer this is a perceived improvement and the fuse or lead can be changed, if it still doesn’t work continue testing, after testing all likely power related components search the net for the answer.

So, coming back to the iTunes issues here is the rough running order followed to fix the problem:

  1. Check link still active - Right click podcast in iTunes and elect to ‘Copy podcast URL’, paste this into a browser and follow link - RSS feed was contacted and list of podcasts could be retrieved.
  2. Check content available - Clicking one of the links that comes up in the feed, doing this worked so proved that the link, content and ability to get the media from the site were ok.
  3. Unsubscribe and subscribe - Right click podcast and elect to ‘Unsubscribe podcast’ then ‘Subscribe podcast’ - at this point I could subscribe but the podcast list did not update and no new shows delivered
  4. Check other podcasts work - Check that content is delivered from other feeds, unsubscribe/subscribe another feed, all other feeds appeared to work
  5. Sign up to new podcasts - Look through iTunes and subscribe to a test feed. At this point I happened to click on The Collings and Herrin Podcasts which showed as a podcast I could not subscribe to, finally I could look for trends. After a couple of minutes of screen gazing the answer leapt out, ‘Explicit’, this little tag was the thing that the broken feeds had in common and what the subscribable feeds had missing.

Now I was certain that the upgrade of iTunes had reset or done something to stop only explicit content so I performed A quick check of the parental controls (‘Edit> Preferences> Parental’), this showed that I had been restricted to content suitable for those up to the age of 14 and the ‘Restrict Explicit Content’ checkbox was ticked, after unticking this box normal service was resumed and I could once again receive answer me this.

Since resolving this issue I have had to revisit these settings but at least I know exactly where to look and what the problem is now.