Reputation: 177
Is there any fast way to create DateTime instance and set minutes\seconds\millis to 0? At this moment I am using the following code:
private DateTime createDateTime(java.util.Date date, org.joda.time.Chronology chronology) {
DateTime dateTime = new DateTime(date, chronology);
dateTime = dateTime.withMinuteOfHour(0);
dateTime = dateTime.withSecondOfMinute(0);
dateTime = dateTime.withMillisOfSecond(0);
return dateTime;
}
But when it invokes about 200.000 times, dateTime.with***(0); takes a lot of time. Probably there is more correct solution?
Upvotes: 7
Views: 3184
Reputation: 220842
Maybe like this?
// Truncate minutes/seconds/milliseconds from the date's timestamp
long truncatedTimestamp = date.getTime() - date.getTime() % 3600000;
DateTime dateTime = new DateTime(truncatedTimestamp, chronology);
Why is this faster?
DateTime
constructorDateTime
constructor and 3 more normalisations (expensive), every time you set some date part to 0
Hence, you probably can't beat modulo. As others pointed out, this might lead to incorrect results in very remote corner-cases where hours don't count 60 seconds (e.g. due to leap seconds), although I fail to see how, as the unix timestamp can always be truncated to zero, to get the beginning of a calendar hour (examples welcome).
Upvotes: 8
Reputation: 63385
The method dateTime.hourOfDay().roundFloorCopy()
should round the minute, second and milli to zero in a single method call (and is the recommended way if performance is not an issue). However, it is unlikely to be faster than calling modulo on the millis directly.
Upvotes: 3
Reputation: 328598
Just tried the code below - it looks like method 1 (yours) takes about 320ms on my pc, vs method 2 (mine) 390ms, vs method 3 (Lukas's) 15ms, vs method 4 (MutableDateTime) 310ms... Now the modulo might (?) lead to incorrect results.
public class Test {
private static int NUM_RUN;
public static void main(String[] args) {
Date date = new Date();
List<Runnable> list = new ArrayList<>();
list.add(method3Withs(date));
list.add(method1With(date));
list.add(methodModulo(date));
list.add(methodMutable(date));
NUM_RUN = 100_000;
for (Runnable r : list) {
long start = System.nanoTime();
r.run();
long end = System.nanoTime();
System.out.println((end - start) / 1000000);
}
NUM_RUN = 10_000_000;
for (Runnable r : list) {
long start = System.nanoTime();
r.run();
long end = System.nanoTime();
System.out.println((end - start) / 1000000);
}
}
private static Runnable method3Withs(final Date date) {
return new Runnable() {
@Override
public void run() {
DateTime d2 = null;
for (int i = 0; i < NUM_RUN; i++) {
d2 = new DateTime(date);
d2 = d2.withMinuteOfHour(0);
d2 = d2.withSecondOfMinute(0);
d2 = d2.withMillisOfSecond(0);
}
System.out.println(d2);
}
};
}
private static Runnable method1With(final Date date) {
return new Runnable() {
@Override
public void run() {
DateTime d2 = null;
for (int i = 0; i < NUM_RUN; i++) {
d2 = new DateTime(date);
d2 = d2.withTime(d2.getHourOfDay(), 0, 0, 0);
}
System.out.println(d2);
}
};
}
private static Runnable methodModulo(final Date date) {
return new Runnable() {
@Override
public void run() {
DateTime d2 = null;
for (int i = 0; i < NUM_RUN; i++) {
long truncatedTimestamp = date.getTime() - date.getTime() % 3600000;
d2 = new DateTime(truncatedTimestamp);
}
System.out.println(d2);
}
};
}
private static Runnable methodMutable(final Date date) {
return new Runnable() {
@Override
public void run() {
MutableDateTime m = null;
for (int i = 0; i < NUM_RUN; i++) {
m = new MutableDateTime(date);
m.setMinuteOfHour(0);
m.setSecondOfMinute(0);
m.setMillisOfSecond(0);
}
System.out.println(m);
}
};
}
}
EDIT
I made it 10 million runs after a warm up round of 100,000:
3037
4068
88
2864
The modulo method wins by a large margin, so it seems safe to think it will perform much better in most situations.
Upvotes: 5
Reputation: 206806
How about using the withTime()
method of class DateTime
, so that you only have to do one call?
private DateTime createDateTime(java.util.Date date, org.joda.time.Chronology chronology) {
DateTime dateTime = new DateTime(date, chronology);
return dateTime.withTime(dateTime.getHourOfDay(), 0, 0, 0);
}
Upvotes: 1
Reputation: 32407
Try creating a MutableDateTime
: http://joda-time.sourceforge.net/userguide.html#Using_a_MutableDateTime, then call toDateTime()
on it
Upvotes: 3