OCPsoft

Convert elapsed timestamps, like, “in 3 minutes!”

PrettyTime is an OpenSource time formatting library. Completely customizable, PrettyTime creates human readable, relative timestamps like those seen on Digg, Twitter, and Facebook. It’s simple, get started “right now!” and in over 18 languages!

See also: PrettyTime Grails Plug-in, PrettyTime with JSP.

Follow @ocpsoft and @lincolnthree on Twitter.


Features:

  1. Generate human-readable timestamps like, “right now”, “2 days ago”, or “3 months from now”
  2. Simple single interface – easy to learn.
  3. Entirely customizable. Provide your own TimeUnit and TimeFormat objects for complete control.
  4. Provided integration for the JSF web-application framework

(Fork us on GitHub and send pull requests with support for other frameworks!)

Documentation:

Using PrettyTime is simple.

  1. Basic use in a Java App
  2. i18n support (contributed by Thomas Weitzel)
  3. Creating a custom TimeUnit
  4. Using PrettyTimeConverter in JSF
  5. Examples using JUnit

Installation


Extract necessary JAR files into your /WEB-INF/lib directory. This step is pretty straight-forward, right? Or include a maven dependency in your pom.xml (optional)

/pom.xml
<dependency>
  <groupId>org.ocpsoft.prettytime</groupId>
  <artifactId>prettytime</artifactId>
  <version>1.0.8.Final</version>
</dependency>

Basic use in a Java Application

PrettyTime, by default, uses the current time as the point of reference (reference time) for calculating the elapsed, or remaining time to the Date argument.

BasicJavaApp.java
import java.util.Date;
import org.ocpsoft.pretty.time.PrettyTime;

public class BasicJavaApp
{
	public static void main(String[] args) 
	{
		PrettyTime p = new PrettyTime();
		System.out.println(p.format(new Date()));
		//prints: “right now”
	}
}

See below for more examples using JUnit.


i18n and multiple-languages support

PrettyTime now supports internationalization via resource bundles. Simply place an appropriate Resources_**.properties bundle on the classpath: org.ocpsoft.pretty.time.i18n, then set the desired Locale into your PrettyTime object. (contributed by Thomas Weitzel)

If you create a new Locale resource bundle for PrettyTime, please fork the project, and submit a pull request.

Locales with built-in support:

  • Bulgarian – BG: Марио Георгиев
  • Chinese – ZH_CN: 陈正华
  • Croatian – Miroslav Rešetar
  • Dutch – NL: Bram Van Dam
  • English – DEFAULT
  • Estonian – Matti Jagula
  • French – FR: Eric Palpacuer
  • German – DE: Thomas Weitzel
  • Hungarian – Balázs Németh
  • Italian – IT: Mirco Attocchi
  • Norwegian – Magnus Byrkjeflot – www.mylog.no
  • Polish – Upender Gilakathula
  • Portugese – PT: Gustavo Ehrhardt
  • Romanian – Upender Gilakathula
  • Spanish – ES: Bruno Resano
  • Slovenian- SL: Uros Majeric
  • Turkish – Halil
  • Vientamese – Xuân Tính – Blog
Basic_i18n.java
import java.util.Date;
import java.util.Locale;

import org.ocpsoft.pretty.time.PrettyTime;

public class Basic_i18n
{
    public static void main(final String[] args)
    {
        PrettyTime p = new PrettyTime(new Locale("de"));
        System.out.println(p.format(new Date()));
    }
}

Creating a custom ResourceBundle

You can find full examples of resource bundles packaged inside pretty-time.jar. Also, if you create a new Locale resource bundle for PrettyTime, please fork the project, and submit a pull request.

org/ocpsoft/pretty/time/i18n/Resources_de.java
package org.ocpsoft.pretty.time.i18n;

import java.util.ListResourceBundle;

public class Resources_de extends ListResourceBundle
{
    private static final Object[][] CONTENTS = new Object[][] {
                                  { "CenturyPattern", "%n %u" },
                                  { "CenturyFuturePrefix", "In " },
                                  { "CenturyFutureSuffix", "" },
                                  { "CenturyPastPrefix", "Vor " },
                                  { "CenturyPastSuffix", "" },
                                  { "CenturyName", "Jahrhundert" },
                                  { "CenturyPluralName", "Jahrhunderten" }
                                  //...
                                  };
    }

    @Override
    protected Object[][] getContents()
    {
        return CONTENTS;
    }
}


Creating a custom TimeUnit:

TimeUnits are the units of measure in PrettyTime. They can be as long or as short as desired, and can be formatted into any necessary pattern. All that needs to be done is to implement the TimeUnit interface, and provide a default TimeFormat

Month.java
package org.ocpsoft.pretty.time.units;

