hamed
hamed

Reputation: 8043

java check a Date instance has the time part

I have a Date field in my class that can has two types of values: with and without time. Something like this: 2015-01-01 and 2015-01-01 12:00:00. I want to make formatted string from my date. I know I can use SimpleDateFormat class for doing this, but I don't know the format. In fact, If my date has the time part, I must use yyyy-MM-dd HH:mm:ss format and if my date does not have the time part, I must use yyyy-MM-dd format. My question is, Is there anyway to check a date has time section before formatting it?

Here is my code:

private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);

.....

private String formatDate(Date date){
     //I need to something like this:
     if(/* `date` has time part */){
          return dateTimeFormat.format(date);
     }

     else{
          return dateFormat.format(date);
     }
}

Upvotes: 1

Views: 3850

Answers (4)

Basil Bourque
Basil Bourque

Reputation: 339043

A Big Mess

As shown in the other answers, the old date-time classes bundled with Java such as java.util.Date and java.sql.Date are a mess. They were rushed to market, with bad design decisions. Specifically a java.util.Date represents both a date and a time-of-day, while its subclass java.sql.Date pretends not to have a time-of-day but actually does. The doc explains that you are supposed to ignore this inheritance relationship to help maintain the illusion. Not good.

java.time

This whole mess has been supplanted by the java.time framework built into Java 8 and later. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.

Date-Only

Among the new classes is LocalDate. This is the first class bundled with Java for representing a date only, without time-of-day nor time zone. To determine a date such as "today", you need a time zone (a ZoneId). For example, a new day dawns earlier in Paris than in Montréal. When you need a date-only value, I suggest you add a member to your class of this type.

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );

Date-Time

If you want a date-time, first consider the Instant class. This marks a moment on the timeline in UTC. Almost always best to do your business logic and data storage in UTC. When you need a specific moment in time rather than a vague date, add a member of this type to your class.

Instant now = Instant.now();

For presentation to the user in their desired/expected time zone, apply a time zone to an Instant to get a ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.ofInstant( now , ZoneId.of( "America/Montreal" ) );

First Moment Of The Day

I do not recommend this strategy, but to directly answer your Question about detecting if the time-of-day in a date-time value happens to be the first moment of the day…

First you need to think about time zone. All of these date-time classes mentioned above track time by a count-from-epoch in UTC. The old classes count in milliseconds, the new in nanoseconds. The epoch for both old and new is the first moment of 1970 in UTC. So there is no such thing as a date-time without a time, as you pose it in the Question. The closest thing to that is a date-time whose time-of-day happens to be the first moment of the day. Seems to be your situation (though my discussion above strongly recommends you change your situation).

How to determine if a date-time has a time-of-day that is the first moment of the day? First you must consider time zone. Either you want UTC or you want a particular time zone such as America/Montreal. Depends on your business rules.

If starting with a java.util.Date, first convert to java.time.

Instant instant = myJUDate.toInstant();

Be aware that a date does not always start at the time 00:00:00.0. Because of Daylight Saving Time (DST), and possibly other anomalies, in some places the first moment of the date is a different wall-clock time. The java.time framework can determine this first moment of the day by using the LocalDate class and its atStartOfDay methods.

So after determining the time zone we care about, we adjust our Instant into a ZonedTimeZone.

Instant instant = Instant.now ();
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );

Next we need to see if that is first moment of the day. So we convert to a LocalDate, then back to another ZonedDateTime by calling atStartOfDay. Comparing the first ZonedDateTime to the second tells us if the original was indeed at the start of the day. To sum it up: We are converting from ZonedDateTime → LocalDate → ZonedDateTime.

// Convert to LocalDate, to get start of day, to compare to above.
LocalDate localDate = zdt.toLocalDate ();
ZonedDateTime startOfDay = localDate.atStartOfDay ( zoneId );
Boolean isStartOfDay = ( zdt.isEqual ( startOfDay ) );

Dump to console.

System.out.println ( "instant: " + instant + " for zoneId: " + zoneId + " is zdt: " + zdt + " if compared to startOfDay: " + startOfDay + " is T/F: " + isStartOfDay );

instant: 2015-12-12T23:20:23.560Z for zoneId: America/Montreal is zdt: 2015-12-12T18:20:23.560-05:00[America/Montreal] if compared to startOfDay: 2015-12-12T00:00-05:00[America/Montreal] is T/F: false

If you want UTC rather than a particular time zone, in the code above use the constant ZoneOffset.UTC as your ZoneId object. ZoneOffset is a subclass of ZoneId.

Upvotes: 2

Ivaylo Toskov
Ivaylo Toskov

Reputation: 4021

You cannot reliably do that, because once you create a Date object, it is represented as a number in milliseconds, which includes the specific time. For this reason you cannot possibly know how the object was built and if the specific time was set.

A workaround would be to check if the hours, minutes and seconds are set to zero. Keep in mind that there is a small probability that the date was parsed as "yyyy-MM-dd HH:mm:ss", but all these values were set to 0, simply because the time was indeed 00:00:00. However, this probability is equal to 1 / (24 * 60 * 60) = 0.00001157407, so I assume that you can live with that.

Upvotes: 2

Remigius Stalder
Remigius Stalder

Reputation: 2170

Use a Calendar object. The calendar can give you structured access to all fields of a Date value, i.e. year, month, day, hours, minutes, seconds, etc. This would allow you to check whether the time fields are non-zero. As JB Nizet stated, the time part can happen to be zero, in which case wou would misinterpret it as a date only value.

Upvotes: 0

Luk
Luk

Reputation: 78

Assuming you're using java.sql.Date which derives from java.util.Date there is no possibility of a Date object not having a time value. Note the documentation: http://docs.oracle.com/javase/7/docs/api/java/sql/Date.html A Date object instance holds a miliseconds value, to be precise the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.

Upvotes: 1

Related Questions