0

I'm trying to convert a time value from a text file from hr:min:sec.sec to just seconds. I have a file with event numbers (consecutive order, 1,2,3 etc.) in column 1 of each row and the rest of the row is event data as in my example below. I want to have the user enter two numbers, with which my script grabs the corresponding hr:min:sec of each event and converts into only seconds.

The file format is 4 000-01:04:10.983745 34.56 string1 string_2 (this would be the 4th line, its date/time, a duration in seconds, and two static strings in the next two columns.

I am using a for loop to grab tokens 1, 2, and 3 using : as the delims and then just trimming the strings for the purpose of performing arithmetic.

So %%A should be 4 000-01, %%B should be 04, and %%C should be everything else on the line. Now I just read batch doesn't support decmials, so I can do without them if needed. But this isn't returning anything:

setlocal enabledelayedexpansion enableextension

REM auto-setting event values for testing 
set begin=3 
set end=4

for /f "tokens=1,2,3 delims=:" %%A in ('findstr /b /c:"!begin![^0-9]" event.txt') do ( 
    set "hr=%%A" 
    set /A "min=%%B" 
    set "sec=%%C" 
    set /A "hr=!hr:~-2!" 
    set /A "sec=!sec:~0,2!" 
    set /A "total=(hr*3600)+(min*60)+sec" 
    echo !total!>>time.txt
)
exit /B
Squashman
  • 13,649
  • 5
  • 27
  • 36
Glycoversi
  • 77
  • 8
  • Why wouldn't you use a hyphen as well to grab the hour **01** instead of the **4 000**? Also you will need to strip leading zeros for `SET /A` to work correctly. And use a period as well for the delims. – Squashman Mar 17 '17 at 18:52
  • I didnt even think about the hyphen delim and I didnt know about the leading zero thing, thanks! Is that documented somewhere? – Glycoversi Mar 17 '17 at 18:56
  • Your findstr command is finding a line that begins with a 3 and any other number. You might want to use the /R option as well. I believe /C is literal string by default. – Squashman Mar 17 '17 at 19:00
  • Yes it is documented in the help for the `SET` command. `Numeric values are decimal numbers, unless prefixed by 0x for hexadecimal numbers, and 0 for octal numbers. So 0x12 is the same as 18 is the same as 022. Please note that the octal notation can be confusing: 08 and 09 are not valid numbers because 8 and 9 are not valid octal digits.` – Squashman Mar 17 '17 at 19:03
  • I forgot to add the `/R` option but I meant to. The script still doesn't output anything :/ And thanks for the documentation, I read that but didn't understand that it represents it as octal. – Glycoversi Mar 17 '17 at 19:05
  • Of course it does not output anything. As I said my my previous post, your input example line begins with a 4 and your regular expression is looking for a line that beings with 3 and any character that is not a number. – Squashman Mar 17 '17 at 19:09
  • Good point. Well the 4 was an example, the actual file has 100 lines, so 3 is in there. But i didnt understand hiw to correctly use the `[^0-9]` notation so this will not also return 31, 32, etc. If I only want the number 3 and nothing after it – Glycoversi Mar 17 '17 at 19:17
  • The `FINDSTR` command clearly states what your code does: `[^class] Inverse class: any one character not in set` So it will return lines that begin with a 3 and any other character that is not a number. 3A, 3#, 3&, 3space, etc.... – Squashman Mar 17 '17 at 19:20
  • Why don't you start by just figuring out the `FINDSTR` syntax by running this at the cmd prompt: `findstr /R /B /C:"3[^0-9]" event.txt` – Squashman Mar 17 '17 at 19:27
  • Yea I need to focus on understanding that better. Thanks for your help @squashman – Glycoversi Mar 17 '17 at 19:29
  • I found that my findstr section works with the number 3 itself, but not with !begin! even when the value of !begin! Is 3. Im baffled – Glycoversi Mar 17 '17 at 20:03
  • This is because you have an error in "setlocal enabledelayedexpansion enableextension**S**", so Delayed Expansion is not Enabled... – Aacini Mar 18 '17 at 13:18
  • What is the `000-` part? is it always `000-` literally? – aschipfl Mar 20 '17 at 18:14
  • @aschipfl The 000 represents the day of the year (001-365). The file consists of events and their corresponding times. Sometimes the times are actual days of the year and time of day (ie. 212-13:03:12 if it was july 31, 1:03:12 pm) and other times the event times in the file can be "absolute" time (ie. Days, hrs, min, sec start from 000-00:00:00.0 regardless of what day it actually is). – Glycoversi Mar 20 '17 at 18:38

2 Answers2

2

If your file format is:

line   4 000-01:04:10.983745 34.56 string1 string_2
delim       -  :  :  . 
token    1   2  3  4
var      -   A  B  C

A common technic to avoid the leading zero/octal problem is to prefix a two place decimal with a literal 1 and subtract 100. Set /A allows multiple calculations on a line seperated by a comma, the vars don't need to be enclosed in percent signs (doesn't apply to for/arg vars).

