33

I have a report created in Jasper Reports which ONLY recognizes java.util.Date's (not Calendar or Gregorian, etc).

Is there a way to create a date 7 days prior to the current date?

Ideally, it would look something like this:

new Date(New Date() - 7)

UPDATE: I can't emphasize this enough: JasperReports DOES NOT RECOGNIZE Java Calendar objects.

Ramy
  • 20,541
  • 41
  • 103
  • 153
  • 1
    create calendar, set the date(`Calendar.setTime(Date)`), `Calendar.add(Calendar.DAY_OF_YEAR, -7)`, `Calendar.getTime()`... what's so damn special? or just new Date(d.getTime()-TimeUnit.DAYS.toMillis(7)) – bestsss Feb 04 '11 at 20:39
  • As is being pointed out to me "7 days prior" may be an imprecise spec. For people affected by daylight savings time, if by `7 days prior`, you mean that if right now is `12pm noon on 14 Mar 2010`, you want the calculation of `7 days prior` to result in `12pm on 7 Mar 2010`, then be careful of answers that treat `7 days prior` as exactly 168 hours. The `7 days prior` that you mean is not always `168 hours` around when DST may start or end for you. – Bert F Feb 04 '11 at 23:17

11 Answers11

60

From exactly now:

long DAY_IN_MS = 1000 * 60 * 60 * 24;
new Date(System.currentTimeMillis() - (7 * DAY_IN_MS))

From arbitrary Date date:

new Date(date.getTime() - (7 * DAY_IN_MS))

Edit: As pointed out in the other answers, does not account for daylight savings time, if that's a factor.

Just to clarify that limitation I was talking about:

For people affected by daylight savings time, if by 7 days earlier, you mean that if right now is 12pm noon on 14 Mar 2010, you want the calculation of 7 days earlier to result in 12pm on 7 Mar 2010, then be careful.

This solution finds the date/time exactly 24 hours * 7 days= 168 hours earlier.

However, some people are surprised when this solution finds that, for example, (14 Mar 2010 1:00pm) - 7 * DAY_IN_MS may return a result in(7 Mar 2010 12:00pm) where the wall-clock time in your timezone isn't the same between the 2 date/times (1pm vs 12pm). This is due to daylight savings time starting or ending that night and the "wall-clock time" losing or gaining an hour.

If DST isn't a factor for you or if you really do want (168 hours) exactly (regardless of the shift in wall-clock time), then this solution works fine.

Otherwise, you may need to compensate for when your 7 days earlier doesn't really mean exactly 168 hours (due to DST starting or ending within that timeframe).

