2

The user will input dates in different patterns to my application. For 2-digit years, he must also determine the pivot date.


Example:
pattern = yy-MM-dd
pivot date = 70 (I add the current millennium and the last century for more dynamics programmatically => 1970)

69-04-22 becomes 2069-04-22
70-04-22 becomes 1970-04-22


Like described in this answer it's easy to build a DateTimeFormatter when the date pattern (here ddMMyy) is known.
But since the user inputs the pattern, I'm not sure how to build the DateTimeFormatterBuilder properly. I can't hard code it.

Do I have to parse the pattern by myself and call appendPattern() and appendValueReduced() in the right order? Or is there a built-in solution?

Community
  • 1
  • 1
halloei
  • 1,892
  • 1
  • 25
  • 45
  • Not sure where your problem is. Suppose you didn't have the base date issue, and the user just entered the pattern. Do you know what you would have done then? Or is your problem that you don't trust the user to enter a proper pattern? If his pattern is valid, what's the problem with adding the `appendValueReduced` to it? – RealSkeptic Sep 25 '15 at 13:01
  • Let's suppose the pattern entered is valid. The problem is that `java.time` takes the current century (2000) when converting a 2-digit year into 4 digits. But I want to let the user decide at what year the last century (1900) or the current century (2000) is chosen. – halloei Sep 25 '15 at 13:06
  • Yes, but I didn't understand what the problem is with the given answer. What's wrong with `new DateTimeFormatterBuilder().appendPattern(userPattern).appendValueReduced(...)`? – RealSkeptic Sep 25 '15 at 13:08
  • It won't work, because for my pattern it must be `new DateTimeFormatterBuilder().appendValueReduced(...).appendPattern(userPattern)`. So they must be called in another order and the `userPattern` has to be edited to be *-MM-dd*. – halloei Sep 25 '15 at 13:13

1 Answers1

2

Here the Java-8-solution (it rather looks like a hack):

String pattern = "MM/dd/yy 'US'"; // user-input
String text = "10/04/69 US"; // user-input
Locale locale = Locale.US; // user-input, too?

int yy = pattern.indexOf("yy");
DateTimeFormatter dtf;

if (
    (yy != -1) // explanation: condition ensures exactly two letters y
    && ((yy + 2 >= pattern.length()) || pattern.charAt(yy + 2) != 'y')
) {
    DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
    String part1 = pattern.substring(0, yy);
    if (!part1.isEmpty()) {
        builder.appendPattern(part1);
    }
    builder.appendValueReduced(ChronoField.YEAR, 2, 2, 1970);
    String part2 = pattern.substring(yy + 2);
    if (!part2.isEmpty()) {
        builder.appendPattern(part2);
    }
    dtf = builder.toFormatter(locale);
} else {
    dtf = DateTimeFormatter.ofPattern(pattern, locale);
}

LocalDate ld = LocalDate.parse(text, dtf);
System.out.println("user-date: " + ld); // 2069-10-04

There is only one tiny caveat: If any user gets the crazy idea to define two times separately "yy" in the pattern then the proposed solution will fail. The correct solution would then require some kind of iterating over the pattern chars but I think that is overkill, so I leave it out here.

Just for comparison, using my external library Time4J enables following short solution because its parse engine also has the concept of setting any suitable format attributes:

LocalDate ld = 
  ChronoFormatter.ofDatePattern(pattern, PatternType.CLDR, locale)
  .with(Attributes.PIVOT_YEAR, 2070).parse(text).toTemporalAccessor();
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • Because you've written Time4J, I think you would be aware of a possible built-in solution. So it seems your answer is (at the moment) the only and best. Thanks! – halloei Sep 28 '15 at 09:47
  • @halloei Thanks, If someone dares to write a new time library like me - with the goal to improve or introduce a lot of features - then he must know and study very well the strengths and weaknesses of existing standards (like the new java.time-lib). If you look at the with()-methods in `DateTimeFormatter` and non-append()-methods in the builder class (like `parseCaseInsensitive()`) then you can easily see that there is no built-in-solution for your problem. – Meno Hochschild Sep 28 '15 at 11:27