Question

I have a problem resetting hours in Java. For a given date I want to set the hours to 00:00:00.

This is my code :

/**
     * Resets milliseconds, seconds, minutes and hours from the provided date
     *
     * @param date
     * @return
     */
    public static Date trim(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR, 0);

        return calendar.getTime();
    }

The problem is that sometimes the time is 12:00:00 and sometimes it is 00:00:00 and when I query the database for an entity that was saved on 07.02.2013 00:00:00 and the actual entity time, that is stored, is 12:00:00 the query fails.

I know that 12:00:00 == 00:00:00!

I am using AppEngine. Is this an appengine bug, problem or some other issue? Or does it depend on something else?

Was it helpful?

Solution

Use another constant instead of Calendar.HOUR, use Calendar.HOUR_OF_DAY.

calendar.set(Calendar.HOUR_OF_DAY, 0);

Calendar.HOUR uses 0-11 (for use with AM/PM), and Calendar.HOUR_OF_DAY uses 0-23.

To quote the Javadocs:

public static final int HOUR

Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.

and

public static final int HOUR_OF_DAY

Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.

Testing ("now" is currently c. 14:55 on July 23, 2013 Pacific Daylight Time):

public class Main
{
   static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args)
    {
        Calendar now = Calendar.getInstance();
        now.set(Calendar.HOUR, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        System.out.println(sdf.format(now.getTime()));
        now.set(Calendar.HOUR_OF_DAY, 0);
        System.out.println(sdf.format(now.getTime()));
    }
}

Output:

$ javac Main.java
$ java Main
2013-07-23 12:00:00
2013-07-23 00:00:00

OTHER TIPS

java.time

Using the java.time framework built into Java 8 and later. See Tutorial.

import java.time.LocalTime;
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now(); # 2015-11-19T19:42:19.224
# start of a day
now.with(LocalTime.MIN); # 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); # 2015-11-19T00:00

If you do not need time-of-day (hour, minute, second etc. parts) consider using LocalDate class.

LocalDate.now(); # 2015-11-19

Here are couple of utility functions I use to do just this.

/**
 * sets all the time related fields to ZERO!
 *
 * @param date
 *
 * @return Date with hours, minutes, seconds and ms set to ZERO!
 */
public static Date zeroTime( final Date date )
{
    return DateTimeUtil.setTime( date, 0, 0, 0, 0 );
}

/**
 * Set the time of the given Date
 *
 * @param date
 * @param hourOfDay
 * @param minute
 * @param second
 * @param ms
 *
 * @return new instance of java.util.Date with the time set
 */
public static Date setTime( final Date date, final int hourOfDay, final int minute, final int second, final int ms )
{
    final GregorianCalendar gc = new GregorianCalendar();
    gc.setTime( date );
    gc.set( Calendar.HOUR_OF_DAY, hourOfDay );
    gc.set( Calendar.MINUTE, minute );
    gc.set( Calendar.SECOND, second );
    gc.set( Calendar.MILLISECOND, ms );
    return gc.getTime();
}

One more JAVA 8 way:

LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);

But it's a lot more useful to edit the date that already exists.

See the below code:

    String datePattern24Hrs = "yyyy-MM-dd HH:mm:ss";
    String datePattern12Hrs = "yyyy-MM-dd hh:mm:ss";

    SimpleDateFormat simpleDateFormat24Hrs = new SimpleDateFormat(datePattern24Hrs);
    SimpleDateFormat simpleDateFormat12Hrs = new SimpleDateFormat(datePattern12Hrs);

    Date dateNow = new Date();
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(dateNow);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    Date dateTime = calendar.getTime();

    String dateTimeIn24Hrs = simpleDateFormat24Hrs.format(dateTime);
    String dateTimeIn12Hrs = simpleDateFormat12Hrs.format(dateTime);

    System.out.println("DateTime in 24Hrs: ".concat(dateTimeIn24Hrs));
    System.out.println("DateTime in 12Hrs: ".concat(dateTimeIn12Hrs));

The expected output is as below:

  • DateTime in 24Hrs: 2021-06-29 00:00:00
  • DateTime in 12Hrs: 2021-06-29 12:00:00

I hope it helps with the answer you are looking for.

You would better to primarily set time zone to the DateFormat component like this:

DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

Then you can get "00:00:00" time by passing 0 milliseconds to formatter:

String time = dateFormat.format(0);

or you can create Date object:

Date date = new Date(0); // also pass milliseconds
String time = dateFormat.foramt(date);

or you be able to have more possibilities using Calendar component but you should also set timezone as GMT to calendar instance:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US);
calendar.set(Calendar.HOUR_OF_DAY, 5);
calendar.set(Calendar.MINUTE, 37);
calendar.set(Calendar.SECOND, 27);