Bert F
  • 85,407
  • 12
  • 106
  • 123
  • 1
    actually It Does account for daylight saving. – bestsss Feb 04 '11 at 21:14
  • @bestsss - Not to poke holes in my own answer, but there is 1 day a year that is exactly 1 hour shorter ("Spring Forward") than a standard day and 1 day a year that is 1 hour longer ("Fall Back") than a standard day. In these cases, we'll appear to be 6 days and 23 hours earlier or 7 days and 1 hour earlier than we expected. I've actually been bitten by this problem with this solution. – Bert F Feb 04 '11 at 21:26
  • 1
    @Bert F, that depends on how you look at the time. 7 * DAY_IN_MS is exactly 7 days in millis. If you are looking at the time 7 days ago at a specific timezone, the timezone MUST be specified by in the context. W/o a timezone specified the answer is just fine. The key lays into formatting that millis part and taking a timezone into effect. – bestsss Feb 04 '11 at 21:35
  • 1
    @BenF, if you want to use the default timezone, you can use the deprecated (for this very reason) date methods – bestsss Feb 04 '11 at 21:49
  • 1
    @BenF, dropped an answer regarding the timezone. – bestsss Feb 04 '11 at 22:16
  • System.currentTimeMillis() gives the time in UTC for which there is no daylight savings. I think you are confusing how time is calculated and how it is presented as a String. In UTC time, every day has 24 hours. – Peter Lawrey Feb 04 '11 at 22:34
  • @Peter - yes, but when doing math with these times, there are 2 days that are conceptually shorter or longer than 24 hours, right? For example, if 12pm on the day before daylight savings starts, I tell you I'll see you in 1 day, at what time would you expect to see me the next day? Noon the next day? or exactly 24 hours later at 1pm (since the clock jumps from 2am to 3am that night)? – Bert F Feb 04 '11 at 22:41
  • @Bert F, the days are different in the different timezone and some timezone do not have 'em at all. – bestsss Feb 04 '11 at 22:43
  • In UTC and many other time zones there is no daylight saving and every day is the same length. In some time zones the length of the day is different but that is down to how you locale a date/time. If its 2.30 am the day before daylight saving changes and you say we will meet in 1 days time. Does that mean there is two times of 2.30 (if time goes back) or no times which are 2.30 am (if time goes forward). I would say it is the time which is 24 hours later. – Peter Lawrey Feb 04 '11 at 22:48
  • @bestsss absolutely agreed!!!! Nevertheless, I believe its important to point this non-intuitive ramification of this solution to anyone who may be affected (i.e. where I say "if that's a factor") when an "intuitive" day may not be equal 24 hours so they can consider and ignore-or-compensate as appropriate for them. – Bert F Feb 04 '11 at 22:49
  • @Peter - okay guys - perhaps you think I don't get what you mean - I absolutely do. I just think there's a gotcha here for some people that may apply this solution naively. I'm pointing this out for there benefit. – Bert F Feb 04 '11 at 22:52
  • 1
    @Bert F, totally agree there are gotchas to do with timezones. That's why I try to separate date/time representation and how it is displayed/how a user would expect it to behave. To make matters worse there are regions which don't follow standard time zones. http://www.getitinya.com/wp-content/uploads/2009/04/western_central_time.jpg – Peter Lawrey Feb 04 '11 at 22:59
34

Use Calendar's facility to create new Date objects using getTime():

import java.util.GregorianCalendar;
import java.util.Date;

Calendar cal = new GregorianCalendar();
cal.add(Calendar.DAY_OF_MONTH, -7);
Date sevenDaysAgo = cal.getTime();
Sudheer Aedama
  • 2,116
  • 2
  • 21
  • 39
Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • 3
    The question states that you can't use Calendar. – Dusty Campbell Feb 04 '11 at 20:40
  • 2
    @Dusty: It doesn't specify how the date gets to the report. I made the assumption from the wording that the final result has to be a Date object, but that Calendar can be used in between. – Powerlord Feb 04 '11 at 20:42
  • Ok, cool, I see how it could be read that way. I took it to mean that there is no support for Calendar. I'm working on a GWT project which has similar requirements. – Dusty Campbell Feb 04 '11 at 20:48
  • @Dusty: The other thing is that people suggest using Calendar for various things all over the Jasper Reports forums. Here's an [example](http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=21493) from 2007. – Powerlord Feb 04 '11 at 20:51
14

try

 Date sevenDay = new Date(System.currentTimeMillis() - 7L * 24 * 3600 * 1000));

