-1

Probably I am trying to achieve something which is not available out of the box from SimpleDateFormat and a limitation as to where the year/month/date are defaulted to 1970/Jan/01, if yy/mm/dd are not defined in the pattern.

Example:

String pattern = "hh:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
Date date = simpleDateFormat.parse("08:05:05");
System.out.println(date);

The result is: Thu Jan 01 08:05:05 IST 1970

I have a scenario where I could receive any custom pattern to my API and should be able to parse to current date/month/day if corresponding format symbols are missing in the pattern (missing y or m or d)

Desired result for the above example (today is 4 June 2018): Mon Jun 04 08:05:05 IST 2018

Could anyone help me as to how could I achieve the behavior?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Vamsi
  • 9
  • 4
  • 2
    I recommend you avoid the `SimpleDateFormat` class. It is not only long outdated, it is also notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). And with it there are more than one straightforward solution to your problem. – Ole V.V. Jun 04 '18 at 08:32
  • 1
    @T.J.Crowder Thanks for the formatting help. I will remember next time. – Vamsi Jun 04 '18 at 08:35
  • @OleV.V. We have a legacy code which we have to support from Java1.6+, Really can't switch to the latest one. – Vamsi Jun 04 '18 at 08:36
  • 1
    For Java 1.6+ I recommend using `java.time` through [the ThreeTen Backport](http://www.threeten.org/threetenbp/), the backport to Java 6 and 7. The `DateTimeUtils` class of the backport contains conversion methods that allow you to interoperate with your legacy code, for example pass an old-fashioned `Date` object to it. So yes, you both can switch for new code and can benefit from doing so. – Ole V.V. Jun 04 '18 at 08:46
  • What does `3/3/3` mean? There is an inherent danger in trying to solve this problem, there are to many edge cases to deal with – MadProgrammer Jun 04 '18 at 08:46
  • Looks like I have to resort to a mutation post parse() https://pastebin.com/uhagLVrB – Vamsi Jun 04 '18 at 09:50

1 Answers1

1

java.time

public static void parseCustomFormat(String formatPattern, String dateTimeString) {
    LocalDate today = LocalDate.now(ZoneId.of("Asia/Kolkata"));
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern(formatPattern)
            .parseDefaulting(ChronoField.YEAR_OF_ERA, today.getYear())
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, today.getMonthValue())
            .parseDefaulting(ChronoField.DAY_OF_MONTH, today.getDayOfMonth())
            .toFormatter(Locale.ENGLISH);
    LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, formatter);
    System.out.format(Locale.ENGLISH, "%-19s -> %s%n",  dateTimeString, parsedDateTime);
}

The above method will basically use day, month and/or year from the string if the pattern says it should, and use the corresponding values form today’s date if not. For example:

    parseCustomFormat("HH:mm:ss", "08:05:05");
    parseCustomFormat("yyyy-MM-dd'T'HH:mm:ss", "2015-11-23T21:41:45");
    parseCustomFormat("MM H:mm", "10 20:58");
    parseCustomFormat("yy d H:mm", "34 29 9:30");

When I ran this code today, the output was:

08:05:05            -> 2018-06-04T08:05:05
2015-11-23T21:41:45 -> 2015-11-23T21:41:45
10 20:58            -> 2018-10-04T20:58
34 29 9:30          -> 2034-06-29T09:30

Parsing will be apt to fail if the pattern contains a week year and/or week number, u for year or a day of week. It will be sure to fail if it contains hour within AM or PM (lowercase h as in the example in the question) and no AM/PM marker.

We have a legacy code which we have to support from Java1.6+

No big problem. I have run the above code on Java 7 with ThreeTen backport, the backport of java.time to Java 6 and 7 (see the link at the bottom), so it should work on Java 6 too. If you need a java.util.Date for your legacy code (and don’t want to upgrade it to java.time just now), convert like this:

    Instant inst = parsedDateTime.atZone(ZoneId.systemDefault()).toInstant();
    Date oldfashionedDate = DateTimeUtils.toDate(inst);
    System.out.format(Locale.ENGLISH, "%-19s -> %s%n",  dateTimeString, oldfashionedDate);

With this change to the above code the output on my computer was:

08:05:05            -> Mon Jun 04 08:05:05 CEST 2018
2015-11-23T21:41:45 -> Mon Nov 23 21:41:45 CET 2015
10 20:58            -> Thu Oct 04 20:58:00 CEST 2018
34 29 9:30          -> Thu Jun 29 09:30:00 CEST 2034

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thank a lot @ole v.v There seems to no direct way as you mentioned and we need to do some like you suggested. Actually, I am trying to solve a JSpinner (DateSpinner) problem as described in [JDK-5067114](https://bugs.openjdk.java.net/browse/JDK-5067114). My idea was to provide a custom dateFormatter which could do above conversions. – Vamsi Jun 04 '18 at 13:51
  • From my analysis, I observed that the text field on the DateSpinner UI is backed by a DateFormatter so whenever we rotate the spinner, the new text would be parsed to Date() by the underlying formatter and stored in the model. I though If I could have change the behavior of the formatter It would solve the issue. – Vamsi Jun 04 '18 at 13:55