Question: I'm looking for a clean solution for formatting [Date](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html) objects with optional parts. My date object can be a timestamp value, a time-only value or a date-only value.

### Expected output

I would like to display the date value like this:

If the date's [ms value](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html#getTime--) is less than (86400\*1000) then it means the value is a really a time-only value. If so display like this:

```
HH:mm:ss.SSS

```

If the date's value is exactly at midnight then it means it is a date-only value. If so display like this:

```
yyyy-MM-dd

```

Otherwise display like this:

```
yyyy-MM-dd HH:mm:ss.SSS

```

### Solution constraints

Unfortunately I'm working with `Date` as the input. Can't be changed. I'm only interested in formatting/rendering, not in parsing. External libraries are a hard sell in my organization.

For the purpose of formatting it would of course be acceptable to first convert to one of new Java 8 date/time objects if that will make the solution simpler.

Platform : Java 8 SE

Answer: 
First step
==========

Convert `Date` into a Java 8 equivalent structure:

```
private static TemporalAccessor toJava8Time(Date date) {
    Instant instant = date.toInstant();

    if (instant.isBefore(Instant.ofEpochSecond(86400))) {
        return instant.atZone(ZoneId.systemDefault()).toLocalTime();
    } else if (instant.equals(instant.truncatedTo(ChronoUnit.HOURS))) {
        return instant.atZone(ZoneId.systemDefault()).toLocalDate();
    } else {
        return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
}

```

Second step
===========

Create a formatter generic enough to stringify `LocalTime`, `LocalDate` and `LocalDateTime` as you need:

```
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd] [HH:mm:ss]");

```

Usage
=====

```
Date time = new Date(39733000L); // 1970-01-01T12:02:13
Date date = new Date(1462399200000L); // 2016-05-05T00:00:00
Date dateTime = new Date(1462442533000L); // 2016-05-05T12:02:13

Stream.of(time, date, dateTime)
        .map(d -> toJava8Time(d))
        .map(t -> formatter.format(t).trim())
        .forEach(System.out::println);

//Outputs "12:02:13", "2016-05-05", "2016-05-05 12:02:13"

```

Note: I had to call `trim()` otherwise the time would begin with a space.
I think you need multiple SimpleDateFormat objects for it. Your code may look like this:

```
SimpleDateFormat timeOnlySdf = new SimpleDateFormat( "HH:mm:ss.SSS");
SimpleDateFormat dateOnlySdf = new SimpleDateFormat( "yyyy-MM-dd");
SimpleDateFormat dateAndTimeSdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS");

Date epochPlusOne = new Date( 86400 * 1000);
Calendar cal = Calendar.getInstance();
cal.setTime( myDate);

if( myDate.before( epochPlusOne))
{
    System.out.println( timeOnlySdf.format( myDate));
}
else if( cal.get( Calendar.HOUR) == 0 && 
        cal.get( Calendar.MINUTE) == 0 && 
        cal.get( Calendar.SECOND) == 0 && 
        cal.get( Calendar.MILLISECOND) == 0)
{
    System.out.println( dateOnlySdf.format( myDate));
}
else
{
    System.out.println( dateAndTimeSdf.format( myDate));
}

```