Another way is to use Calendar but I don't like using it myself.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    Will be buggy on daylight saving dates – Lev Khomich Feb 04 '11 at 20:42
  • 1
    Except if the report is an overnight job between 11 and 1 it will be wrong for a week every year. :) – Affe Feb 04 '11 at 20:42
  • 1
    @Lev Khomich, why do you think it will be buggy on dailight saving? The time returned by System.currentTimeMillis **has NO** dailight saving properties, thus it's not affected – bestsss Feb 04 '11 at 21:17
  • 1
    @bestsss, After conversation "02.11.2010 08:00" will be "26.10.2010 09:00" (in my region) but workday starts at 08:00 for both of this days – Lev Khomich Feb 04 '11 at 21:33
  • 1
    @Lev Khomich - "in your region", taking into account YOUR timezone, it does depend on some timezone which is not specified in the question. Using the default timezone `Calendar.getInstance()` can be just wrong (or worse) as using a designated timezone as UTC. Using the defulat timezone is one of the very bad source of errors and mishandling of the 'time' in java. – bestsss Feb 04 '11 at 21:37
  • 1
    @bestsss, I wrote "in my region" in case I specified concrete date. Same thing happens in any region with daylight savings. A agree at all, but in this case f('02.11.2010 08:00') must be '26.10.2010 08:00' because we need 7 DAYS before, not 7 * 24 HOURS – Lev Khomich Feb 04 '11 at 21:49
  • 1
    @Lev, you have designated timezone, a java.util.Date has none (you can argue that Date can be subclassed and `getTimezoneOffset()` implemented accordingly but that's beyond the point). That's the point. Again if you want to use the default timezone and dont want to be any custom, you can go w/ the deprecated date methods like `setDate/getDate`. Many computers (servers) might have just an UTC timezone (or whatever) and that would be even worse from a user point of view. – bestsss Feb 04 '11 at 21:56
  • Yes, that's point, and because of this if we will want to list all reports for past 7 WORKdays, we will lose some. No offence, just different cases and different implementations. – Lev Khomich Feb 04 '11 at 22:01
  • @Lev, The question doesn't ask for seven working days, that would be completely different as you would have to count holidays and no library I know of handles regional holidays. Note: holidays can be different in regions which share the same time zone. – Peter Lawrey Feb 04 '11 at 22:32
  • @Peter Lawrey, I dont think holidays can be counted/determined by locale and any library since they can altered dynamically (government decisions, Day of Mourning and what not) – bestsss Feb 04 '11 at 22:48
  • @bestsss, which is why I doubt any library supports holidays correctly for working day calculations (though it should be possible to have support for it) – Peter Lawrey Feb 05 '11 at 11:31
12

Since no one has mentioned TimeUnit yet:

new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7))
Daniel
  • 6,194
  • 7
  • 33
  • 59
8

Java 8 based solution:

new Date(
     Instant.now().minus(7, ChronoUnit.DAYS)
     .toEpochMilli()
)
5

Try this:

Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, -7);
return c.getTime();
Jeffrey Hantin
  • 35,734
  • 7
  • 75
  • 94
  • The add method returns void, which reference will it use? – Gilberto Aug 13 '14 at 12:10
  • @Petter, I'm not sure where I got the notion `Calendar#add` was fluent, but I think it's because I've been hanging around .Net too much. Both `Calendar#AddDays` and `DateTime#AddDays` are fluent there. – Jeffrey Hantin Jan 29 '16 at 02:22
4

A determining "days" requires a time zone. A time zone defines when a "day" begins. A time zone includes rules for handling Daylight Saving Time and other anomalies. There is no magic to make time zones irrelevant. If you ignore the issue, the JVM's default time zone will be applied. This tends to lead to confusion and pain.

Avoid java.util.Date

The java.util.Date and .Calendar classes are notoriously troublesome. Avoid them. They are so bad that Sun/Oracle agreed to supplant them with the new java.time package in Java 8. Use either that or Joda-Time.

Joda-Time

Example code in Joda-Time 2.3.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); // Specify or else the JVM's default will apply.
DateTime dateTime = new DateTime( new java.util.Date(), timeZone ); // Simulate passing a Date.
DateTime weekAgo = dateTime.minusDays( 7 );

First Moment Of Day

Or, you may want to adjust the time-of-day to the first moment of the day so as to capture an entire day's worth of time. Call the method withTimeAtStartOfDay. Keep in mind this is usually 00:00:00 but not always.

Avoid the "midnight" methods and classes in Joda-Time. They are based on a faulty concept and are now deprecated.

DateTime dateTimeStart = new DateTime( new java.util.Date(), timeZone ).withTimeAtStartOfDay(); // Not necessarily the time "00:00:00".
DateTime weekAgo = dateTime.minusDays( 7 ).withTimeAtStartOfDay(); 

