136

I have a Java Date object containing date and time information. I want to write a method that cuts off the time information, truncates the hours-minutes-seconds, so I only have the date left.

Example input:

2008-01-01 13:15:00

Expected output:

2008-01-01 00:00:00

Do you have a tip? I tried doing something like this:

(timestamp / (24 * 60 * 60 * 1000)) * (24 * 60 * 60 * 1000)

but I ran into problems with the timezone.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Marco
  • 2,005
  • 4
  • 16
  • 9

21 Answers21

185

The recommended way to do date/time manipulation is to use a Calendar object:

Calendar cal = Calendar.getInstance(); // locale-specific
cal.setTime(dateObject);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long time = cal.getTimeInMillis();
jitter
  • 53,475
  • 11
  • 111
  • 124
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 3
    @cletus, Is it possible to remove the time from Date object. I want pure date like 2008-01-01 no time portion. – Prem Mar 22 '12 at 04:06
  • 2
    I would not say java.util.Calendar is recommended. Sun/Oracle supplanted that class in Java 8 with the new java.time package. Use either that or Joda-Time. – Basil Bourque Jun 20 '14 at 17:26
  • 3
    Calendar is no longer recommended. See http://stackoverflow.com/a/28868089/40064 if you are using Java 8. – Wim Deblauwe Jan 13 '16 at 13:36
  • 3
    FYI, the troublesome old date-time classes such as [`java.util.Calendar`](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html) are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Sep 02 '17 at 17:52
167

Have you looked at the DateUtils truncate method in Apache Commons Lang?

Date truncatedDate = DateUtils.truncate(new Date(), Calendar.DATE);

will remove the time element.

Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92
A_M
  • 7,693
  • 6
  • 33
  • 37
  • 10
    Updated link again (come on Apache! Quit movin your docs around!) – Ogre Psalm33 Jan 31 '14 at 21:00
  • 6
    Minus of this approach that timezone in what truncate operation is performed is always local PC timezone. So if you working with calendar and dates in UTC timezone or in any timezone other than local timezone - it could truncate date not as intended. – Cloud Sep 30 '15 at 10:09
  • as @Cloud pointed out, the fact that i don't see the Calendar instance here (have no control over it) makes me a bit nervous :) – Jaroslav Záruba Oct 08 '17 at 14:19
  • That method is surprisingly long and had at least two bugfixes. – Pino Aug 23 '18 at 10:08
  • I like simple, elegant solutions like this one. With Calendar, you have to make 6 different api calls. When your application is always, always only ever going to run in one time zone--because it is deployed on a server and it is for the State government--you can feel pretty safe that you won't have problems with timezone. – Chad Lehman Apr 20 '21 at 18:19
48

Just a quick update in light of the java.time classes now built into Java 8 and later.

LocalDateTime has a truncatedTo method that effectively addresses what you are talking about here:

LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES)

This will express the current time down to minutes only:

2015-03-05T11:47

You may use a ChronoUnit (or a TemporalUnit) smaller than DAYS to execute the truncation (as the truncation is applied only to the time part of LocalDateTime, not to the date part).

Matvey Zhuravel
  • 154
  • 2
  • 13
Adam Berry
  • 493
  • 4
  • 6
41

Have you looked at Joda ? It's a much easier and more intuitive way to work with dates and times. For instance you can convert trivially between (say) LocalDateTime and LocalDate objects.

e.g. (to illustrate the API)

LocalDate date = new LocalDateTime(milliseconds).toLocalDate()

