DEV Community

SÃĐrgio AraÚjo
SÃĐrgio AraÚjo

Posted on Edited on

Formating Dates With Vim Substitutuions

The problem

I have stumbled upon an article on how to format dates using vim sub-expression and sub-match tricks in order to format dates, but what happens is that the original article shows examples that work on MacOS and does not have comments section. So I decided to adapt what I have learned reading the article and some personal research.

Let's say you have a HTML file with a large number of lines like this:

<time datetime="2017-10-17">2017-10-17</time>
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Our mission is to change the view of the result to the public, keeping our internal html as it is, so the change will be:

<time datetime="2017-10-17">october 17, 2017</time>
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

The regex to match our date

/>\zs\v\d{4}-\d{2}-\d{2}

>  .................. literal >
\zs ................. start of our match
\v .................. very magic search (avoid backslashes)
\d .................. digits [0-9]
\{4} ................ four times
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Using an expression in our substitution

If you have a series of numbers in your file and want to increase them on the substitution you can go:

0 first line
1 second line
2 third line

:%s/\v\d+/\=submatch(0)+1

\v .......... very magic
\d+ ......... a digit or more
\=submatch(0)  the whole search match
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Of course, in the above example we could have done:

:g/./exec "normal \<c-a>"
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Whic means:

.  ................ every lines that has at least one char '.'
exec .............. execute
normal ............ a normal command
\<c-a> ............ as we used double quotes: the Ctrl-a to increase
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

But the problem is that in some situations things are a little more complex

You can even use functions as expressions in substitutions. Copy the function bellow to the clipboard:

function! Hello()
    return "Hello World"
endfunction
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

and run:

:@0
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

The above command loads de function with no need to save on your vimrc.

Now let's substitute "amazing" with the return of our function:

This is amazing
This is amazing
This is amazing
This is amazing
This is amazing
This is amazing

:%s/amazing/\=Hello()
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

So for the dates we can do:

%s/>\v\zs\d{4}-\d{2}-\d{2}/\=system('date -d "'.submatch(0).'" +"%B %d, %Y"')/g

\=system() ................ calls any system command
date -d ................... use a parameter as date input
.    ...................... used for concatenation
+"%B %d, %Y" .............. date format we want
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Update

I have just read a comment from Filipe Brandenburger giving us a useful update, he says:
For the replacement, also possible to use Vim functions strftime() and strptime(), so you don't need to shell out to an external date binary..

:%s/>\v\zs\d{4}-\d{2}-\d{2}/\=strftime("%B %d, %Y", strptime("%Y-%m-%d", submatch(0)))/g
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ† āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

But on my neovim when I try to use this solution it says: Unknown function "strptime"

Top comments (2)

🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
filbranden profile image
Filipe Brandenburger •

Great article, as usual!

For the replacement, also possible to use Vim functions strftime() and strptime(), so you don't need to shell out to an external date binary..

:%s/\v\d{4}-\d{2}-\d{2}/\=strftime("%B %d, %Y", strptime("%Y-%m-%d", submatch(0)))/g
🏆 āļĒāļ­āļ”āļ™āļīāļĒāļĄ: voyegr/formating dates with vim substitutuions dof - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
voyeg3r profile image
SÃĐrgio AraÚjo •

Filipe, it seems that my neovim does not have the function "strptime"