Vim : time increment in a schedule

297 Views Asked by At

I'm new to Vim and I'm trying to see what I can / can't do with it. I would like to increment a list of times like this :

09:00 Breakfast 
09:30 RSS 
09:50 Stretch
10:00 Main proj
13:00 food
14:00 Main proj...

Lets say I woke up too late, and I'd like to quickly increment everything by 45 minutes in Vim

I tried a macro :

  • Time in minutes : 09:00 -> 09 * 60 + 00
  • + 45
  • SUM with Ctrl + R =
  • Trying to reformat it (int)SUM/60 : SUM - ((int)SUM/60)*60

But I couldn't get it to work (it is such a long macro) and I'm quicker at doing it manually.

On top of that, even if I succeed I can't figure out how to keep the "0" of "09" to keep my numbers in a column.

Is it possible in Vim ? Maybe a regex ?

[edit] For the purpose of exercise, I'd rather use macros, a regex, or even a function in VimScript than a plugin

4

There are 4 best solutions below

0
On BEST ANSWER

So, I tried in a regex ( remove return carriage) :

%s@\(\d\d\):\(\d\d\)@\=printf('%.2d:%.2d'((submatch(1)*60+submatch(2)+45)/60),
((submatch(1)*60+submatch(2)+45)-((submatch(1)*60+submatch(2)+45)/60)*60))@

it's quite inelegant and i'd like to have inc = 45 and sum = (submatch(1)*60+submatch(2)+inc), I would need to declare the variables on the same line as the printf... but it works ;)

Inside visual selection : with '<,'> instead of %.

One problem of course is that it doesnt loop back around midnight, but I guess for that @steffen's answer would be better

Edit : I found that modulo existed in Vimscript and I couldn't resist...now it loops around midnight :

%s@\(\d\d\):\(\d\d\)@\=printf('%.2d:%.2d',((submatch(1)*60+submatch(2)+45)/60)%24,
(submatch(1)*60+submatch(2)+45)%60)@

Edit 2: And here is the code in a function using the func-range (thanks @Kent)

function! IncrementTime(mins) range
    "Increments time within a range ( current line or selection)
    let pat = '(submatch(1)*60+submatch(2)+'.a:mins.'+1440)'
    execute a:firstline.','.a:lastline.'s@\(\d\d\):\(\d\d\)@\=printf("%.2d:%.2d",('.pat.'/60)%24,'.pat.'%60)@'
endfunction

I had to add 1440 to avoid negative hours when one decrements

3
On

I just found OP's new edit, it seems that he is looking for a little vimscript function. Here is one, NOT generic function, however it works for your needs.

Note, after the minute increment, the result could be greater (later) than 24:00 in this case, the date info will be lost, an example is adding 45mins on 23:30 will result 00:15

function! IncTime(mins) 
    let pat = '^\d\d:\d\d\ze '
    for i in range(line('$'))
        let tss = matchstr(getline(i+1), pat)
        if tss
            let ts = split(tss,':')
            let ns = 60*ts[0] + ts[1] + a:mins
            let nts = printf('%.2d:%.2d', (ns/60)%24, ns % 60)
            execute i+1.'s/'.pat.'/'.nts
        endif
    endfor
endfunction

source it, and in your file call :call IncTime(45) to check the changes applied. You can also pass different offset other than 45 to the function, like 10, or even 2000

enter image description here

0
On

Date and time calculations always turn out to be more difficult than expected. Think of daylight savings for instance. You should let some other tool make the calculations. If you're on Linux, you could try to this with date:

let @a=substitute(system("date -d @$(($(date -d " . substitute(getline('.'), '\(\S\+\).*', '\1', '') . " +\\%s)+45*60)) +\\%H:\\%M"), ".$", "", "")

This will add 45 Minutes to the time in the beginning of the current line (delimited by space) and put it into register a. Your macro could then delete the time and replace it with @a:

"_dE
"aP0

BTW: This would also work with a string like "now":

09:00 Breakfast (before)
09:45 Breakfast (after)

now Breakfast (before)
14:45 Breakfast (after)
5
On

It is possible only (or write function as Kent commented) with some plugins, like this:

Speeddating plugin