1

I would like to format three numbers representing year, month and day using the Java date format specifiers. I know I can create a Date object and use the built in formatting functions, but I would like to know if there is any way to avoid creating the intermediate date object. Given the volumes of data that I am expecting, the garbage collection overhead is something that I always have to keep in mind.

Essentially I am looking for library function suggestions or similar.

Edit: The idea is that the user can specify the format parameter. If they don't I am falling back to a standard format like that suggested in the comment. So I will get a string like "YYYY-DD-MM" and have to use that as appropriate.

Greg Reynolds
  • 9,736
  • 13
  • 49
  • 60
  • 5
    Please append an example of input and desired output. – Smutje Jan 15 '15 at 14:45
  • 2
    If you already have the year, month and day integers, why don't you just do: String date = String.format("%d/%d/%d", month, day, year); (US style) – Fallso Jan 15 '15 at 14:49
  • Look into joda time maybe or if using Java8 there's a new api, see http://stackoverflow.com/questions/24631909/differences-between-java-8-date-time-api-java-time-and-joda-time – unigeek Jan 15 '15 at 14:51
  • That string format suggestion is my "fallback" in case no format string is specified. – Greg Reynolds Jan 15 '15 at 15:03

3 Answers3

2

If you're concerned about garbage collecting and objects creation, why not keep a single Calendar instance in your class or system, and use it for all formatting purposes using a static / synchronized method?

Ofer Lando
  • 814
  • 7
  • 12
  • 1
    That's what I did in the end. A thread local SimpleDateFormatter that can have new patterns applied to it, and a thread local Calendar. I imagine that still creates some objects under the hood, but I put some special casing in for what I think will be the most common formats to short-circuit it. – Greg Reynolds Jan 15 '15 at 17:08
  • FYI, the `SimpleDateFormat` class was supplanted by the modern and thread-safe [`DateTimeFormatter`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) class as of [JSR 310](https://jcp.org/en/jsr/detail?id=310). – Basil Bourque May 14 '19 at 00:45
0

In that case, see:

http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#dt

That will allow you to parse dates with a custom format. I think this is probably what SimpleDateFormatt uses under the bonnet. In reference to your concerns about garbage collection, have you actually tried it? The following demo code executes in one second on my machine (logging and console output omitted as this will unfairly slow it down):

long startTime = System.currentTimeMillis();
Calendar c = Calendar.getInstance();
DateFormat formatter = SimpleDateFormat.getDateInstance(DateFormat.SHORT);
Random rand = new Random();
for (int i = 0; i < 1000000; ++i)
{
  c.set(Calendar.HOUR_OF_DAY, rand.nextInt(24) + 1);
  c.set(Calendar.DAY_OF_MONTH, rand.nextInt(28) + 1);
  c.set(Calendar.MONTH, rand.nextInt(12) + 1);
  c.set(Calendar.YEAR, rand.nextInt(2015) + 1);
  formatter.format(c.getTime());
}

long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Time taken: " + TimeUnit.MILLISECONDS.toSeconds(totalTime));
Fallso
  • 1,311
  • 1
  • 9
  • 18
  • 1
    This kind of benchmark is generally a little uninformative, it's possible that it's not doing anything as the result of the format isn't used anywhere. In answer to your question, it's not particularly about this particular case, but something that we have to keep in mind for all new code as garbage collection pauses really kill us. So anything that is creating a bunch of objects when it might not need to is to be avoided. The issue is really with stop-the-world garbage collections rather than individual loops running slow, if that makes sense. – Greg Reynolds Jan 15 '15 at 17:11
  • Ah OK, I think I see what you mean there. Unfortunately, unless you decide to use a set of static objects (as Ofer Lando suggested) I think you probably are stuck in regards to the garbage collection pauses if this is a big issue. Perhaps this is a wider indicator that you shouldn't be using Java for this if performance is that critical? Seems as if something you could trivialise with a bit of nifty C++. – Fallso Jan 16 '15 at 08:46
0

tl;dr

In extreme data loads where you want to minimize object creation, keep your DateTimeFormatter object(s) around for re-use. That class is inherently thread-safe, so you may re-use across threads.

java.time

Some years ago, the troublesome date-time classes such as Date and Calendar and SimpleDateFormat were supplanted entirely by the modern java.time classes defined in JSR 310.

One of the many benefits to the java.time classes: They are thread-safe by design, using immutable objects. So you can keep them around for re-use.

LocalDate

For a date-only value, without time-of-day and without time zone, use the LocalDate class.

LocalDate ld = LocalDate.of( 2019 , 1 , 23 ) ;

To generate text in standard ISO 8601 format of YYYY-DD-MM, simply call toString.

String output = ld.toString() ;  // ISO 8601 format.

DateTimeFormatter

For other formats, use the DateTimeFormatter class.

Again, you can safely keep objects of this class around for re-use across threads. Loop through multiple DateTimeFormatter objects, trying each in succession, trapping for DateTimeParseException until one succeeds.

If concerned about efficiency and minimizing object creation because of extreme data loads, be clever about identifying which formatter(s) may be appropriate to a particular input. For example, the length of the string may tell you which formatter to use.

Also, be aware that with the DateTimeFormatterBuilder class, you can specify optional parts. This effectively lets a single formatter parse multiple kinds of inputs.

Let the JVM work for you

Lastly, a caution: Worrying about creating too many objects is almost certainly unwarranted.

The modern JVMs are extremely well-tuned and effective. They commonly have special handling for short-lived objects for efficient disposal. Do not fall into the trap of premature-optimization: Use profiling to prove you have a measurable performance problem before writing squirrelly code.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • If you talk about lightweight objects then yes we don't worry about object creation (costs similar to a method call). But recommending the creation of multiple `DateTimeFormatter` objects is a bad advice because such objects are extremely heavy weight and expensive in construction. Better assign such objects to static constants (possible based on immutability). However, another disadvantage of your suggested solution is unavoidable in bulky parsing, namely to rely on exception handling when testing different parsers (remember: creating internal exceptions on the fly is also expensive). – Meno Hochschild May 14 '19 at 09:19
  • @MenoHochschild Actually, my specific recommendation *is* to keep collection of `DateTimeFormatter` objects around for re-use rather than recreating. As for the advice about not worrying about object creation, both I was referring to the OP’s specific wariness of creating `Date` objects, not formatters. Lastly, regarding bulky parsing by relying on exception handling, of course it makes sense to identify the appropriate formatter by means such as checking the length of the string. I thought that goes without saying, but perhaps not. I will say so in an edit. – Basil Bourque May 14 '19 at 23:11