Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

The (real life) problem

Following my question on SO, I found out that printing a Java Date() in a custom format is quite tedious:

final Date date = new Date();
final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
final SimpleDateFormat sdf = new SimpleDateFormat(ISO_FORMAT);
final TimeZone utc = TimeZone.getTimeZone("UTC");
sdf.setTimeZone(utc);
System.out.println(sdf.format(date));

I was looking for a one-liner without object initialization:

System.out.println(magic(date, "yyyy-MM-dd'T'HH:mm:ss.SSS zzz", "UTC"));

My Solution

PrettyDate class, which formats Date() objects using TimeZones and Formats given as strings, sans any external object creation. There are some convenience methods for popular timezone\format combinations.

Alternatives to Consider (please comment on these, too!)

  • Extending Date() with better toString()
  • Using non-static methods: Initializing PrettyDate with a Format and a TimeZone, and feeding it with Date objects to get a string representation

Usage

// The problem - not UTC
Date.toString()                      
"Tue Jul 03 14:54:24 IDT 2012"

// ISO format, now
PrettyDate.now()        
"2012-07-03T11:54:24.256 UTC"

// ISO format, specific date
PrettyDate.toString(new Date())         
"2012-07-03T11:54:24.256 UTC"

// Legacy format, specific date
PrettyDate.toLegacyString(new Date())   
"Tue Jul 03 11:54:24 UTC 2012"

// ISO, specific date and time zone
PrettyDate.toString(moonLandingDate, "yyyy-MM-dd hh:mm:ss zzz", "CST") 
"1969-08-20 03:17:40 CDT"

// Specific format and date
PrettyDate.toString(moonLandingDate, "yyyy-MM-dd")
"1969-08-20"

// ISO, specific date
PrettyDate.toString(moonLandingDate)
"1969-08-20T20:17:40.234 UTC"

// Legacy, specific date
PrettyDate.toLegacyString(moonLandingDate)
"Wed Aug 20 08:17:40 UTC 1969"

Code

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Formats dates to sortable UTC strings in compliance with ISO-8601.
 * 
 * @author Adam Matan <adam@matan.name>
 * @see http://stackoverflow.com/questions/11294307/convert-java-date-to-utc-string/11294308
 */
public class PrettyDate {
    public static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
    public static String LEGACY_FORMAT = "EEE MMM dd hh:mm:ss zzz yyyy";
    private static final TimeZone utc = TimeZone.getTimeZone("UTC");
    private static final SimpleDateFormat legacyFormatter = new SimpleDateFormat(LEGACY_FORMAT);
    private static final SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
    static {
        legacyFormatter.setTimeZone(utc);
        isoFormatter.setTimeZone(utc);
    }

    /**
     * Formats the current time in a sortable ISO-8601 UTC format.
     * 
     * @return Current time in ISO-8601 format, e.g. :
     *         "2012-07-03T07:59:09.206 UTC"
     */
    public static String now() {
        return PrettyDate.toString(new Date());
    }

    /**
     * Formats a given date in a sortable ISO-8601 UTC format.
     * 
     * <pre>
     * <code>
     * final Calendar moonLandingCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
     * moonLandingCalendar.set(1969, 7, 20, 20, 18, 0);
     * final Date moonLandingDate = moonLandingCalendar.getTime();
     * System.out.println("UTCDate.toString moon:       " + PrettyDate.toString(moonLandingDate));
     * >>> UTCDate.toString moon:       1969-08-20T20:18:00.209 UTC
     * </code>
     * </pre>
     * 
     * @param date
     *            Valid Date object.
     * @return The given date in ISO-8601 format.
     * 
     */

    public static String toString(final Date date) {
        return isoFormatter.format(date);
    }

    /**
     * Formats a given date in the standard Java Date.toString(), using UTC
     * instead of locale time zone.
     * 
     * <pre>
     * <code>
     * System.out.println(UTCDate.toLegacyString(new Date()));
     * >>> "Tue Jul 03 07:33:57 UTC 2012"
     * </code>
     * </pre>
     * 
     * @param date
     *            Valid Date object.
     * @return The given date in Legacy Date.toString() format, e.g.
     *         "Tue Jul 03 09:34:17 IDT 2012"
     */
    public static String toLegacyString(final Date date) {
        return legacyFormatter.format(date);
    }

    /**
     * Formats a date in any given format at UTC.
     * 
     * <pre>
     * <code>
     * final Calendar moonLandingCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
     * moonLandingCalendar.set(1969, 7, 20, 20, 17, 40);
     * final Date moonLandingDate = moonLandingCalendar.getTime();
     * PrettyDate.toString(moonLandingDate, "yyyy-MM-dd")
     * >>> "1969-08-20"
     * </code>
     * </pre>
     * 
     * 
     * @param date
     *            Valid Date object.
     * @param format
     *            String representation of the format, e.g. "yyyy-MM-dd"
     * @return The given date formatted in the given format.
     */
    public static String toString(final Date date, final String format) {
        return toString(date, format, "UTC");
    }

    /**
     * Formats a date at any given format String, at any given Timezone String.
     * 
     * 
     * @param date
     *            Valid Date object
     * @param format
     *            String representation of the format, e.g. "yyyy-MM-dd HH:mm"
     * @param timezone
     *            String representation of the time zone, e.g. "CST"
     * @return The formatted date in the given time zone.
     */
    public static String toString(final Date date, final String format, final String timezone) {
        final TimeZone tz = TimeZone.getTimeZone(timezone);
        final SimpleDateFormat formatter = new SimpleDateFormat(format);
        formatter.setTimeZone(tz);
        return formatter.format(date);
    }
}
share|improve this question
1  
What about FastDateFormat in Commons Lang? And DateFormatUtils with a set of static methods for formatting dates using FastDateFormat –  Alexey Grigorev Jul 5 '12 at 18:31
    
I will take a look - seems like I've been trying to reinvent the wheel. –  Adam Matan Jul 6 '12 at 16:40
    
FastDateFormat uses the default Java Date String format as a default, but thanks again for the idea. –  Adam Matan Jul 11 '12 at 6:08

2 Answers 2

up vote 5 down vote accepted

The thing about Date is that there are so many different time zones, so many different "standard" ways of representing the date and even, in some places, completely different calendar systems. As a result, Sun designed Date to not make any assumptions about anything and let application developers write whatever implementation best suited them.

So, if you find your implementation for PrettyDate works well for you, that's ok. My only comment about that is that heavy use of static methods smells of procedural, rather than object oriented thinking, and that's not a good thing. Embrace the objects.

share|improve this answer
    
+1 Thanks for your answer, Perhaps I will refactor my code to comply with OOP design, although it is procedural in nature. Do you have any feedback regarding code style and readability? –  Adam Matan Jul 4 '12 at 5:35
    
I thought the style and readability were fine - otherwise I would have said something. You might try trimming the comments a little - not to remove any of the information, but just to try and shrink them a little. They make it hard to see the actual code. –  Donald.McLean Jul 4 '12 at 8:02
    
Thanks for the feedback! –  Adam Matan Jul 4 '12 at 8:07

Also be aware that SimpleDateFormat is not thread-safe. In a Multithreading Environment users should create a separate instance for each thread. For more information how to achieve it check this link

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.