145

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?

Michael Currie
  • 13,721
  • 9
  • 42
  • 58
Adelin
  • 18,144
  • 26
  • 115
  • 175
  • Could this have something to do with different locales or does this happen from the same PC all the time? – LostBoy Jul 23 '13 at 21:48
  • it happens when I deploy on appengine. – Adelin Jul 23 '13 at 21:50
  • Lots of other solutions for cutting off time: http://stackoverflow.com/a/1908955/2646526 – heenenee Feb 02 '16 at 01:23
  • FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/9/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/9/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/9/docs/api/java/time/package-summary.html) classes built into Java 8 & Java 9. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Feb 01 '18 at 04:42
  • 1
    I used `calendar.set(Calendar.HOUR_OF_DAY, 0);`, for my purpose, it works well. – hariprasad Jul 31 '19 at 13:02

14 Answers14

242

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
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • 3
    @JarrodRoberson But using `Calendar.HOUR` wouldn't set PM to AM, leaving it as 12:00 noon. – rgettman Jul 23 '13 at 21:48
  • Can you please help me in constructing a LocalDate with hours, minute and second? I know one option is to follow DateTime. – Woody Jul 23 '15 at 10:05
  • 16
    Whoever created the field HOUR and HOUR_OF_DAY should have been flogged and put on rations. – Johann Sep 08 '15 at 14:19
  • 2
    @AndroidDev whoever invented am/pm deserves the same... This also goes for non-metric standards – Dediqated Sep 09 '16 at 15:09
  • 1
    FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/9/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/9/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/9/docs/api/java/time/package-summary.html) classes built into Java 8 & Java 9. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Feb 01 '18 at 04:42
  • 2
    All is correct, but there should be millis also: now.set(Calendar.MILLISECOND, 0); – Sergey Chepurnov Jan 29 '19 at 03:31
  • You can set Minutes and Seconds too . Say for example : calender.set(Calendar.MINUTE, 59); calender.set(Calendar.SECOND, 46); – Pratik Roy Jun 23 '21 at 05:26
41

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
Przemek
  • 7,111
  • 3
  • 43
  • 52
  • 2
    This should be the new accepted answer since Java 1.8 has been released since this question was first asked. – matt forsythe Feb 01 '18 at 18:00
  • `LocalDateTime` is exactly the **wrong class** to use for this. It cannot represent a moment as it lacks any concept of time zone or offset-from-UTC. Calling `LocalDateTime.now` almost never makes sense. Use `ZonedDateTime` instead. Otherwise you are ignoring crucial time zone issues. For one thing, some dates in some zones do *not* start at 00:00! – Basil Bourque May 26 '19 at 20:28
15

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();
}
14

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.

thorinkor
  • 958
  • 1
  • 11
  • 20
  • 1
    `LocalDateTime` cannot represent a moment, as it lacks any concept of time zone or offset-from-UTC. Calling `LocalDateTime.now` almost never makes sense. You should be using `ZonedDateTime` instead. – Basil Bourque May 26 '19 at 20:10
6

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.

Benson Githinji
  • 559
  • 7
  • 10
3

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());
3

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


Chao Jiang
  • 483
  • 3
  • 13
  • `LocalDateTime` cannot represent a moment, as it lacks any concept of time zone or offset-from-UTC. Calling `LocalDateTime.now` almost never makes sense. You should be using `ZonedDateTime` instead. – Basil Bourque May 26 '19 at 20:08
3

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 ) ;
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

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);
2

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))
Jadson Santos
  • 199
  • 1
  • 2
  • 11
1

Doing this could be easier (In Java 8)

LocalTime.ofNanoOfDay(0)
Adelin
  • 18,144
  • 26
  • 115
  • 175
meszias
  • 91
  • 1
  • 4
  • Thank you, I worked with other stuff last 2 years, and Java 6/7 before it. I've back to Java now (after worked with few things on Groovy) and liking Java 8 differences. – meszias Feb 28 '17 at 19:30
0

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;
}
MMascarin
  • 468
  • 4
  • 6
0

You can either do this with the following:

Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth, 0, 0, 0);
Date date = cal.getTime();
SagarScript
  • 1,145
  • 11
  • 15
0

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