Question

Does anyone know of a .NET date/time parser similar to Chronic for Ruby (handles stuff like "tomorrow" or "3pm next thursday")?

Note: I do write Ruby (which is how I know about Chronic) but this project must use .NET.

Was it helpful?

Solution

We developed exactly what you are looking for on an internal project. We are thinking of making this public if there is sufficient need for it. Take a look at this blog for more details: http://precisionsoftwaredesign.com/blog.php.

Feel free to contact me if you are interested: contact@precisionsoftware.us

This library is now a SourceForge project. The page is at:

http://www.SourceForge.net/p/naturaldate

The assembly is in the downloads section, and the source is available with Mercurial.

OTHER TIPS

I don't, but there's a Java port called jchronic. If nothing else, it could provide a good jumping-off point for your own. Or perhaps you could use a semi-automatic Java to C# translator like Octopus to help translate it. (Or something better, if anyone knows of anything.)

Okay, another possible avenue: could you use the chronic code using IronRuby?

A .NET port of Chronic exists. See https://github.com/robertwilczynski/nChronic. I created a fork of it with some improvements and bug fixes, here: https://github.com/dorony/nChronic (sent pull requests, the author still hasn't responded).

@Blair Conrad - Good ideas! I tried to get Chronic running under IronRuby but had some problems with dependencies - I don't know that it's ready yet.

I found a project on Codeplex (DateTimeEnglishParser) that is attempting to do the same thing. It doesn't handle years or time yet, but it's a good start. I've worked on the project a little and contributed a patch to better handle written numbers.

It's an interesting problem, and has definitely helped me understand regular expressions better, so I think I'll keep working on it.

There was a similar thread earlier and it gave a link to a library on CodeProject that seems to do what you want: http://www.codeproject.com/KB/edit/dateparser.aspx but unfortunately the library seems to be written in MFC so you would have to make a DLL out of it and then call it from your .NET program.

Palmsey, I have just recently had the same requirment so I went ahead and wrote a simple parser. Its not the nicest code but it will handle things like:

"Today at 2pm" "Tuesday at 2pm - 15th july 2010 at 2am" "Previous Year at 2am - Tommorow at 14:30" "18th july 2010 at 2:45pm"

Stuck it on codeplex as maybe someone else will find it useful. Check it out: http://timestamper.codeplex.com/

I've checked several frameworks and Python's ParseDateTime worked the best. It can be used from .NET using IronPython.

If anyone's interested in a full sample project, comment on the answer and I'll try to create one.

EDIT

As requested, here is a simple project that you can use with the library:

http://www.assembla.com/code/relativedateparser/subversion/nodes

Try the following usage case, for example:

  • August 25th, 2008
  • 25 Aug 2008
  • Aug 25 5pm
  • 5pm August 25
  • next saturday
  • tomorrow
  • next thursday at 4pm
  • at 4pm
  • eod
  • tomorrow eod
  • eod tuesday
  • eoy
  • eom
  • in 5 minutes
  • 5 minutes from now
  • 5 hours before now
  • 2 hours before noon
  • 2 days from tomorrow

I'm not aware of one, but it sounded like a cool problem, so here's my whack at it (VB.NET):

Private Function ConvertDateTimeToStringRelativeToNow(ByVal d As DateTime) As String
    Dim diff As TimeSpan = DateTime.Now().Subtract(d)
    If diff.Duration.TotalMinutes < 1 Then Return "Now"

    Dim str As String
    If diff.Duration.TotalDays > 365 Then
        str = CInt(diff.Duration.TotalDays / 365).ToString() & " years"
    ElseIf diff.Duration.TotalDays > 30 Then
        str = CInt(diff.TotalDays / 30).ToString() & " months"
    ElseIf diff.Duration.TotalHours > 24 Then
        str = CInt(diff.Duration.TotalHours / 24) & " days"
    ElseIf diff.Duration.TotalMinutes > 60 Then
        str = CInt(diff.Duration.TotalMinutes / 60) & " minutes"
    Else
        str = CInt(diff.Duration.TotalMinutes).ToString() & " minutes"
    End If
    If str.StartsWith("1") Then str = str.SubString(0, str.Length - 1)
    If diff.TotalDays > 0 Then
        str &= " ago"
    Else
        str &= " from now"
    End If
    Return str
End Function

It's really not as sophisticated as ones that already exist, but it works alright I guess. Could be a nice extension method.

@ Burton: I think he meant the other way, at least from the example on the linked page:

  Chronic.parse('tomorrow')
    #=> Mon Aug 28 12:00:00 PDT 2006

  Chronic.parse('monday', :context => :past)
    #=> Mon Aug 21 12:00:00 PDT 2006

  Chronic.parse('this tuesday 5:00')
    #=> Tue Aug 29 17:00:00 PDT 2006

I thought I would take a stab at it too until I realized! (nice implementation though)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top