Reputation: 2401
I have a very simple ToDo file which looks like this :
130821 Go to the dentist
130824 Ask a question to StackOverflow
130827 Read the Vim Manual
130905 Stop reading the Vim Manual
I would like to calculate - each time I open the file - the number of days remaining until the different due dates (today is the 22nd of August 2013, i.e. 130822, in Paris), thus obtaining something like :
130821 -1 Go to the dentist
130824 2 Ask a question to StackOverflow
130827 5 Read the Vim Manual
130905 14 Stop reading the Vim Manual
but I do not know how to achieve that (and I do not know if it is reasonably possible : cf. glts'comment)
Your help would be appreciated.
Upvotes: 2
Views: 1567
Reputation: 2401
Although convinced by them, I was kind of disappointed by the answers given to my question. I tried to find a solution, and it seems I have almost succeeded. Needless to say, it is a clumsy contraption, but it works.
First of all, the file (slightly modified for testing purposes) :
130825 Past ToDo test
130827 Today's ToDo test
130829 In two days ToDo test
130831 Another test
130902 Change of month ToDo test
131025 Another change of month test
Second, the data given by http://www.epochconverter.com :
1 day = 86400 seconds
1 month (30.44 days) = 2629743 seconds
1 year (365.24 days) = 31556926 seconds
Third, the function I tinkered :
function! DaysLeft()
:normal! gg
let linenr = 1
while linenr <= line("$")
let linenr += 1
let line = getline(linenr)
:normal! 0"ayiw
:.s/\(\(\d\d\)\)\(\d\d\)\(\d\d\)\>/\1
:normal! 0"byiw
:execute "normal! diw0i\<C-R>a"
:normal! 0"ayiw
:.s/\(\d\d\)\(\(\d\d\)\)\(\d\d\)\>/\2
:normal! 0"cyiw
:execute "normal! diw0i\<C-R>a"
:normal! 0"ayiw
:.s/\(\d\d\)\(\d\d\)\(\(\d\d\)\)\>/\3
:normal! 0"dyiw
:execute "normal! diw0i\<C-R>a"
let @l = strftime("%s")
:execute "normal! 0wi\<C-R>=((\<C-R>b+30)*31556926+(\<C-R>c-1)*2629743+(\<C- R>d-1)*86400+1-\<C-R>l)/86400\<Enter>\<tab>"
exe linenr
endwhile
endfunction
Fourth, the results :
130825 -2 Past ToDo test
130827 0 Today's ToDo test
130829 1 In two days ToDo test
130831 3 Another test
130902 5 Change of month ToDo test
131025 58 Another change of month test
As you can see, there is a glitch : the 130829 ToDo is shown as being in 1 day instead of 2 days (because I did not do floating point calculation). But in fact I consider that as a programming glitch (among others…), but a psychologically sound one : In fact I have only one full day's work available.
It may be an exercise in futility, but this made me study : capture, loops, registers, and of course previous StackOverflow precious answers in order to give a pure Vim answer.
Thank you for all the improvements you will bring to my answer.
Upvotes: 0
Reputation: 8905
This command will do the desired substitution but the wrong calculation (it WON'T work as-is):
%s#\v^(\d{6})( -?\d+)?#\=submatch(1).' '.(submatch(1)-strftime("%y%m%d"))
See :help sub-replace-expression, :help submatch(), :help strftime().
Note my use of \v
to put Vim's regex parser into "very magic" mode.
You could easily apply this whenever you load the file using a BufReadPost autocmd.
Something like:
augroup TODO_DATE_CALC
au!
au BufReadPost myToDoFileName %s#\v^(\d{6})( -?\d+)?#\=submatch(1).' '.(submatch(1)-strftime("%y%m%d"))
augroup END
Find out the time since unix epoch for a certain date time? shows how to get a unix time for a specific date, you can use the system() function in Vim to grab the result. But I don't have a system to test that out on at the moment. I think you might be out of luck, on Windows.
Unless you can change your file format to include unix time...then it ought to be fairly easy.
Upvotes: 2