Search code examples
javajodatimepolish

Parsing date in polish locale in Joda?


I have following date:

eg. String rawDate = "pon, 17 lis 2014, 15:51:12";

and I would like to parse it.

I call:

DateTime time = new DateTimeFormatterBuilder()
                    .append(DateTimeFormat.forPattern("EEE, dd MMM yyyy, HH:mm:ss")
                            .getParser())
                    .toFormatter().withLocale(new Locale("pl")).parseDateTime(rawDate);

But I get:

java.lang.IllegalArgumentException: Invalid format: "pon, 17 lis 2014, 15:51:12"


Solution

  • Good question!

    The JDK uses its own text resources. So following Java-8-code produces an exception:

    String input = "pon, 17 lis 2014, 15:51:12";
    
    DateTimeFormatter dtf1 = 
      DateTimeFormatter.ofPattern("EEE, dd MMM yyyy, HH:mm:ss", new Locale("pl"));
    LocalDateTime ldt1 = LocalDateTime.parse(input, dtf1);
    System.out.print(ldt1);
    // error message:
    // java.time.format.DateTimeParseException:
    // Text 'pon, 17 lis 2014, 15:51:12' could not be parsed at index 0
    

    If we try to find out what is the problem then we find out that JDK uses "Pn":

    DateTimeFormatter dtf1 = 
      DateTimeFormatter.ofPattern("EEE, dd MMM yyyy, HH:mm:ss", new Locale("pl"));
    String output = LocalDateTime.of(2014, 11, 17, 15, 51, 12).format(dtf1);
    System.out.println(output); // "Pn, 17 lis 2014, 15:51:12"
    LocalDateTime ldt1 = LocalDateTime.parse(output, dtf1);
    

    Normally people cannot change the input. Fortunately, there is a workaround defining your own text resources:

    String input = "pon, 17 lis 2014, 15:51:12";
    
    TemporalField field = ChronoField.DAY_OF_WEEK;
    Map<Long,String> textLookup = new HashMap<>();
    textLookup.put(1L, "pon");
    textLookup.put(2L, "wt");
    textLookup.put(3L, "\u0347r"); // śr
    textLookup.put(4L, "czw");
    textLookup.put(5L, "pt");
    textLookup.put(6L, "sob");
    textLookup.put(7L, "niedz");
    
    DateTimeFormatter dtf2 = 
      new DateTimeFormatterBuilder()
      .appendText(field, textLookup)
      .appendPattern(", dd MMM yyyy, HH:mm:ss")
      .toFormatter()
      .withLocale(new Locale("pl"));
    LocalDateTime ldt2 = LocalDateTime.parse(input, dtf2);
    System.out.print(ldt2);
    // output: 2014-11-17T15:51:12
    

    Okay, now about (old) Joda-Time. It is missing such a method like appendText(field, lookupMap). But we can write an implementation for a DateTimeParser:

      final Map<String, Integer> textLookup = new HashMap<String, Integer>();
      textLookup.put("pon", 1);
      textLookup.put("wt", 2);
      textLookup.put("\u0347r", 3); // śr
      textLookup.put("czw", 4);
      textLookup.put("pt", 5);
      textLookup.put("sob", 6);
      textLookup.put("niedz", 7);
    
      DateTimeParser parser =
        new DateTimeParser() {
        @Override
        public int estimateParsedLength() {
            return 5;
        }
        @Override
        public int parseInto(DateTimeParserBucket bucket, String text, int position) {
            for (String key : textLookup.keySet()) {
                if (text.startsWith(key, position)) {
                    int val = textLookup.get(key);
                    bucket.saveField(DateTimeFieldType.dayOfWeek(), val);
                    return position + key.length();
                }
            }
            return ~position;
        }
      };
      DateTimeFormatter dtf =
        new DateTimeFormatterBuilder().append(parser)
        .appendPattern(", dd MMM yyyy, HH:mm:ss").toFormatter()
        .withLocale(new Locale("pl"));
      String input = "pon, 17 lis 2014, 15:51:12";
      LocalDateTime ldt = LocalDateTime.parse(input, dtf);
      System.out.println(ldt); // 2014-11-17T15:51:12.000
    

    Finally a question to you: In Unicode-CLDR-data a dot is used behind the abbreviated weekday names, for example "pon." instead of "pon" (my own library uses the CLDR-content, too). What is more common according to your language knowledge and feeling regarding polish? Using a dot or not?