Additionally it solves some thread-safety issues with date/time formatters and is to be strongly recommended for working with any date/time issues in Java.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 12
    I believe it does. It's a recommendation to use a better library rather than battle with the broken java.util classes (as evidenced by the question) – Brian Agnew Dec 15 '09 at 16:38
  • 10
    Of course it relates, Joda is THE library for date,time & calendar manipulation in Java. It would be a dereliction of duty not to recommend it. – Joel Dec 15 '09 at 16:44
  • I confess I was faintly surprised not to find anyone else mentioning it. Thanks for emphasising that. – Brian Agnew Dec 15 '09 at 16:47
  • 1
    The thread safety issue is very interesting, I found this post researching an Oracle/Hibernate error "IllegalArgumentException, sun.util.calendar.ZoneInfo.getOffset(ZoneInfo), oracle.jdbc.driver.DateCommonBinder.zoneOffset(OraclePreparedStatement)". This talks about another Oracle problems only appearing w heavy load https://forums.oracle.com/forums/thread.jspa?threadID=325576 It's really hard to even create an object with invalid milliseconds in normal code. For me, I think I'll downcast in my thread using Joda, rather than let Oracle use the possibly-suspect non-joda stuff. – Mark Bennett Nov 04 '11 at 21:41
  • 4
    I wish I could downvote everybody who up-voted this. Who are all these people who +1 a reply that doesn't even attempt to answer the question? An answer using Joda would be more than welcome, but this isn't it... – Ryan Nov 21 '13 at 08:07
  • 1
    @Ryan How is this answer not relevant? The Question asked for the date without a time-of-day. This answer presents a class whose sole purpose is representing a date without a time-of-day. – Basil Bourque Jun 20 '14 at 17:36
  • At first I was thinking I was just being a frustrated prick until I thought about it. The poster asked about modifying a Java `java.util.Date` object. The resultant object in this answer is not a `Date` nor can it be (effortlessly) used in a `Date`. `Date` has time fields, `LocalDate` does not. I probably literally needed '00:00:00' like in the question. – Ryan Jun 20 '14 at 21:05
  • 1
    @Ryan As I mentioned in [my answer](http://stackoverflow.com/a/24332866/642706), the question is not clear. Does the person want (a) no time-of-day as suggested by title, or (b) does the person want first moment of the day ("midnight") as suggested by the example `00:00:00`? My supposition, like Brian Agnew, is that the person asking wants a date-only with no time-of-day but with only java.util.Date as a frame of reference does not know how to ask otherwise. Before Java 8, there is **no built-in way to truly represent date-only**. `LocalDate` in Joda-Time & java.time is a legitimate solution. – Basil Bourque Jun 21 '14 at 01:03
  • 1
    FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), with the team advising migration to the [*java.time*](http://docs.oracle.com/javase/9/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Mar 28 '18 at 00:14
  • This answer is irrelevant. If you're trying to manipulate dates dealing with JDBC information, you don't have the choice of using JodaTime really. JDBC STILL uses java.util.Date, despite it being horribly broken. – PlexQ Mar 28 '21 at 17:08
  • @PlexQ no mention of JDBC in the question, I’m afraid – Brian Agnew Mar 28 '21 at 18:02
27
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
date = cal.getTime();
jitter
  • 53,475
  • 11
  • 111
  • 124
22

With Joda you can easily get the expected date.

As of version 2.7 (maybe since some previous version greater than 2.2), as a commenter notes, toDateMidnight has been deprecated in favor or the aptly named withTimeAtStartOfDay(), making the convenient

DateTime.now().withTimeAtStartOfDay()

possible.

Benefit added of a way nicer API.

With older versions, you can do

new DateTime(new Date()).toDateMidnight().toDate()
h7r
  • 4,944
  • 2
  • 28
  • 31
  • 6
    The midnight-related methods and classes in Joda-Time are now deprecated. The developers recommend against using them. Instead use the method `withTimeAtStartOfDay`. – Basil Bourque Jun 20 '14 at 17:28
  • Thank you for pointing out. Updated the answer to consider this. – h7r Feb 10 '15 at 20:31
  • You can also use `toLocalDate` to get an object that doesn't even have a time component. – Charles Wood Dec 01 '15 at 18:15
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), with the team advising migration to the [*java.time*](http://docs.oracle.com/javase/9/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Mar 28 '18 at 00:15
12

I did the truncation with new java8 API. I faced up with one strange thing but in general it's truncate...

Instant instant = date.toInstant();
instant = instant.truncatedTo(ChronoUnit.DAYS);
date = Date.from(instant);
Sergio Kosik
  • 192
  • 2
  • 6
8

tl;dr

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.toString()                                     // Generate a String in standard ISO 8601 format, wisely extended to append the name of the time zone in square brackets.

2008-01-01T00:00+01:00[Europe/Paris]

To generate a String in your desired format, pass a DateTimeFormatter.

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.format(                                        // Generate a String representing the object’s value.
    DateTimeFormatter.ISO_LOCAL_DATE_TIME       // Built-in predefined formatter close to what you want. 
)
.replace( "T" , " " )                           // Replace the standard’s use of a 'T' in the middle with your desired SPACE character.

2008-01-01 00:00:00

Details

Other Answers are correct, but use old date-time classes now outmoded by the java.time framework.

java.time

The java.time framework is built into Java 8 and later. Much of the java.time functionality is back-ported to Java 6 & 7 (ThreeTen-Backport) and further adapted to Android (ThreeTenABP).

First alter the input string to comply with the canonical version of ISO 8601 format. The standard ISO 8601 formats are used by default in java.time classes for parsing/generating strings that represent date-time values. We need to replace that SPACE in the middle with a T.

String input = "2008-01-01 13:15:00".replace( " " , "T" );  // → 2008-01-01T13:15:00

Now we can parse it as a LocalDateTime, where “Local” means no specific locality. The input lacks any offset-from-UTC or time zone info.

LocalDateTime ldt = LocalDateTime.parse( input );

ldt.toString()… 2008-01-01T13:15:00

If you do not care about time-of-day nor time zone, then convert to a LocalDate.

LocalDate ld = ldt.toLocalDate();

ld.toString()… 2008-01-01

First Moment Of Day

If instead you want the time-of-day set to the first moment of the day, use a ZonedDateTime class, then convert to a LocalDate object to call its atStartOfDay method. Be aware that the first moment may not be the time 00:00:00 because of Daylight Saving Time or perhaps other anomalies.

The time zone is crucial because for any given moment the date varies around the world by zone. For example, a few moments after midnight in Paris is a new day for Parisians but is still “yesterday” in Montréal for the Canadians.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );
LocalDate ldFromZdt = zdt.toLocalDate();
ZonedDateTime zdtStartOfDay = ldFromZdt.atStartOfDay( zoneId );

