prettytime

Convert Java/Android Date() objects in just “a few minutes!”

Get Started, see how simple social date-formatting can be (2 steps)



1. Include PrettyTime in your Project

Add PrettyTime to your maven pom.xmlOr download the JAR
<dependency>
   <groupId>org.ocpsoft.prettytime</groupId>
   <artifactId>prettytime</artifactId>
   <version>5.0.7.Final</version>
</dependency>

<!-- To use snapshots, you must also use the Sonatype Snapshots respository -->
<repository>
   <id>sonatype-snapshots</id>
   <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>

2. Format some timestamps!

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

BasicJavaApp.java
import java.time.LocalDateTime;
import java.util.Date;
import org.ocpsoft.prettytime.PrettyTime;

public class BasicJavaApp
{
	public static void main(String[] args) 
	{
		PrettyTime p = new PrettyTime();

		// Traditional Date API:
		System.out.println(p.format(new Date()));
		//prints: “moments from now”

		// JDK 8 DateTime API:
		System.out.println(p.format(LocalDateTime.now().minusSeconds(1)));
		//prints: “moments ago”


		System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
		//prints: “10 minutes from now”
	}
}

See below for more examples using JUnit.



3. Use extensions for other frameworks.

  • Groovy on Grails – Visit plugin website.

  • Android – When using Android with ProGuard, you must add the following to your ProGuard configuration script:
    -keep class org.ocpsoft.prettytime.i18n.**


  • JavaServer Faces – PrettyTime comes with an extension for JavaServer Faces so that Date objects can be displayed using the standard JSF Converter system.

    First, you must include the JSF integration module.

    <dependency>
       <groupId>org.ocpsoft.prettytime</groupId>
       <artifactId>prettytime-integration-jsf</artifactId>
    </dependency>
  • Then you may attach PrettyTimeConverter to your JSF Date and timestamp outputs:

    example.xhtml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:f="http://java.sun.com/jsf/core"      
          xmlns:h="http://java.sun.com/jsf/html">
     
        <h:head>
            <title>PrettyTime Example</title>
        </h:head>
        <h:body>
            <h3>Let's format some timestamps!</h3>
            <h:outputText value="#{timeBean.time}" converter="prettyTimeConverter"/>
        </h:body>
    </html>

    Or you can also use the converter tag for additional control.

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

(Get involved! Fork us on GitHub and integrate with other frameworks! Feel free to send pull requests with enhancements and bug-fixes.)

PrettyTime :: NLP – Date and Time Parser

Introducing the simplest and smallest standalone natural language date and time parser. Comprehend phrases like, “let’s go to dinner at 7”, and “every four days, I go to the store.” » Learn more.

i18n and multiple-languages support

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

Locales with built-in support:

  • Arabic – AR: Muhammad Sabry Ali
  • Azerbaijani – AZ: Nizami20052022
  • Bengali – BN: David Serrano
  • Bulgarian – BG: B0pol
  • Burmese (Myanmar) – MM: Aung Kyaw Paing
  • Catalan – ca_ES: Mathieu
  • Chinese – ZH_CN: 陈正华
  • Chinese (Taiwan) – ZH_TW: edwardinubuntu
  • Croatian – Miroslav Rešetar
  • Czech – Martin Kouba
  • Dutch – NL: Bram Van Dam
  • English – DEFAULT
  • Estonian – Matti Jagula and Antti Markus
  • Esparanto – EO: David Serrano
  • French – FR: Eric Palpacuer
  • Galacian – GL: Jose Maria Rico
  • German – DE: Thomas Weitzel
  • Greek – EL: Anonymous
  • Hindi – HI: Sumit Bisht
  • Hungarian – Balázs Németh
  • Indonesian – in_ID xsalefter
  • Italian – IT: Mirco Attocchi and Massimo Mangoni
  • Japanese – JA: Shane Witbeck
  • Kazakh – KK: Azimkhan
  • Khmer – KM: Anonymous
  • Korean – KO: Seungbeom
  • Latin Serbian – sr_Latn: Michael LAGUERRE
  • Malay – Musasshi90
  • Norwegian – Magnus Byrkjeflot – www.mylog.no
  • Polish – Upender Gilakathula (and tswistak)
  • Portugese – PT: Gustavo Ehrhardt
  • Punjabi – PA: ShareASmile
  • Romanian – Upender Gilakathula
  • Russian – Tumin Alexander
  • Spanish – ES: Bruno Resano
  • Somali – SO: nadiration
  • Slovenian- SL: Uros Majeric
  • Turkish – Halil
  • Turkmen – Alashow
  • Ukrainian – UA
  • Urdu – Ali Akram
  • Vientamese – Xuân Tính – Blog
Basic_i18n.java
import java.util.Date;
import java.util.Locale;

import org.ocpsoft.prettytime.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

Please read the translation guide. Additionally, you can find full examples of resource bundles packaged inside pretty-time.jar. If you create a new Locale resource bundle for PrettyTime, please fork the project, and submit a pull request with the bundle and a test case.
org/ocpsoft/prettytime/i18n/Resources_de.java
package org.ocpsoft.prettytime.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 TimeFormat to accompany it.

Month.java
import org.ocpsoft.prettytime.TimeUnit;

public class Month implements TimeUnit
{
   public long getMillisPerUnit()
   {
      return 2629743830L;
   }

   public long getMaxQuantity()
   {
      private long maxQuantity = 0;
   }
}

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

TimeFormat.java
import org.ocpsoft.prettytime.TimeFormat;

public interface MonthTimeFormat
{
   public String format(final Duration duration)
   {
      if(duration.getQuantity() > 1)
         return duration.getQuantity() + "months";
      if(duration.getQuantity() == 1)
         return duration.getQuantity() + "month";
   }

   public String formatUnrounded(Duration duration)
   {
      return format(duration);
   }

   public String decorate(Duration duration, String time)
   {
      if(duration.isInPast())
         return time + " ago";
      else
         return time + " from now";
   }

   public String decorateUnrounded(Duration duration, String time)
   {
      return decorate(duration, time);
   }
}

See BasicTimeFormat for an implementation example using regular expressions


Examples using JUnit:

See below for creating custom time units and formats:

PrettyTimeTest.javaView complete file
package org.ocpsoft.prettytime;

import static org.junit.Assert.*;

import java.text.SimpleDateFormat;
import java.util.*;
import org.junit.*;
import org.ocpsoft.prettytime.*;

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);
   }

}