@Echo off
setlocal enabledelayedexpansion enableextensions
for /f "tokens=2-4 delims=-:." %%A in (
  'findstr /b /C:"4 " event.txt'
) do Set /A "hr=1%%A-100,min=1%%B-100,sec=1%%C-100,total=hr*3600+min*60+sec"
echo Total is %total% (hr=%hr%, min=%min%, sec=%sec%)
echo %total% >>time.txt
exit /B

Sample output:

Total is 3850 (hr=1, min=4,sec=10)
  • Thats a clever trick with the 100 subtraction. Thanks for the help, but for some reason my script returns 3 as well as 30-39, when a variable with a value of 3 is used in the findstr argument... – Glycoversi Mar 17 '17 at 20:41
  • Well the regex with the anchor at the begin `^`I used is the reason, change it above soon. Is it intended to have more than one find via the for loop? –  Mar 17 '17 at 20:55
  • @Glycoversi: I invite you to review [this answer](http://stackoverflow.com/questions/42603119/arithmetic-operations-with-hhmmss-times-in-batch-file/42603985#42603985) – Aacini Mar 17 '17 at 21:06
  • Wow. That was lazy on my part, i didnt see that. But I think my real issue is sending the user input number into the findstr literal string option as `findstr /b /r /c:"!begin![^0-9]" event.tab` and it not only returning the line beginning with the number `3` but those beginning with any numbers in the 30's. – Glycoversi Mar 17 '17 at 22:45
  • I'm not sure your setlocal command works at all because there is an s missing in `setlocal enabledelayedexpansion enableextensions` Second is that `findstr /b /r /c:"%begin%[^0-9]" event.tab` should be okay. Testing should always be in an open cmd window. If a comment should get attention from another person you should addres him via @Name. –  Mar 17 '17 at 22:48
  • Yay! It works and only grabs 3, and not 30-39 when I use percents instead of exclamations around the `begin` variable in findstr. Why is this, or where should I look to find the answer, @LotPings? – Glycoversi Mar 17 '17 at 23:33
  • Thanks for the links. Ive been finding ss64.com super useful, but the second link is either the wrong one or the relation of DEVE to distributed make systems is waaaaay over me. Thanks again, @Lotpings. – Glycoversi Mar 18 '17 at 00:35
  • The second link was broken. Second try: Well delayed expansion is a support evergreen, read [here the basics](https://ss64.com/nt/delayedexpansion.html) or [here for in depth understanding](https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts). –  Mar 18 '17 at 00:42
0

Here is an approach that regards the fractional seconds also, rounded to six fractional figures:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_SOURCE=event.txt"
set "_TARGET=time.txt"
set "_REGEX=^[0-9][0-9]* [0-3][0-9][0-9]-[0-9][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9]* "

rem // Convert filtered lines:
> "%_TARGET%" (
    for /F "tokens=1-9* delims=:.- " %%A in ('findstr /R /C:"%_REGEX%" "%_SOURCE%"') do (
        rem // Extract and store hour, minute, second values:
        set "HOUR=1%%C" & set "MIN=1%%D" & set "SEC=1%%E"
        rem // Extract and store fractional seconds and also the static strings:
        set "FRAC=1%%F0000000" & set "STR1=%%I" & set "STR2=%%J"
        rem // Convert hour, minute, second values to decimal integers:
        set /A "HOUR%%=100, MIN%%=100, SEC%%=100"
        setlocal EnableDelayedExpansion
        rem // Convert fractional seconds to decimal number:
        set /A "FRAC=!FRAC:~,7!%%1000000+!FRAC:~7,1!/5"
        rem // Compute integer seconds, round to 6 decimal places:
        set /A "SEC+=60*(MIN+60*HOUR)+FRAC/1000000" & set "FRAC=000000!FRAC!"
        rem // Rebuilt line with time value replaced by fractional seconds:
        echo %%A %%B-!SEC!.!FRAC:~-6! %%G.%%H !STR1! !STR2!
        endlocal
    )
)

endlocal
exit /B
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Im sorry for being dense; i dont need the day calculated in seconds. But after removing the day components, the shell returns an error that the argument is too long in findstr – Glycoversi Mar 21 '17 at 18:27
  • Also, i dont understand what `set /a hour%%=100` etc. does? – Glycoversi Mar 21 '17 at 18:29
  • I removed the day number from conversion now. `HOUR` holds a two-digit number initially, which may begin with `0` (e. g., `08`); so firstly, I do `set "HOUR=1%%C"` (so it's `108`), then `set /A "HOUR%%=100` (so it's `8`), all this to remove the leading zero (`%%` it parsed to `%` and is the modulo operator), because leading zeros denote octal numbers, which lead to unexpected results or errors as `8` and `9` are invalid octal digits. – aschipfl Mar 21 '17 at 18:38
  • Concerning `findstr`: sorry, I changed the search expression after testing; I reverted that now. What version of Windows are you using? XP? `findstr` has changed since then and might still return an error under XP... – aschipfl Mar 21 '17 at 18:45
  • Im using Windows 8.1 – Glycoversi Mar 21 '17 at 18:48
  • I shortened the `_REGEX` string due to faulty behaviour of `findstr` (there are several bugs -- see also this thread: [What are the undocumented features and limitations of the Windows FINDSTR command?](http://stackoverflow.com/q/8844868))... – aschipfl Mar 21 '17 at 19:07