简体   繁体   中英

Relative time for views in Play Framework 2.1

It seems like the Play Framework used(?) to have a since() function to get relative time (like "4 minutes ago") in views for Play 1.x. This is mentioned as a Date Extension here

However in Play 2.1 this doesn't appear to work anymore. I get value since is not a member of java.util.Date ... Additionally I can't find any other references to since() (in the context of Play 2.1) online.

Is there a proper/default way of handling this common case? I feel like I must be missing something important since this seems to no longer be supported?

Thanks!

The since() method is unavailable since beginning of the 2.0 branch.

Not a direct answer, but if it's possible I'd suggest to use JavaScript plugin for this task for an example: timeago jQuery plugin reasons:

  • It doesn't require calculating it in the controller
  • You can cache your site (for an example in the memory) for long time, and since time will be still displayed correctly as it's updated on the client-side.
  • It auto updates even without page refresh (like here, on the Stack Overflow)

As far as I can tell this isn't possible to do any more (by default in Play2.1). Please correct me if I am wrong. Here's how I recreated it. As mentioned here I "pimped" the "Date" class:

// File app/views/pimps.scala

package views


package object pimps {

  import java.util.Date
  import org.joda.time.DateTime;
  import org.joda.time.Period;

  class PimpedDate(col: Date) {

    def since() = {
      def addS(b: Int) = if (b == 1) "" else "s"

      val now: DateTime = new DateTime();
      val period: Period = new Period(new DateTime(col), now);
      var r: String = "";

      if (period.getYears() > 0) {
        r = period.getYears() + " year" + addS(period.getYears()) + " ago";
      } else if (period.getWeeks() > 0) {
        r = period.getWeeks() + " week" + addS(period.getWeeks()) + " ago";
      } else if (period.getMonths() > 0) {
        r = period.getMonths() + " month" + addS(period.getMonths()) + " ago";
      } else if (period.getDays() > 0) {
        r = period.getDays() + " day" + addS(period.getDays()) + " ago";
      } else if (period.getHours() > 0) {
        r = period.getHours() + " hour" + addS(period.getHours()) + " ago";
      } else if (period.getMinutes() > 0) {
        r = period.getMinutes() + " minute" + addS(period.getMinutes()) + " ago";
      } else {
        r = period.getSeconds() + " second" + addS(period.getSeconds()) + " ago";
      }

      r
    }
  }

  implicit def pimpDate(col: Date) = new PimpedDate(col)
}

Then in my view I can just import the above:

@import views.pimps._

and then use since() just as you could in Play1

<td>@record.created_on.since()</td>

Please comment/answer if there's a better way to do this or write the scala code...

@Jack suggested a pretty good answer.

Here is a version of his code that might be useful because it'll enable some composition if needed (the check function is not composing but could be easily changed to compose and show a more detailed since value)

package object pimps {

  import java.util.Date
  import org.joda.time.DateTime;
  import org.joda.time.Period;

  def step(f:Period => Int)(fi:String):Period => Option[String] = {
    def g(i:Int = 1) = i + " " + fi + (if (i==1) "" else "s") + " ago"

    (p:Period) => {
      f(p) match {
        case 0 => None
        case 1 => Some(g())
        case x => Some(g(x))
      }
    }
  }
  val yearsStep = step(_.getYears)("year")
  val monthsStep = step(_.getMonths)("month")
  val daysStep = step(_.getDays)("day")
  val hoursStep = step(_.getHours)("hour")
  val minutesStep = step(_.getMinutes)("minute")
  val secondsStep = step(_.getSeconds)("second")
  val steps = Seq(yearsStep, monthsStep, daysStep, hoursStep, minutesStep, secondsStep)

  val check = 
    (p:Period) =>
      steps.collectFirst {
        case f if f(p).isDefined => f(p).get
      }

  implicit class PimpedDate(col: Date) {

    def since() = {
      val period: Period = new Period(new DateTime(col), DateTime.now);
      check(period)
    }
  }
}

As you can see, for now we stop at the first matching level, and also we repeat the getter (getYears if matching will be called twice).

Nevertheless, another thing to note is the usage of implicit class which has been introduced in Scala 2.10 to ease the pimping

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM