Using Joda Date & Time API to parse multiple formats - java

I'm parsing third party log files containing date/time using Joda. The date/time is in one of two different formats, depending on the age of the log files I'm parsing.
Currently I have code like this:
try {
return DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss").parseDateTime(datePart);
} catch (IllegalArgumentException e) {
return DateTimeFormat.forPattern("E, MMM dd, yyyy HH:mm").parseDateTime(datePart);
}
This works but contravenes Joshua Bloch's advice from Effective Java 2nd Edition (Item 57: Use exceptions only for exceptional conditions). It also makes it hard to determine if an IllegalArgumentException occurs due to a screwed up date/time in a log file.
Can you suggest a nicer approach that doesn't misuse exceptions?

You can create multiple parsers and add them to the builder by using DateTimeFormatterBuilder.append method:
DateTimeParser[] parsers = {
DateTimeFormat.forPattern( "yyyy-MM-dd HH" ).getParser(),
DateTimeFormat.forPattern( "yyyy-MM-dd" ).getParser() };
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter();
DateTime date1 = formatter.parseDateTime( "2010-01-01" );
DateTime date2 = formatter.parseDateTime( "2010-01-01 01" );

Joda-Time supports this by allowing multiple parsers to be specified - DateTimeFormatterBuilder#append
Simply create your two formatters using a builder and call toParser() on each. Then use the builder to combine them using append.

Unfortunately I don't believe Joda Time has any such capabilities. It would be nice to have a "tryParseDateTime" method, but it doesn't exist.
I suggest you isolate this behaviour into your own class (one which takes a list of patterns, and will try each in turn) so that the ugliness is only in one place. If this is causing performance issues, you might want to try to use some heuristics to guess which format to try first. For example, in your case if the string starts with a digit then it's probably the first pattern.
Note that DateTimeFormatters in Joda Time are conventionally immutable - you shouldn't be creating a new one each time you want to parse a line. Create them once and reuse them.

Related

Generic date and time parsing in java 8

I was recently trying to make a generic date and time parsing method with the java 8 time API, mainly for interfacing with older code using Date.
I wanted to do something like that:
public static Date parse(String dateStr, String pattern) {
return Date.from(Instant.parse(dateStr, DateTimeFormatter.ofPattern(pattern)));
}
The problem is that with the time API, the class to use depends on the pattern DateTimeFormatter.parse will never fail but will return a TemporalAccessor which is horrible to work with and convert to a usable class.
And LocalDateTime.parse will fail if the pattern has no time information like "dd/MM/yyyy". Other classes like Instant, ZonedDateTime, etc. will all fail to parse if the pattern doesn't match the expected class.
Ideally, I'd like a way to parse leniently and return an Instant, with default values for missing fields, but I can't find a way to do that.
Any idea?
You can use DateTimeFormatterBuilder::parseDefaulting to set default values.
var now = ZonedDateTime.now();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.OFFSET_SECONDS, now.getOffset().getTotalSeconds())
.parseDefaulting(ChronoField.YEAR, now.getYear())
.parseDefaulting(ChronoField.MONTH_OF_YEAR, now.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, now.getDayOfMonth())
.parseDefaulting(ChronoField.HOUR_OF_DAY, now.getHour())
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, now.getMinute())
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, now.getSecond())
.toFormatter(Locale.ROOT);
Instant dt = Instant.from(formatter.parse(str));
Note that it's important to first append the pattern using appendPattern, and then set all your defaults using parseDefaulting.
Also note that I used the current time stamp to fill the defaults. So, for example, if you left out the year, it takes the current year (2022 at the time of writing). Of course, the defaults depend on your exact use case.
Examples:
At the time of writing, it's 2022-06-09T17:18:36+02:00.
System.out.println(parse("9-6", "d-M"));
System.out.println(parse("2023", "uuuu"));
System.out.println(parse("10:13", "H:m"));
System.out.println(parse("25 Dec, 16:22", "d MMM, H:mm"));
resolves to
2022-06-09T15:18:36Z
2023-06-09T15:18:36Z
2022-06-09T08:13:36Z
2022-12-25T14:22:36Z

Problems when moving from SimpleDateFormat to DateTimeFormatter

I have been successfully using SimpleDateFormat for the last couple of years. I built a bunch of time utility classes using it.
As I ran into problems with SimpleDateFormat (SDF) not being thread safe, I spent the last couple of days refactoring these utility classes to internally use DateTimeFormatter (DTF) now. Since both classes' time patterns are almost identical, this transition seemed a good idea at the time.
I now have problems obtaining EpochMillis (milliseconds since 1970-01-01T00:00:00Z): While SDF would e.g. interpret 10:30 parsed using HH:mm as 1970-01-01T10:30:00Z, DTF does not do the same. DTF can use 10:30 to parse a LocalTime, but not a ZonedDateTime which is needed to obtain EpochMillis.
I understand that the objects of java.time follow a different philosophy; Date, Time, and Zoned objects are kept separately. However, in order for my utility class to interpret all strings as it did before, I need to be able to define the default parsing for all missing objects dynamically. I tried to use
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.parseDefaulting(ChronoField.YEAR, 1970);
builder.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1);
builder.parseDefaulting(ChronoField.DAY_OF_MONTH, 1);
builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0);
builder.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0);
builder.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
builder.append(DateTimeFormatter.ofPattern(pattern));
but this does not work for all patterns. It seems to only allow defaults for parameters that are not defined in pattern. Is there a way to test which ChronoFields are defined in pattern to then selectively add defaults?
Alternatively, I tried
TemporalAccessor temporal = formatter.parseBest(time,
ZonedDateTime::from,
LocalDateTime::from,
LocalDate::from,
LocalTime::from,
YearMonth::from,
Year::from,
Month::from);
if ( temporal instanceof ZonedDateTime )
return (ZonedDateTime)temporal;
if ( temporal instanceof LocalDateTime )
return ((LocalDateTime)temporal).atZone(formatter.getZone());
if ( temporal instanceof LocalDate )
return ((LocalDate)temporal).atStartOfDay().atZone(formatter.getZone());
if ( temporal instanceof LocalTime )
return ((LocalTime)temporal).atDate(LocalDate.of(1970, 1, 1)).atZone(formatter.getZone());
if ( temporal instanceof YearMonth )
return ((YearMonth)temporal).atDay(1).atStartOfDay().atZone(formatter.getZone());
if ( temporal instanceof Year )
return ((Year)temporal).atMonth(1).atDay(1).atStartOfDay().atZone(formatter.getZone());
if ( temporal instanceof Month )
return Year.of(1970).atMonth((Month)temporal).atDay(1).atStartOfDay().atZone(formatter.getZone());
which does not cover all cases either.
What is the best strategy to enable dynamic date / time / date-time / zone-date-time parsing?
Java-8-solution:
Change the order of your parsing instructions inside the builder such that the defaulting instructions all happen AFTER the pattern instruction.
For example using this static code (well, your approach will use an instance-based combination of different patterns, not performant at all):
private static final DateTimeFormatter FLEXIBLE_FORMATTER;
static {
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.appendPattern("MM/dd");
builder.parseDefaulting(ChronoField.YEAR_OF_ERA, 1970);
builder.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1);
builder.parseDefaulting(ChronoField.DAY_OF_MONTH, 1);
builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0);
builder.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0);
builder.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
FLEXIBLE_FORMATTER = builder.toFormatter();
}
Reason:
The method parseDefaulting(...) works in a funny way, namely like an embedded parser. That means, this method will inject a default value for defined field if that field has not been parsed yet. And the later pattern instruction tries to parse the same field (here: MONTH_OF_YEAR for pattern "MM/dd" and input "07/13") but with a possibly different value. If so then the composite parser will abort because it has found ambivalent values for same field and is unable to resolve the conflict (parsed value 7, but default value 1).
The official API contains following notice:
During parsing, the current state of the parse is inspected. If the
specified field has no associated value, because it has not been
parsed successfully at that point, then the specified value is
injected into the parse result. Injection is immediate, thus the
field-value pair will be visible to any subsequent elements in the
formatter. As such, this method is normally called at the end of the
builder.
We should read it as:
Dont't call parseDefaulting(...) before any parsing instruction for the same field.
Side note 1:
Your alternative approach based on parseBest(...) is even worse because
it does not cover all combinations with missing minute or only missing year (MonthDay?) etc. The default value solution is more flexible.
it is performancewise not worth to be discussed.
Side note 2:
I would rather have made the whole implementation order-insensitive because this detail is like a trap for many users. And it is possible to avoid this trap by choosing a map-based implementation for default values as done in my own time library Time4J where the order of default-value-instructions does not matter at all because injecting default values only happens after all fields have been parsed. Time4J also offers a dedicated answer to "What is the best strategy to enable dynamic date / time / date-time / zone-date-time parsing?" by offering a MultiFormatParser.
UPDATE:
In Java-8: Use ChronoField.YEAR_OF_ERA instead of ChronoField.YEAR because the pattern contains the letter "y" (=year-of-era, not the same as proleptic gregorian year). Otherwise the parse engine will inject the proleptic default year in addition to parsed year-of-era and will find a conflict. A real pitfall. Just yesterday I had fixed a similar pitfall in my time library for the month field which exists in two slightly different variations.
I have used new java.time package and it takes time getting used to it. But after a learning curve I have to say it is definitely very comprehensive and robust solution probably superseding Joda time library and other previous solutions. I wrote my own utilities for working with parsing Strings to Date. I wrote a summarizing article that explains how I implemented a feature that parsed String of unknown format to Date. It might be helpful. Here is the link to an article: Java 8 java.time package: parsing any string to date