zdtStartOfDay.toString()… 2008-01-01T00:00:00-05:00[America/Montreal]

UTC

To see that moment through the lens of the UTC time zone, extract a Instant object. Both the ZonedDateTime and Instant will represent the same moment on the timeline but appear as two different wall-clock times.

An Instant is the basic building-block class in java.time, always in UTC by definition. Use this class frequently, as you should generally be doing your business logic, data storage, and data exchange in UTC.

Instant instant = zdtStartOfDay.toInstant();

instant.toString()… 2008-01-01T05:00:00Z

We see 5 AM rather than stroke-of-midnight. In standard format, the Z on the end is short for Zulu and means “UTC”.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
6

Use DateUtils from Apache, with truncate, like this:

DateUtils.truncate(Calendar.getInstance().getTime(), Calendar.DATE);
6

For timestamps:

timestamp -= timestamp % (24 * 60 * 60 * 1000)
nibarius
  • 4,007
  • 2
  • 38
  • 56
Gan Quan
  • 449
  • 5
  • 13
  • 3
    There is an tiny error in this code - the left bracket in not placed correctly, it must be timestamp -= timestamp % (24 * 60 * 60 * 1000). This will cut off the time part. And Im sure this way is more sufficient than creating Caledar object and playing with its methods or even using any other 3rd party libraries – Stan Dec 12 '13 at 21:21
  • 2
    No, this is NOT the correct solution, BEWARE. This is the same as rounding the date value to floor, that is - you may get 28 March for timestamp of 29 March (in your locale). So Calendar-based solutions (Apache's DateUtils uses Calendar, too) is the only way – Drew Mar 31 '16 at 07:46
  • This will also not work when the time changes due to Daylight saving time. – Alexandru Severin Jan 13 '17 at 13:03
6

Just clear() redundant fields.

Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.clear(Calendar.MINUTE);
calendar.clear(Calendar.SECOND);
calendar.clear(Calendar.MILLISECOND);
Date truncatedDate = calendar.getTime();

From Java 8 a better option is to use truncatedTo method of LocalDateTime, e.g.:

LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)
m190
  • 351
  • 5
  • 11
  • This doesn't work, because `calendar.clear(Calendar.HOUR_OF_DAY);` doesn't clear hours. The solution from @cletus works OK. – Arcao Jun 27 '13 at 13:29
  • Sorry, you are right, I corrected it, for hours you should set the value. In general it almost the same way how to truncate date... – m190 Jun 28 '13 at 07:05
5

From java.util.Date JavaDocs:

The class Date represents a specific instant in time, with millisecond precision

and from the java.sql.Date JavaDocs:

To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

So, the best approach is to use java.sql.Date if you are not in need of the time part

java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());

and the output is:

java.util.Date : Thu Apr 26 16:22:53 PST 2012
java.sql.Date  : 2012-04-26
Sunil Manheri
  • 2,313
  • 2
  • 18
  • 19
3

Use the Calendar class's set() method to set the HOUR_OF_DAY, MINUTE, SECOND and MILLISECOND fields to zero.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
2

The question is contradictory. It asks for a date without a time of day yet displays an example with a time of 00:00:00.

Joda-Time

UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. See my other Answer for java.time solution.

If instead you want the time-of-day set to the first moment of the day, use a DateTime object on the Joda-Time library and call its withTimeAtStartOfDay method. Be aware that the first moment may not be the time 00:00:00 because of Daylight Saving Time or perhaps other anomalies.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

You can do this to avoid timezone issue:

public static Date truncDate(Date date) {
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

Although Java Date object is timestamp value, but during truncate, it will be converted to local timezone, so you will get surprising value if you expect value from UTC timezone.

Sam YC
  • 10,725
  • 19
  • 102
  • 158
  • The troublesome `Calendar` and `Date` classes became legacy years ago with the *java.time* classes implementing JSR 310 in Java 8 and later. Suggesting their use in 2018 is poor advice. – Basil Bourque Mar 13 '18 at 19:33
1

It really annoyed me that the new "improved" calendar constructor doesn't take an int for milliseconds like the "awful" old Date one. I then got really cross and wrote this:

long stuffYou = startTime.getTimeInMillis() % 1000;
startTime.setTimeInMillis(startTime.getTimeInMillis() - stuffYou);

I didn't use the word "stuff" at the time, but then I discovered the happiness of this:

startTime.set(Calendar.MILLISECOND, 0);

But I'm still quite cross about it.

Dave
  • 3,093
  • 35
  • 32
1

I fixed the issue like this(in Eastern eight zone(Beijing time)):

private Date getTruncatedDate(Date d) {
    if (d == null) {
        return null;
    }
    long h = 60 * 60 * 1000L;
    long dateStamp = d.getTime() - (d.getTime() + 8 * h) % (24 * h);
    return new Date(dateStamp);
}

First of all, you should be clear what is time stamp. Time stamp is the total milliseconds from Jan 01 00:00:00 1970 of GMT(same as UTC), or Thu Jan 01 08:00:00 CST 1970 to now.

Remember: Time stamp is independent of time zone.

So you get same result with the following statement in differnt time zones:

System.out.println(new Date().getTime());

And

System.out.println(new Date(0));

prints diferent time info in different time zones: If you set your pc time zone as UTC, you get

Thu Jan 01 00:00:00 UTC 1970

But if you set the time zone as (UTC +8:00) Beijing, Chongqing, HongKong, Urumq, you get:

Thu Jan 01 08:00:00 CST 1970

Java gets the time stamp, then displays date and time info according on the time zone.

For the introduction of how Java displays date and time info in different time zones, how to trancate the time info is easy. You should get the time stamp , and take the time zone into account when cut off the time info. Then you can create a new Date object with the cut time stamp(we can call it date stamp), java will compensate the time zone when displays date info.

As in Eastern eight zone(Beijing time), the Beijing time is earlier 8 hours than GMT, so you should subtract more 8 hours when you do the modulo operation. That's to say, you should get the GMT time first, then Java will add 8 hours when display time based on your pc's time zone setting.


The time zone issue is obscure, and also puzzles me for a long time. Now I make it clear. Hope helps.


2018-01-04 The method below also works.

private Date getTruncatedDate2(Date d) {
    Calendar cal = Calendar.getInstance(); // locale-specific
    cal.setTime(d);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);


return cal.getTime();

}

Gelbert
  • 11
  • 4
0

Might be a late response but here is a way to do it in one line without using any libraries:

new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(YOUR_TIMESTAMP))
Alex
  • 103
  • 1
  • 1
  • 10
0

With Joda-Time since version 2.0 you can use LocalDate.toDate().

Simply

// someDatetime is whatever java.util.Date you have.
Date someDay = new LocalDate(someDatetime).toDate();
lamusique
  • 392
  • 4
  • 6
  • [A] Your answer is redundant. Already [posted by Brian Agnew](http://stackoverflow.com/a/1908647/642706). [B] Your code is incorrect, as it ignores time zone, the very issue raised in the question. – Basil Bourque Jul 08 '14 at 06:47
  • Could be redundant but I just put a simpler example here because I recognized an answer shouldn't be in comments. Yes, java.util.Date ignores TimeZone but the original question was with `a Java Date object` thus I used `java.util.Date`. Moreover it doesn't explain how his timezone is problematic with java.util.Date (when? where?) although he can't help using other than `Date`. – lamusique Jul 08 '14 at 07:22
0

For all the answers using Calendar, you should use it like this instead

public static Date truncateDate(Date date) {
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, c.getActualMinimum(Calendar.HOUR_OF_DAY));
    c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
    c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
    c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND));
    return c.getTime();
}

But I prefer this:

public static Date truncateDate(Date date) {
    return new java.sql.Date(date.getTime());
}
Guest
  • 1
  • 1
  • The `java.sql.Date` class pretends to represent a date-only value but actually does have a time-of-day adjusted for UTC time zone. So not really a fit solution to the Question. – Basil Bourque Jun 18 '16 at 00:29
0

Solution: e.g: for truncating the timestamp to minutes, use:

Timestamp timestamp=  Timestamp.from(Instant.now());

              Timestamp.from(timestamp.toInstant().truncatedTo(ChronoUnit.MINUTES);
justCurious
  • 720
  • 7
  • 13
  • 1
    Only (1) Since you can use java.time, the modern Java date and time API to which `Instant` and `ChronoUnit` belong, you should not wish to use the old and hacky `Timestamp` class at all. (2) The question was about cutting the entire time away, setting it to the start of the day, not only the minutes (and using `ChronoUnit.DAYS` will not work for that). – Ole V.V. May 12 '23 at 10:36