Resetting the time part of a timestamp in Java
Asked Answered
U

10

39

In Java, given a timestamp, how to reset the time part alone to 00:00:00 so that the timestamp represents the midnight of that particular day ?

In T-SQL, this query will do to achieve the same, but I don't know how to do this in Java.

SELECT CAST( FLOOR( CAST(GETDATE() AS FLOAT ) ) AS DATETIME) AS 'DateTimeAtMidnight';

Unstop answered 22/10, 2008 at 18:28 Comment(0)
M
82

You can go Date->Calendar->set->Date:

Date date = new Date();                      // timestamp now
Calendar cal = Calendar.getInstance();       // get calendar instance
cal.setTime(date);                           // set cal to date
cal.set(Calendar.HOUR_OF_DAY, 0);            // set hour to midnight
cal.set(Calendar.MINUTE, 0);                 // set minute in hour
cal.set(Calendar.SECOND, 0);                 // set second in minute
cal.set(Calendar.MILLISECOND, 0);            // set millis in second
Date zeroedDate = cal.getTime();             // actually computes the new Date

I love Java dates.

Note that if you're using actual java.sql.Timestamps, they have an extra nanos field. Calendar of course, knows nothing of nanos so will blindly ignore it and effectively drop it when creating the zeroedDate at the end, which you could then use to create a new Timetamp object.

I should also note that Calendar is not thread-safe, so don't go thinking you can make that a static single cal instance called from multiple threads to avoid creating new Calendar instances.

Macaroon answered 22/10, 2008 at 18:38 Comment(1)
Seriously, who ever named it Date? It's a timestamp.Luckless
C
19

If you're using commons lang you can call DateUtils.truncate. Here's the javadoc documentation.

It does the same thing @Alex Miller said to do.

Coppage answered 22/10, 2008 at 21:22 Comment(1)
Where do you find that library, DateUtils?Goatfish
K
7

Assuming your "timestamp" is a java.util.Date, which is represented as the number of milliseconds since the beginning of the epoch (Jan 1, 1970), you can perform the following arithmetic:

public static Date stripTimePortion(Date timestamp) {
    long msInDay = 1000 * 60 * 60 * 24; // Number of milliseconds in a day
    long msPortion = timestamp.getTime() % msInDay;
    return new Date(timestamp.getTime() - msPortion);
}
Kalsomine answered 22/10, 2008 at 18:37 Comment(4)
Note that if the Date here is actually a java.sql.Timestamp instance, you would miss setting nanos to 0 which would probably bite you in the ass later.Macaroon
Also, you're making an assumption that leap seconds never affect the millis since the epoch. I think that's true but I'm not sure if it's guaranteed.Macaroon
According to the javadoc for java.sql.Timestamp, getTime() should still return milliseconds. The getNanos() will return nanoseconds.Kalsomine
I doubt this would work on days where we gain or lose an hour due to daylight savings.Insulting
D
4

I prefer this solution:

GregorianCalendar now = new GregorianCalendar();
GregorianCalendar calendar = new GregorianCalendar(
              now.get(GregorianCalendar.YEAR), now.get(GregorianCalendar.MONTH), 
              now.get(GregorianCalendar.DAY_OF_MONTH));
Dunsany answered 19/11, 2012 at 21:57 Comment(0)
T
4

Do this

import org.apache.commons.lang.time.DateUtils;

Date myDate = new Date();
System.out.println(myDate);        
System.out.println(DateUtils.truncate(myDate, Calendar.DATE));

and the output is

Wed Mar 19 14:16:47 PDT 2014
Wed Mar 19 00:00:00 PDT 2014

Trillion answered 19/3, 2014 at 21:21 Comment(0)
D
1

Since I don't do much DateTime manipulation, this might not be the best way to do it. I would spawn a Calendar and use the Date as source. Then set hours, minutes and seconds to 0 and convert back to Date. Would be nice to see a better way, though.

Deictic answered 22/10, 2008 at 18:38 Comment(0)
B
0

Using Calendar.set() would certanly be "by the book" solution, but you might also use java.sql.Date:

java.util.Date originalDate = new java.util.Date();
java.sql.Date wantedDate = new java.sql.Date(originalDate.getTime());

That would do exactly what you want since:

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.

Since java.sql.Date extends java.util.Date, you can freely use it as such. Be aware that wantedDate.getTime() will retrieve original timestamp though - that's why you don't want to create another java.util.Date from java.sql.Date!