get calendar pattern for a given locale [duplicate]

It is quite easy to format and parse Java Date (or Calendar) classes using instances of DateFormat.
I could format the current date into a short localized date like this:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String today = formatter.format(new Date());
My problem is that I need to obtain this localized pattern string (something like "MM/dd/yy").
This should be a trivial task, but I just couldn't find the provider.
For SimpleDateFormat, You call toLocalizedPattern()
EDIT:
For Java 8 users:
The Java 8 Date Time API is similar to Joda-time. To gain a localized pattern we can use class
DateTimeFormatter
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
Note that when you call toString() on LocalDate, you will get date in format ISO-8601
Note that Date Time API in Java 8 is inspired by Joda Time and most solution can be based on questions related to time.
For those still using Java 7 and older:
You can use something like this:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String pattern = ((SimpleDateFormat)formatter).toPattern();
String localPattern = ((SimpleDateFormat)formatter).toLocalizedPattern();
Since the DateFormat returned From getDateInstance() is instance of SimpleDateFormat.
Those two methods should really be in the DateFormat too for this to be less hacky, but they currently are not.
It may be strange, that I am answering my own question, but I believe, I can add something to the picture.
ICU implementation
Obviously, Java 8 gives you a lot, but there is also something else: ICU4J. This is actually the source of Java original implementation of things like Calendar, DateFormat and SimpleDateFormat, to name a few.
Therefore, it should not be a surprise that ICU's SimpleDateFormat also contains methods like toPattern() or toLocalizedPattern(). You can see them in action here:
DateFormat fmt = DateFormat.getPatternInstance(
DateFormat.YEAR_MONTH,
Locale.forLanguageTag("pl-PL"));
if (fmt instanceof SimpleDateFormat) {
SimpleDateFormat sfmt = (SimpleDateFormat) fmt;
String pattern = sfmt.toPattern();
String localizedPattern = sfmt.toLocalizedPattern();
System.out.println(pattern);
System.out.println(localizedPattern);
}
ICU enhancements
This is nothing new, but what I really wanted to point out is this:
DateFormat.getPatternInstance(String pattern, Locale locale);
This is a method that can return a whole bunch of locale specific patterns, such as:
ABBR_QUARTER
QUARTER
YEAR
YEAR_ABBR_QUARTER
YEAR_QUARTER
YEAR_ABBR_MONTH
YEAR_MONTH
YEAR_NUM_MONTH
YEAR_ABBR_MONTH_DAY
YEAR_NUM_MONTH_DAY
YEAR_MONTH_DAY
YEAR_ABBR_MONTH_WEEKDAY_DAY
YEAR_MONTH_WEEKDAY_DAY
YEAR_NUM_MONTH_WEEKDAY_DAY
ABBR_MONTH
MONTH
NUM_MONTH
ABBR_STANDALONE_MONTH
STANDALONE_MONTH
ABBR_MONTH_DAY
MONTH_DAY
NUM_MONTH_DAY
ABBR_MONTH_WEEKDAY_DAY
MONTH_WEEKDAY_DAY
NUM_MONTH_WEEKDAY_DAY
DAY
ABBR_WEEKDAY
WEEKDAY
HOUR
HOUR24
HOUR_MINUTE
HOUR_MINUTE_SECOND
HOUR24_MINUTE
HOUR24_MINUTE_SECOND
HOUR_TZ
HOUR_GENERIC_TZ
HOUR_MINUTE_TZ
HOUR_MINUTE_GENERIC_TZ
MINUTE
MINUTE_SECOND
SECOND
ABBR_UTC_TZ
ABBR_SPECIFIC_TZ
SPECIFIC_TZ
ABBR_GENERIC_TZ
GENERIC_TZ
LOCATION_TZ
Sure, there are quite a few. What is good about them, is that these patterns are actually strings (as in java.lang.String), that is if you use English pattern "MM/d", you'll get locale-specific pattern in return. It might be useful in some corner cases. Usually you would just use DateFormat instance, and won't care about the pattern itself.
Locale-specific pattern vs. localized pattern
The question intention was to get localized, and not the locale-specific pattern. What's the difference?
In theory, toPattern() will give you locale-specific pattern (depending on Locale you used to instantiate (Simple)DateFormat). That is, no matter what target language/country you put, you'll get the pattern composed of symbols like y, M, d, h, H, M, etc.
On the other hand, toLocalizedPattern() should return localized pattern, that is something that is suitable for end users to read and understand. For instance, German middle (default) date pattern would be:
toPattern(): dd.MM.yyyy
toLocalizedPattern(): tt.MM.jjjj (day = Tag, month = Monat, year = Jahr)
The intention of the question was: "how to find the localized pattern that could serve as hint as to what the date/time format is". That is, say we have a date field that user can fill-out using the locale-specific pattern, but I want to display a format hint in the localized form.
Sadly, so far there is no good solution. The ICU I mentioned earlier in this post, partially works. That's because, the data that ICU uses come from CLDR, which is unfortunately partially translated/partially correct. In case of my mother's tongue, at the time of writing, neither patterns, nor their localized forms are correctly translated. And every time I correct them, I got outvoted by other people, who do not necessary live in Poland, nor speak Polish language...
The moral of this story: do not fully rely on CLDR. You still need to have local auditors/linguistic reviewers.
You can use DateTimeFormatterBuilder in Java 8. Following example returns localized date only pattern e.g. "d.M.yyyy".
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT, null, IsoChronology.INSTANCE,
Locale.GERMANY); // or whatever Locale
The following code will give you the pattern for the locale:
final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern();
System.out.println(pattern1);
Java 8 provides some useful features out of the box for working with and formatting/parsing date and time, including handling locales. Here is a brief introduction.
Basic Patterns
In the simplest case to format/parse a date you would use the following code with a String pattern:
DateTimeFormatter.ofPattern("MM/dd/yyyy")
The standard is then to use this with the date object directly for formatting:
return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));
And then using the factory pattern to parse a date:
return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy"));
The pattern itself has a large number of options that will cover the majority of usecases, a full rundown can be found at the javadoc location here.
Locales
Inclusion of a Locale is fairly simple, for the default locale you have the following options that can then be applied to the format/parse options demonstrated above:
DateTimeFormatter.ofLocalizedDate(dateStyle);
The 'dateStyle' above is a FormatStyle option Enum to represent the full, long, medium and short versions of the localized Date when working with the DateTimeFormatter. Using FormatStyle you also have the following options:
DateTimeFormatter.ofLocalizedTime(timeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle);
The last option allows you to specify a different FormatStyle for the date and the time. If you are not working with the default Locale the return of each of the Localized methods can be adjusted using the .withLocale option e.g
DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH);
Alternatively the ofPattern has an overloaded version to specify the locale too
DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH);
I Need More!
DateTimeFormatter will meet the majority of use cases, however it is built on the DateTimeFormatterBuilder which provides a massive range of options to the user of the builder. Use DateTimeFormatter to start with and if you need these extensive formatting features fall back to the builder.
Please find in the below code which accepts the locale instance and returns the locale specific data format/pattern.
public static String getLocaleDatePattern(Locale locale) {
// Validating if Locale instance is null
if (locale == null || locale.getLanguage() == null) {
return "MM/dd/yyyy";
}
// Fetching the locale specific date pattern
String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance(
DateFormat.SHORT, locale)).toPattern();
// Validating if locale type is having language code for Chinese and country
// code for (Hong Kong) with Date Format as - yy'?'M'?'d'?'
if (locale.toString().equalsIgnoreCase("zh_hk")) {
// Expected application Date Format for Chinese (Hong Kong) locale type
return "yyyy'MM'dd";
}
// Replacing all d|m|y OR Gy with dd|MM|yyyy as per the locale date pattern
localeDatePattern = localeDatePattern.replaceAll("d{1,2}", "dd").replaceAll(
"M{1,2}", "MM").replaceAll("y{1,4}|Gy", "yyyy");
// Replacing all blank spaces in the locale date pattern
localeDatePattern = localeDatePattern.replace(" ", "");
// Validating the date pattern length to remove any extract characters
if (localeDatePattern.length() > 10) {
// Keeping the standard length as expected by the application
localeDatePattern = localeDatePattern.substring(0, 10);
}
return localeDatePattern;
}
Since it's just the locale information you're after, I think what you'll have to do is locate the file which the JVM (OpenJDK or Harmony) actually uses as input to the whole Locale thing and figure out how to parse it. Or just use another source on the web (surely there's a list somewhere). That'll save those poor translators.
You can try something like :
LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy"))
Im not sure about what you want, but...
SimpleDateFormat example:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");
Date date = sdf.parse("12/31/10");
String str = sdf.format(new Date());

