ThG
ThG

Reputation: 2401

Vim strftime calculations

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

Answers (2)

ThG
ThG

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

Ben
Ben

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

Related Questions