Bellona answered 22/10, 2008 at 19:21 Comment(1)
This is pretty dangerous I think. java.sql.Date doesn't work like java.util.Date and still holds the full value. If you try to get the h/m/s from it, it throws IllegalArgumentException. It also inherits java.util.Date equals so won't compare as expected necessarily.Macaroon
M
0

Find below a solution which employs Joda Time and supports time zones. So, you will obtain the current date and time (into currentDate and currentTime) or some date and time you inform (into informedDate and informedTime) in the currently configured timezone in the JVM.

The code below also informs if the informed date/time is in future (variable schedulable).

Please notice that Joda Time does not support leap seconds. So, you can be some 26 or 27 seconds off the true value. This probably will only be solved in the next 50 years, when the accumulated error will be closer to 1 min and people will start to care about it.

See also: https://en.wikipedia.org/wiki/Leap_second

/**
 * This class splits the current date/time (now!) and an informed date/time into their components:
 * <lu>
 *     <li>schedulable: if the informed date/time is in the present (now!) or in future.</li>
 *     <li>informedDate: the date (only) part of the informed date/time</li>
 *     <li>informedTime: the time (only) part of the informed date/time</li>
 *     <li>currentDate: the date (only) part of the current date/time (now!)</li>
 *     <li>currentTime: the time (only) part of the current date/time (now!)</li>
 * </lu>
 */
public class ScheduleDateTime {
    public final boolean schedulable;
    public final long millis;
    public final java.util.Date informedDate;
    public final java.util.Date informedTime;
    public final java.util.Date currentDate;
    public final java.util.Date currentTime;

    public ScheduleDateTime(long millis) {
        final long now = System.currentTimeMillis();
        this.schedulable = (millis > -1L) && (millis >= now);

        final TimeZoneUtils tz = new TimeZoneUtils();

        final java.util.Date          dmillis   = new java.util.Date( (millis > -1L) ? millis : now );
        final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault());
        final java.util.Date          zdmillis  = java.util.Date.from(tz.tzdate(zdtmillis));
        final java.util.Date          ztmillis  = new java.util.Date(tz.tztime(zdtmillis));

        final java.util.Date          dnow   = new java.util.Date(now);
        final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault());
        final java.util.Date          zdnow  = java.util.Date.from(tz.tzdate(zdtnow));
        final java.util.Date          ztnow  = new java.util.Date(tz.tztime(zdtnow));

        this.millis       = millis;
        this.informedDate = zdmillis;
        this.informedTime = ztmillis;
        this.currentDate  = zdnow;
        this.currentTime  = ztnow;
    }
}



public class TimeZoneUtils {

    public java.time.Instant tzdate() {
        final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
        return tzdate(zdtime);
    }
    public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) {
        final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
        final java.time.Instant instant = zddate.toInstant();
        return instant;
    }

    public long tztime() {
        final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
        return tztime(zdtime);
     }
    public long tztime(java.time.ZonedDateTime zdtime) {
        final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
        final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS);
        return millis;
    }
}
Mosstrooper answered 10/7, 2015 at 12:20 Comment(1)
That looks like java.time code, not Joda-Time.Ology
G
0

Here's a simple function with a main example:

import java.util.Calendar;
import java.util.Date;
public class Util {
/**
 * Returns an imprecise date/timestamp. 
 * @param date
 * @return the timestamp with zeroized seconds/milliseconds
 */
public static Date getImpreciseDate(Date date) {
   Calendar cal = Calendar.getInstance(); // get calendar instance
   cal.setTime(date);// set cal to date
   cal.set(Calendar.SECOND, 0); // zeroize seconds 
   cal.set(Calendar.MILLISECOND, 0);   // zeroize milliseconds
   return cal.getTime();
}

public static void main(String[] args){
   Date now = new Date();
   now.setTime(System.currentTimeMillis()); // set time to now
   System.out.println("Precise date:  " + Util.getImpreciseDate(now));
   System.out.println("Imprecise date:  " + Util.getImpreciseDate(now));
}
}
Goatfish answered 18/1, 2017 at 15:22 Comment(0)
B
0

Just trying to put an answer for Java-8 , though answers using Calendar are valid too but lots of folks are not using that class anymore.

Refer SO Answers this & this to understand conversions between java.time.ZonedDateTime & java.sql.Timestamp

then you can simply truncate ZonedDateTime on days & reconvert back to Timestamp

Timestamp.valueOf(ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS).toLocalDateTime())
Beck answered 20/8, 2019 at 13:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.