Natural language date conversion for TextMate

[Tweet : nvALT]

I’ve been flirting with a plain-text to-do system again. The biggest problem for me is that a plain text system opens up so many possibilities for fiddling and scripting. I always end up fiddling more than working when I try it. I don’t see any reason this time would be different, but it’s Sunday and I have some extra time on my hands after being snowed in today. So I’m fiddling.

In the process, I wrote a quick TextMate command which lets me enter a date in natural language and have it converted to whatever format I need for my system. It has variables at the top of the command for defining the date format and output string template. I packaged it up in its own little bundle for people to play with. The command is similar to what I built as a TaskPaper script a while back. Just download at the end of the post, unzip and double-click to install.

## Customizing

The output format of the command defaults to a full date in the system’s preferred format. This makes it easy to see the effect of various strings. For most purposes, you’ll want something more along the lines of “2011-02-22” instead. To change the format, you just need to edit the dateformat variable at the top of the command’s script.

To edit the command, just go to Bundles > Bundle Editor > Show Bundle Editor and find the Date Entry bundle. Select the Natural Date Entry command and edit it in the field on the right.

Date Format

There’s a commented-out dateformat replacement above the current variable, and you can modify it to fit whatever you need. Don’t forget to comment out or remove the current variable if you uncomment the one above it. The % format elements use Ruby’s strftime format. I built the command to work with GTDAlt and TaskPaper, and on my system both use the YYYY-MM-DD format, so that’s what the secondary option is set to.

Output Template

To be practical, you probably also need to output some delimiters with the date. In GTDAlt, it would look like “due:[2011-02-22]”, and in TaskPaper it would look like “@due(2010-02-22)”. You can set this up using the outputtemplate variable below dateformat. It uses %date% as a placeholder which will be replaced with the date in the format you specified above. As an example, if you wanted to use the command with TaskPaper files, you would set it to '@due(%date%)'.


The command uses Command-Shift-D by default, but you can change that to whatever’s clever when you’re in the Bundle Editor. When run, it pops up an input dialog courtesy of TextMate’s built-in dialog system. You can enter text in an intuitive natural language format and it will output the date based on the variables you’ve defined. Here are some example strings:

  • tomorrow
  • tomorrow 3pm
  • wednesday
  • wednesday morning
  • wed
  • next thursday
  • in one week
  • in three days
  • in 3 days

You get the idea. I also set it up to take “+” modifiers. You can add any number of days at the end of a string, or just use the plus modifier to add days to today. For example:

  • thu+7
  • +2
  • tomorrow + 3

It will roll with any of those punches. Abbreviated days have to be three characters, i.e. mon, tue, wed, thu, fri, sat, or sun.

Moving the command

This command has to be distributed in a bundle because it requires the Ruby library “Chronic” for the date conversion. The library is included in the Support/lib folder of the bundle. If you happen to have RubyGems installed, you can install the Chronic gem (sudo gem install chronic) and then modify the command to allow you to put it wherever you like without needing the support folder at all. To make the command use the gem instead of the bundled library, change the require statements in the command to look like this:

require SUPPORT + '/lib/ui'
require SUPPORT + '/lib/exit_codes'
require 'rubygems'
require 'chronic'

It would also be pretty easy to port to any other system, including an OS X system service. You’d just need to make sure you include the Chronic library, either bundled or install the gem, and find a way to get the text input without using TextMate’s dialog. CocoaDialog or a service that acts on selected text would fit the bill.

I think this will be handy for more than just to-do lists. Let me know if you find a use for it elsewhere!

Man, it took me twice as long to write that post as it did to put together the command and the bundle. Like I said: Sunday.


Date Conversion for TextMate v1.0

A TextMate bundle which contains one command: Natural Date Entry. When triggered, it requests a natural-language date string (e.g. “tomorrow 3pm”), converts it to a configurable date format, and outputs it with a customizable template.

Updated Sun Feb 20 2011.

DonateMore info…