I need to convert java.util.Date
to String
in yyyy-MM-dd
format in a big amounts.
I have just moved to java 8 and want to know how to do it properly.
My solution with Java 7 was like:
DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern(DATE_FORMAT_PATTERN)
DATE_FORMATTER.print(value.getTime())
It helped me not to create a lots of redundant objects.
So now when I moved to java 8 I want rewrite it properly but:
LocalDate.fromDateFields(value).toString())
creates each time new LocalDate
object and this gives a lot of work to GC.
Are there any ways to solve my problem?
Performance and thread-safety are very important.
After some testing I have found that even with creating new objects construction with:
new SimpleDateFormat("yyyy-MM-dd")).format(value))
the fastest all over this topic.
The following only has an overhead for the conversion of the old Date to the new LocalDate.
Date date = new Date();
LocalDate ldate = LocalDate.from(date.toInstant().atZone(ZoneOffset.UTC));
String s = DateTimeFormatter.ISO_DATE.format(ldate); // uuuu-MM-dd
It is true however that DateTimeFormatters are thread-safe and hence will have one instantiation more per call.
P.S.
I added .atZone(ZoneOffset.UTC)
because of a reported exception, and @Flown's solution: specifying the zone. As Date
is not necessarily used for UTC dates, one might use another one.
Use SimpleDateFormat to format Date.
watch out, SDF is NOT THREAD-SAFE, it might not be important but keep that in mind.
For Example:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println((sdf.format(new Date())).toString());
LINK with more information.
I don't have exact numbers from point of view of the performance but I would use the Java 8 Time API to solve this issue. In your special case I would use the following statement:
LocalDate.now().format(DateTimeFormatter.ISO_DATE);
EDIT:
For this solution is a conversion from java.util.Date
to java.time.LocalDate
required!
new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Without creating lots of objects, meaning you want the performance version?
public static String getIsoDate(java.util.Date time) {
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.setTime(time);
StringBuilder sb = new StringBuilder();
int year = cal.get(java.util.Calendar.YEAR);
int month = cal.get(java.util.Calendar.MONTH) + 1;
int day = cal.get(java.util.Calendar.DAY_OF_MONTH);
sb.append(year);
sb.append('-');
if (month < 10) {
sb.append('0');
}
sb.append(month);
sb.append('-');
if (day < 10) {
sb.append('0');
}
sb.append(day);
return sb.toString();
}
This version is thread-safe and avoids most hidden object creations, and unless you have years under 1000 or over 9999, it will print just fine.
you can use @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") annotation on your field.