import org.ocpsoft.pretty.time.BasicTimeFormat;
import org.ocpsoft.pretty.time.TimeFormat;
import org.ocpsoft.pretty.time.TimeUnit;

public class Month implements TimeUnit
{
    private static final TimeFormat defaultFormat = new BasicTimeFormat().setPattern("%n %u").setPastSuffix(" ago")
            .setFutureSuffix(" from now");

    private TimeFormat format = defaultFormat;
    private long maxQuantity = 0;
    private final long millisPerUnit = 2629743830L;
    private String name = "month";
    private String pluralName = "months";
    
    /* getters and setters */
}

TimeFormat is also simple — and is the core of the Formatting platform.

TimeFormat.java
package org.ocpsoft.pretty.time;

public interface TimeFormat
{
    /**
     * Given a populated Duration object. Apply formatting and output the
     * result.
     */
    public abstract String format(final Duration duration);
}

See BasicTimeFormat for an implementation example using regular expressions


JavaServer Faces support via PrettyTimeConverter

PrettyTime includes a JSF Converter for easy output formatting. No additional configuration is required to use this object, since PrettyTime includes its own META-INF/faces-config.xml — Just include the PrettyTime jar file or dependency on your classpath.

example.xhtml
<h:outputText value="#{exampleBean.futureDate}">
	<f:converter converterId="org.ocpsoft.PrettyTimeConverter"/>
</h:outputText>

In this example, futureDate must be a valid java.util.Date object.


Examples using JUnit:

See below for creating custom time units and formats:

PrettyTimeTest.javaView complete file
package org.ocpsoft.pretty.time;

import static org.junit.Assert.*;

import java.text.SimpleDateFormat;
import java.util.*;
import org.junit.*;
import org.ocpsoft.pretty.time.*;

public class PrettyTimeTest
{

   @Test
   public void testRightNow() throws Exception
   {
      PrettyTime t = new PrettyTime();
      assertEquals("moments from now", t.format(new Date()));
   }

   @Test
   public void testMinutesFromNow() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      assertEquals("12 minutes from now", t.format(new Date(1000 * 60 * 12)));
   }

   @Test
   public void testHoursFromNow() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      assertEquals("3 hours from now", t.format(new Date(1000 * 60 * 60 * 3)));
   }

   @Test
   public void testDaysFromNow() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      assertEquals("3 days from now", t.format(new Date(1000 * 60 * 60 * 24 * 3)));
   }

   @Test
   public void testWeeksFromNow() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      assertEquals("3 weeks from now", t.format(new Date(1000 * 60 * 60 * 24 * 7 * 3)));
   }

   @Test
   public void testMonthsFromNow() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      assertEquals("3 months from now", t.format(new Date(2629743830L * 3L)));
   }

   // ... and so on

   /*
    * Past
    */
   @Test
   public void testMomentsAgo() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(6000));
      assertEquals("moments ago", t.format(new Date(0)));
   }

   @Test
   public void testMinutesAgo() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(1000 * 60 * 12));
      assertEquals("12 minutes ago", t.format(new Date(0)));
   }

   @Test
   public void testCenturiesAgo() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(3155692597470L * 3L));
      assertEquals("3 centuries ago", t.format(new Date(0)));
   }

   // ...


   /*
    * Format duration lists
    */
   @Test
   public void testFormattingDurationListInThePast() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(1000 * 60 * 60 * 24 * 3 + 1000 * 60 * 60 * 15 + 1000 * 60 * 38));
      List<Duration> durations = t.calculatePreciseDuration(new Date(0));
      assertEquals("3 days 15 hours 38 minutes ago", t.format(durations));
   }

   @Test
   public void testFormattingDurationListInTheFuture() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(0));
      List<Duration> durations = t.calculatePreciseDuration(new Date(1000 * 60 * 60 * 24 * 3 + 1000 * 60 * 60 * 15
               + 1000 * 60 * 38));
      assertEquals("3 days 15 hours 38 minutes from now", t.format(durations));
   }

   @Test
   public void testSetLocale() throws Exception
   {
      PrettyTime t = new PrettyTime(new Date(315569259747L * 3L));
      assertEquals("3 decades ago", t.format(new Date(0)));
      t.setLocale(Locale.GERMAN);
      assertEquals("vor 3 Jahrzehnten", t.format(new Date(0)));
   }

   SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");

   // Stores current locale so that it can be restored
   private Locale locale;

   // Method setUp() is called automatically before every test method
   @Before
   public void setUp() throws Exception
   {
      locale = Locale.getDefault();
      Locale.setDefault(Locale.ROOT);
   }

   // Method tearDown() is called automatically after every test method
   @After
   public void tearDown() throws Exception
   {
      Locale.setDefault(locale);
   }

}


Get updates from OCPSoft



Add OCPsoft to your Circles

Read Something New

Join the Discussion

Blatant Advertising

Meta