Convert To/From j.u.Date

As seen above, to convert from java.util.Date to Joda-Time merely pass the Date object to constructor of DateTime. Understand that a j.u.Date has no time zone, a DateTime does. So assign the desired/appropriate time zone for deciding what "days" are and when they start.

To go the other way, DateTime to j.u.Date, simply call the toDate method.

java.util.Date date = dateTime.toDate();
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Funnily, in the Joda-Time example, `java.util.Date` is used... :p – Stephan May 15 '15 at 12:29
  • @Stephan Not really so funny. The Question says a `java.util.Date` is specifically required for use with the *JasperReports* library. Many such libraries work only with j.u.Date. So quite commonly we do the bulk of the work in Joda-Time (or java.time) and then at the end convert to a j.u.Date. Both Joda-Time and java.time offer convenience methods for converting back and forth. Like using an electrical power adapter. Over the years, hopefully we will see use of j.u.Date fade as libraries switch to [java.time](http://docs.oracle.com/javase/tutorial/datetime/index.html). – Basil Bourque May 16 '15 at 00:10
  • I'm not sure that JodaTime/JSR310 is required, here: all of this can be done with `java.util.Calendar` relatively easily. Yes, the interface for JodaTime/JSR310 is much nicer, but it will either require JodaTime or Java 8 as a prerequisite for your application, which might not be possible. – Christopher Schultz Nov 04 '15 at 15:05
  • @ChristopherSchultz [A] Many of us consider Joda-Time to be a requirement for any Java 5/6/7 project. The old date-time classes really are that bad. [B] Java 7 and earlier is now end-of-life'd by Oracle unless you purchase an extended support contract. So Java 8 or later, with its built-in *java.time* framework, is now a practical requirement for most of us. – Basil Bourque Nov 04 '15 at 15:54
3

I'm not sure when they added these, but JasperReports has their own set of "functions" that can manipulate dates. Here is an example that I haven't tested thoroughly:

DATE(YEAR(TODAY()), MONTH(TODAY()), DAY(TODAY()) - 7)

That builds a java.util.Date with the date set to 7 days from today. If you want to use a different "anchor" date, just replace TODAY() with whatever date you want to use.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
1

You can try this,

    Calendar c = Calendar.getInstance();
    c.add(Calendar.DAY_OF_MONTH, -7);
    System.out.println(new java.sql.Date(c.getTimeInMillis()));
emon
  • 1,629
  • 1
  • 17
  • 18
0

I'm doing it this way :

Date oneWeekAgo = DateUtils.addDays(DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH), -7);
Ellone
  • 3,644
  • 12
  • 40
  • 72
0

Due to the heated discussion:

The question may not have a proper answer w/o a designated timezone.

below it is some code to work w/ the default (and hence deprecated) timezone that takes into account the default timezone daylight saving.

Date date= new Date();
date.setDate(date.getDate()-7);//date works as calendar w/ negatives

While the solution does work, it is exactly as bogus as in terms of assuming the timezone.

new Date(System.currentTimeMillis() - 10080*60000);//a week has 10080 minutes

Please, don't vote for the answer.

bestsss
  • 11,796
  • 3
  • 53
  • 63
  • True, time zone is critical to handle Daylight Saving Time and other anomalies. One reason why using Joda-Time or java.time is so important rather than java.util.Date. – Basil Bourque Jun 21 '14 at 01:44
  • @BasilBourque, personally I have never needed joda. j.u.Date, itself, is quite a useless class but j.u.Calendar works fine - albeit a bit weird but I am well used to using it since 1999... – bestsss Jun 21 '14 at 23:06
  • 1
    The javadoc says that the parameter for `setDate` should be an integer from 1-31 (inclusive) and does not define any particular behavior for negative numbers. Just because this works in one JVM/version does not guarantee it will work elsewhere. The example with the milliseconds is more reliable if you want to use either of these two. – Christopher Schultz Nov 04 '15 at 15:01