0

I'm running into an issue similar to this post during a JUnit test where a date seems to be parseable by SimpleDateFormat but I'm getting a ParseException saying:

java.text.ParseException: Unparseable date: "05-13-2013"

I'm running under Java 6.

The class under test FileMoveBasedOnControlFile has a function getDateStringEntriesFromStreamwhich takes in an InputStream, tries to parse each line within that Stream as a Date using the format MM-dd-yyyy, converts each successfully parsed date into a new format yyyy-MM-dd, and finally outputs the successfully converted dates to an ArrayList.

'05-11-2013' seems to get parsed fine. The next date in the test '05-13-2013' doesn't. I'm at a loss, and it doesn't seem like InputStream (or '\n') should affect this code. I have tried '\r\n', which didn't work either.

During a test the following code will parse the first but not the second date:

@Test
    public void testMultipleValidEntries() throws IOException
    {
        StringBuilder strBuilder = new StringBuilder();

        String date1 = "05-11-2013";
        String date2 = "05-13-2013";
        String date3 = "05-16-2013";

        strBuilder.append(date1 + "\n");
        strBuilder.append(date2 + "\n");
        strBuilder.append(date3);

        FileMoveBasedOnControlFile fileMoveBasedOnControlFile = new FileMoveBasedOnControlFile();

        InputStream inputStream = new ByteArrayInputStream(strBuilder.toString().getBytes("UTF-8"));

        ArrayList<String> entries = fileMoveBasedOnControlFile.getDateStringEntriesFromStream(inputStream);

        assertTrue(entries.size() == 3);

        assertTrue(entries.get(0).equals("2013-05-11"));
        assertTrue(entries.get(1).equals("2013-05-13"));
        assertTrue(entries.get(2).equals("2013-05-16"));
    }

This is the class function that is under test:

public ArrayList<String> getDateStringEntriesFromStream(InputStream inputStream) throws IOException
    {
        ArrayList<String> controlFileEntries = new ArrayList<String>();
        BufferedReader controlFileReader = new BufferedReader(new InputStreamReader(inputStream));
        String controlFileEntry;

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ORIGINAL_DATE_FORMAT);
        simpleDateFormat.setLenient(false);

        LOG.info("Reading stream.");
        while( (controlFileEntry = controlFileReader.readLine()) != null)
        {
            try
            {
                Date controlFileDate = simpleDateFormat.parse(controlFileEntry);
                simpleDateFormat.applyPattern(NEW_DATE_FORMAT);
                String newDateString = simpleDateFormat.format(controlFileDate);
                controlFileEntries.add(newDateString);
                LOG.info("Got " + newDateString + ".");
            }
            catch(ParseException e)
            {
                LOG.info("Invalid date entry \'" + controlFileEntry  + "\'.");
            }
        }
        if (controlFileEntries.size() == 0)
        {
            LOG.info("Stream is empty.");
        }
        return controlFileEntries;
    }

Where ORIGINAL_DATE_FORMAT is 'MM-dd-yyyy' and NEW_DATE_FORMAT is 'yyyy-MM-dd'.

Community
  • 1
  • 1
Marko Galesic
  • 472
  • 5
  • 17
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Oct 12 '18 at 22:42

1 Answers1

3

Move the SimpleDateFormat declaration into your loop. It works for the first Date, but then fails because it never reinitializes to your ORIGINAL_DATE_FORMAT

LOG.info("Reading stream.");
while( (controlFileEntry = controlFileReader.readLine()) != null)
{
  // Every iteration should start with the ORIGINAL_DATE_FORMAT
  SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ORIGINAL_DATE_FORMAT);
  simpleDateFormat.setLenient(false);
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • 4
    @Tavor: Well yes - if it didn't do that, what did you *expect* it to do and why were you calling it? I would personally just have two `SimpleDateFormat` instances instead though - one for parsing, and one for formatting. There's no need to create a new one for each iteration of the loop – Jon Skeet Sep 15 '15 at 17:33