Humanizing dates

Hello!

What would be the easiest way to pick up a Date or DateTime object and “humanize” them, like:

  • Next wednesday
  • Last friday
  • 10 hours ago
  • Next month

Is there a Ruby library, gem or Rails plugin that helps on assembling such phrases from date/datetime information?

Could someone put me on the right direciton?

Thanks!

Marcelo.

distance_of_time_in_words might be like what you’re looking for (from ActionView::Helpers::DateHelper).

Cheers,

James Brooks

Good Dog Design

Thanks a lot!

This solves almost all of my specs.

One thing that I’m trying to figure out,though, is, given a date, output something like:

“Last wednesday” or “Next friday”…

Would you know a solution from the top of your head?

Marcelo.

I don’t know of something that works that way around, that you might have to code yourself. Perhaps you could get inspiration from a gem called chronic (which does the reverse of what you want, e.g. It can take a string “next wednesday” and calculate a date)… Maybe it can do the reverse, I’ve never checked :slight_smile:

Cheers,

James Brooks

Good Dog Design

Thanks James, I will do that.

Clever and simple solution, perfect.

The issue with date/time is that things can get ambiguous and complex. The solution provided before could work to some extent and were similar but much more complex and while I could add code to support the use-case, I’m just so glad you did and shared it! Thanks a lot!

Marcelo.

That is neat. I don't have anything real to contribute other than for
some odd reason I was talking about this issue last night with my wife
(not ruby, but the date thing).

Let's say it's Thursday.

Is "next saturday" in two days? Or in nine? We decided it was nine.
"this saturday" is in two days. But we agreed that "the next
saturday" is in two days.

So, when you say "next saturday" which do you mean? :slight_smile:

Maybe it's just us and the folks around us that gets confused by that,
but it's something to consider.

-philip

Hey Philip,

I think that, for weekday names, you have to keep you have to take into account the week (7 days).

For example, let’s say we have a Date object that “A” represents 11/08/2008 and another one “B” that represents 18/08/2008. Both are mondays.

Now, we have a Date object that represents today - 07/08/2008.

If you load Ryan’s code and do this:

A.to_words

The following will happen:

  1. Is this date the same as today (Date.today)? If so, output “Today”;

  2. Is this date the same as yesterday (Date.today-1)? If so, output “Yesterday”;

  3. Is this date included in the set = {today - 7 (one week ago) … yesterday} - this will essentially create an array that has date objects from one week ago until yesterday. If the date is included in this array, and as we have considered it to be “last week” and as we know that the date is not yesterday, nor the current date nor tomorrow, we can say this date was the last “weekday”.

  4. Applies the same logic as above, but inverted (one week from now).

Now, things get a little more complicated. For example, the next test says:

elsif ((Date.today + 8)…(Date.today + 14)).include?(self)

“Two #{self.strftime(”%A")}s away"

What does that mean? From what I could understand, the test checks if the Date object being converted is in a period of time that starts one week + 1 from now ( ss ) and ends two weeks - 1 from now. Considering we have the following date object: 14/08/2008 and today is today’s date (07/08/2008):

today + 8 = 15/08/2008 today + 14 = 21/08/2008

S M Tu W Th F S S M Tu W Th { F S S M Tu W Th } F S S … > > >

        Today                 14/08/2008                   |   
                                                               21/08/2008

This test wouldn’t catch our date object, but the previous one would do (Next #{weekday}).

But one important point is that he seems to build upon last the previous tests, so I think the order is important, and also explains the odd offsets he does in the checks, the code “considers” something like “hey, if this date is not tomorrow then I can omit tomorrow from the next check…”.

Calculations with Dates are confusing, at least to me. That’s how I could interpret Ryan’s code, and I’m sure it is not a complete view yet. I don’t know if there’s a pattern for such thing or any way to simplify this code, that’s with Ryan!

Please, correct me if I’m wrong!

Marcelo.

I tried simplifying the code this morning, first it would check to see if the date was today, if so just print today, then it would check if the date is less than today and if so run all the checks for dates less than today, else run all the checks for dates greater than today. I think I updated the gist (can't check, on train writing emails offline) and there's a person called lachie who forked it which may make the code a bit cleaner for you.

Cool. Just checked it out. I’m glad my post turned out into something useful for the community :slight_smile:

Also, I would like to note that this could be used together with the distance_in_time_in_words. Even though they appear to be similar, they fit in different use cases. I can see that distance_in_time_in_words tries do be more general and count in days/months and years, not weeks, also it doesn’t print weekdays. But it is useful for building more granular historical data, like “less than 1 hour ago”, and Ryan’s to_word more useful for schedule and calendar use-cases.

Cheers,

Marcelo.

I just read Philip's post and I realised that Date.today + 1..Date.today + 7 says "Next <blah>", instead of "This <blah>.. interesting point. I've updated the gist again:

http://gist.github.com/4363

It will now display "this coming Friday" for example of it's within the range of 6 days from today. This should mean that it'll say "this coming Thursday" for thursday next week, and "next Friday" for the friday that follows.