Human readable and parsable date format in Java

I want to save a Date object to a readable string (for example 22/10/2009 21:13:14) that is also parsable back to a Date object.
I have tried many things and the best I could find was to use DateFormater for parsing and formating but it has a setback. When you format a date you lose seconds information. I tried to find if there is an option to format it and display the seconds (even better would be to the millisecond level since that's the resolution the Date object allows you to have) but I came up short.
Any ideas?
Take a look at java.text.SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS");
Date dt = new Date();
String S = sdf.format(dt); // formats to 09/23/2009 13:53:28.238
Date dt2 = sdf.parse(S); // parses back
SimpleDateFormat can format and parse a date based on a very simple pattern system that include second and even milliseconds.
Other answers are all good.
But when doing this kind of thing please pick a format that sorts properly when coded as a string.... "yyyy/MM/dd HH:mm:ss" is fine. It always astounds me when software engineers pick a date format which doesn't sort in the obvious, convenient way.
You'll save your fellow developers a lot of pain at some distant point in the future - think of it as good karma :-)
ISO 8601
Use ISO 8601 format.
It’s flexible, it includes seconds and fraction of second if there are any, but you may also leave them out if they are 0.
It’s standard, so more and more tools format and parse it. Great for serialization for storage or data interchange.
It goes like 2009-10-22T21:13:14, I should say it’s pretty human-readable (though the T in the middle that denotes the start of the time part may feel unusual at first).
The strings sort properly, as mikera requested in another answer, as long as the years are in the four-digit range from 1000 through 9999.
The classes of java.time, the modern Java date and time API, as well as those of Joda Time parse ISO 8601 as their default, that is, without any explicit formatter, and produce the same format from their toString methods.
A modest demonstration of using java.time:
LocalDateTime dateTime = LocalDateTime.of(2009, 10, 22, 21, 13, 14);
String readableString = dateTime.toString();
System.out.println(readableString);
LocalDateTime parsedBack = LocalDateTime.parse(readableString);
System.out.println(parsedBack);
This prints two identical lines:
2009-10-22T21:13:14
2009-10-22T21:13:14
The latter System.out.println() call implicitly calls toString() once more, so this shouldn’t surprise.
A little off-topic, but I always feel the need to remind people that DateFormat and SimpleDateFormat are not thread safe! The Sun documentation clearly states this, but I keep finding code out in the wild where people stick a SimpleDateFormat in a static ...
If you want to do it a little simpler, and be spared from making your own DateFormat that most other Answers involve, you can leverage the default format in java.time.Instant:
(new Date()).toInstant.toString();

How to convert a date String into the right format in Java?

Can somebody please explain to me how I can convert
2009-10-27 14:36:59.580250
into
27.10.2009, 14:36 ?
The first date is available as a string and the second one should be a string as well ;) Up to now I'm not so into date conversion within Java...
Thanks in advance!
You can use java.text.SimpleDateFormat for this. First step is to parse the first string into a java.util.Date object using SimpleDateFormat based on the pattern of the first string. Next step is to format the obtained java.util.Date object into a string based on the pattern of the second string. For example:
String datestring1 = "2009-10-27 14:36:59.580250";
Date date1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(datestring1);
String datestring2 = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(date1);
System.out.println(datestring2);
Edit: I've removed the .SSSSSS part from the first pattern because it failed. But in my opinion it should in theory have worked with "yyyy-MM-dd HH:mm:ss.SSS" and "yyyy-MM-dd HH:mm:ss.SSSSSS" as well, but it is calculating them as seconds! I consider this as a buggy implementation in SimpleDateFormat. The JodaTime handles the millis/micros perfectly with those patterns.
You can use SimpleDateFormat. Although there's no format specification for micro-seconds (the last fragment of your input), you can make use of the fact that the parser ignores the rest of the string if it has already managed to match the configured pattern:
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm");
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy HH:mm");
System.out.println(formatter.format(parser.parse("2009-10-27 14:36:59.580250")));
The parser will in this case simply ignore the last part ":59.580250" of the input string.
Check out SimpleDateFormat. You can use this to both parse and format. I would suggest parsing the above into a Date object using one SimpleDateFormat, and then formatting to a String using a 2nd SimpleDateFormat.
Note that SimpleDateFormat suffers from threading issues, and so if you're using this in a threaded environment, either create new SimpleDateFormats rather than used static versions, or use the corresponding but thread-safe classes in Joda.
Keep in mind when you do this that you are losing precision. Depending on your specific application, this may or may not matter.
If you already have the original date saved somewhere, this is not an issue. However, if the source date is from a transient source (e.g., streaming in from a physical sensor of some sort), it may be a good idea to persist the interim Date object (output of SimpleDateFormat#parse(String)) somewhere.
Just thought I'd point that out.

Categories