dateFormat.format(calendar.getTime());

tl;dr

myJavaUtilDate                                 // The terrible `java.util.Date` class is now legacy. Use *java.time* instead.
.toInstant()                                   // Convert this moment in UTC from the legacy class `Date` to the modern class `Instant`.
.atZone( ZoneId.of( "Africa/Tunis" ) )         // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
.toLocalDate()                                 // Extract the date-only portion.
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )   // Determine the first moment of that date in that zone. The day does *not* always start at 00:00:00.

java.time

You are using terrible old date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310.

DateInstant

A java.util.Date represent a moment in UTC. Its replacement is Instant. Call the new conversion methods added to the old classes.

Instant instant = myJavaUtilDate.toInstant() ;

Time zone

Specify the time zone in which you want your new time-of-day to make sense.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

ZonedDateTime

Apply the ZoneId to the Instant to get a ZonedDateTime. Same moment, same point on the timeline, but different wall-clock time.

ZonedDateTime zdt = instant.atZone( z ) ;

Changing time-of-day

You asked to change the time-of-day. Apply a LocalTime to change all the time-of-day parts: hour, minute, second, fractional second. A new ZonedDateTime is instantiated, with values based on the original. The java.time classes use this immutable objects pattern to provide thread-safety.

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.
ZonedDateTime zdtAtThreeThirty = zdt.with( lt ) ; 

First moment of day

But you asked specifically for 00:00. So apparently you want the first moment of the day. Beware: some days in some zones do not start at 00:00:00. They may start at another time such as 01:00:00 because of anomalies such as Daylight Saving Time (DST).

Let java.time determine the first moment. Extract the date-only portion. Then pass the time zone to get first moment.

LocalDate ld = zdt.toLocalDate() ;
ZonedDateTime zdtFirstMomentOfDay = ld.atStartOfDay( z ) ;

Adjust to UTC

If you need to go back to UTC, extract an Instant.

Instant instant = zdtFirstMomentOfDay.toInstant() ;

InstantDate

If you need a java.util.Date to interoperate with old code not yet updated to java.time, convert.

java.util.Date d = java.util.Date.from( instant ) ;

As Java8 add new Date functions, we can do this easily.


    // If you have instant, then:
    Instant instant1 = Instant.now();
    Instant day1 = instant1.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day1); //2019-01-14T00:00:00Z

    // If you have Date, then:
    Date date = new Date();
    Instant instant2 = date.toInstant();
    Instant day2 = instant2.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day2); //2019-01-14T00:00:00Z

    // If you have LocalDateTime, then:
    LocalDateTime dateTime = LocalDateTime.now();
    LocalDateTime day3 = dateTime.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day3); //2019-01-14T00:00
    String format = day3.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    System.out.println(format);//2019-01-14T00:00:00


Doing this could be easier (In Java 8)

LocalTime.ofNanoOfDay(0)

Another simple way,

final Calendar today = Calendar.getInstance();
        today.setTime(new Date());
        today.clear(Calendar.HOUR_OF_DAY);
        today.clear(Calendar.HOUR);
        today.clear(Calendar.MINUTE);
        today.clear(Calendar.SECOND);
        today.clear(Calendar.MILLISECOND);

Another way to do this would be to use a DateFormat without any seconds:

public static Date trim(Date date) {
    DateFormat format = new SimpleDateFormat("dd.MM.yyyy");
    Date trimmed = null;
    try {
        trimmed = format.parse(format.format(date));
    } catch (ParseException e) {} // will never happen
    return trimmed;
}

You can either do this with the following:

Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth, 0, 0, 0);
Date date = cal.getTime();

If you need format 00:00:00 in string, you should use SimpleDateFormat as below. Using "H "instead "h".

Date today = new Date();
SimpleDateFormat ft = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); 
//not SimpleDateFormat("dd-MM-yyyy hh:mm:ss")
Calendar calendarDM = Calendar.getInstance();
calendarDM.setTime(today);
calendarDM.set(Calendar.HOUR, 0);
calendarDM.set(Calendar.MINUTE, 0);
calendarDM.set(Calendar.SECOND, 0);
System.out.println("Current Date: " + ft.format(calendarDM.getTime()));

//Result is: Current Date: 29-10-2018 00:00:00

Before Java 8:

Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);

After Java 8:

LocalDateTime.now().with(LocalTime.of(0, 0, 0))

We can set java.util.Date time part to 00:00:00 By using LocalDate class of Java 8/Joda-datetime api:

Date datewithTime = new Date() ; // ex: Sat Apr 21 01:30:44 IST 2018
LocalDate localDate = LocalDate.fromDateFields(datewithTime);
Date datewithoutTime = localDate.toDate(); // Sat Apr 21 00:00:00 IST 2018
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top