Java - Unexpected result from Calendar.set(HOUR_OF_DAY) [duplicate] - java

This question already has answers here:
How to set time zone of a java.util.Date?
(12 answers)
Closed 5 years ago.
JVM version is 1.7. Timezone is GMT+3, offset 180 minutes. 1500411600000 corresponds to 7/19/2017, 12:00:00 AM (I've verified this online).
I'm executing the following code to adjust time of a Date instance:
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Date date = new Date(1500411600000L);
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
date = calendar.getTime();
I expect date to become 7/19/2017, 11:59:59 PM but instead of this I get 7/19/2017, 2:59:59 AM. 3 hours difference - exactly as much as my timezone is different from UTC/GMT, so I suppose that some unnoticed conversion happens here.
Can you please help me to find timezone agnostic code for adjusting time in date?

You are correct that at offset UTC+3 your millisecond value, 1500411600000, corresponds to July 19, 2017 at midnight (start of day). At other offsets it corresponds to other times of day either July 18 or 19.
java.time
Assuming that it is no coincidence that you have got midnight in your own time zone, that the value is really supposed to represent a date, not a time, I recommend you use LocalDate from java.time to represent it:
ZoneId yourTimeZone = ZoneId.of("Europe/Riga");
LocalDate date = Instant.ofEpochMilli(1500411600000L)
.atZone(yourTimeZone)
.toLocalDate();
System.out.println(date);
This prints the expected
2017-07-19
Please either substitute your correct time zone in case it doesn’t happen to be Europe/Riga, or use a ZoneOffset instead: .atOffset(ZoneOffset.ofHoursMinutes(3, 0)) (the other lines are the same).
I suspect you don’t really want the end of the day even though in your question you are trying to set it. If this is for determining whether some point in time is before the end of the day, compare it to the start of the following day and require that it is strictly before. This saves you the trouble with the odd-looking minutes, seconds and fractions of second.
ZonedDateTime startOfNextDay = date.plusDays(1).atStartOfDay(yourTimeZone);
java.time came out in 2014 as a replacement for both the poorly designed date and time classes from Java 1.0 and 1.1 and for Joda-Time, from which much inspiration was drawn. I warmly recommend you use it.
What you tried in the question
I believe your code from the question is also clearer when expressed with java.time:
OffsetDateTime endOfDay = Instant.ofEpochMilli(1500411600000L)
.atOffset(ZoneOffset.UTC)
.with(LocalTime.MAX);
System.out.println(endOfDay);
This prints
2017-07-18T23:59:59.999999999Z
(July 18 at the end of day in UTC; Z at the end denotes UTC). Except for the number of decimals, this is also the result you got. You may have been fooled by the fact that your Date instance is printed something like Wed Jul 19 02:59:59 EEST 2017 (the time zone abbreviation depending on your JVM’s time zone setting). Date.toString() grabs your JVM’s time zone setting and converts the date-time to this time zone for the generated string only; the Date instance itself is not modified and only holds a point on the time line, no time zone.
Question: can I use java.time with my Java version?
Yes you can. You just need to use at least Java 6.
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310).
On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP, and there’s a thorough explanation in this question: How to use ThreeTenABP in Android Project.
For learning to use java.time, see the Oracle tutorial or find other resoureces on the net.

You're using Calendar.getInstance(TimeZone.getTimeZone("UTC")), but you have to use the timezone you're in. As you stated GMT+3

Please refer to this thread here which explains the issue regarding Date and timezones.
How to set time zone of a java.util.Date?
The Date object will have the correct adjusted time but when it is displayed, the output will use your local timezone. You can forcefully set the timezone of your JVM using the following code but this may have unintended consequences in other parts of your code.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
In an ideal world you would use the Java 8 date classes or Joda time library classes both of which provide some simple date manipulation methods.
Java 8 date classes

Use clear. It seems a historical "bug" to me, a time zoned Calendar, where setTime does not alter the zone.
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Date date = new Date(1500411600000L);
calendar.clear(); // To reset _all_ fields, incl. the time zone offset ZONE_OFFSET.
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
date = calendar.getTime();
Of course this might be the right argument to switch to the new java time API.

The problem is bigger than described in my question. It stems from incorrect managing Date/Time for user's timezone. In my application timestamp was sent in user's timezone and then evaluated to date in server's timezone, but timezone difference was not taken into account. I tried to fix this and faced the issue described in the question.
I listened to the #ThomasEdwin's advice to use Joda Time and I'm happy to share this solution:
long userTimezoneOffset = 180; // it's a parameter submitted by client app
Date date = new Date(1500411600000L); // it's another parameter submitted by client app
final DateTimeZone zone = DateTimeZone.forOffsetMillis((int) TimeUnit.MINUTES.toMillis(userTimezoneOffset));
final DateTimeZone serverZone = DateTimeZone.getDefault();
MutableDateTime dateTime = new MutableDateTime(date, zone);
dateTime.setHourOfDay(23);
dateTime.setMinuteOfHour(59);
dateTime.setSecondOfMinute(59);
dateTime.setMillisOfSecond(999);
dateTime.setZoneRetainFields(serverZone);
date = dateTime.toDate();
// now date.toString() returns expected result
Also I found -Duser.timezone JVM parameter to be quite useful when debugging this issue. See here for a list of supported timezone IDs.

Related

Cannot Convert Date '0001-01-01' from Java to C# correctly

I try to provide a tool to convert datetime from Java to C#. But there is a serious problem.
In Java, I read '0001-01-01' from the SQL Server database via java.sql.Date, and get the millisecond -62135798400000.
I also consider the timezone offset.
private static long getMilliSecondWithoutTimeZone(long origin) {
return origin + (ZonedDateTime.now().getOffset().getLong(OFFSET_SECONDS) * 1000);
}
And the final millisecond is -62135769600000.
In C#, I use this millisecond to new Datetime
var ticks = new DateTime(1970, 1, 1).Ticks + (-62135769600000 * 10000);
var date = new DateTime(ticks);
When the code runs, it will throw the exception:
System.ArgumentOutOfRangeException: 'Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. (Parameter 'ticks')'
However, the conversion is correct after '1600-01-01' according to my test.
Before '1600-01-01', there always is a few days of error.
It makes me very confused.
I find the remarks in https://learn.microsoft.com/en-us/dotnet/api/system.globalization.juliancalendar?view=net-5.0#remarks
The Gregorian calendar was developed as a replacement for the Julian calendar (which is represented by the JulianCalendar class) and was first introduced in a small number of cultures on October 15, 1582. When working with historic dates that precede a culture's adoption of the Gregorian calendar, you should use the original calendar if it is available in the .NET Framework. For example, Denmark changed from the Julian calendar to the Gregorian calendar on February 19 (in the Julian calendar) or March 1 (in the Gregorian calendar) of 1700. In this case, for dates before the adoption of the Gregorian calendar, you should use the Julian calendar. However, note that no culture offers intrinsic support for the JulianCalendar class. You must use the JulianCalendar class as a standalone calendar. For more information, see Working with calendars.
The actual reason is:
C# uses the Gregorian calendar all the time.
Java uses the Gregorian calendar after October 15, 1582, and uses the Julian calendar before.
The solution:
import java.sql.Date;
import java.time.chrono.IsoChronology;
import java.time.*;
public class Test {
public static Long getMilliSeconds(Date date) {
if (null == date) {
return null;
}
IsoChronology ISO = IsoChronology.INSTANCE;
LocalDate ld = date.toLocalDate();
return ISO.localDateTime(LocalDateTime.of(ld.getYear(), ld.getMonth(), ld.getDayOfMonth(), 0, 0, 0)).toInstant(ZoneOffset.UTC).toEpochMilli();
}
}
It seems like the millisecond value that you mention, -62_135_798_400_000, comes out of an old-fashioned java.sql.Date object created in a timezone that is assumed to be at UTC offset +08:00 back then, perhaps just Etc/GMT-8. With this assumption, the value is historically correct since it was the Julian calendar that was used back then, and Date does use that.
I don’t know the .NET classes that C# uses, but I consider it a likely that a few days error are caused by them using the proleptic Gregorian calendar, that is, pretending that the Gregorian calendar was used in all past even though it didn’t come into existence before 1582. The modern Java date and time API does this and therefore gives you millisecond values that usually differ by a few days.
long milliseconds = LocalDate.of(1, 1, 1)
.atStartOfDay(ZoneOffset.ofHours(8))
.toInstant()
.toEpochMilli();
System.out.format(Locale.ENGLISH, "%,d%n", milliseconds);
Output:
-62,135,625,600,000
It is 48 hours — or 2 days — later than the time you mentioned. See if it solves your issue.
Link
Oracle tutorial: Date Time explaining how to use java.time.
You forgot to account for time zone offset.
If we set the time zone to UTC, you'll see this:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println(new Date(-62135798400000L));
Output
Fri Dec 31 16:00:00 UTC 1
It is actually year 1 BC, not year 1 AD.
The time 16:00 indicates a time zone offset of 8 hours, so if we change to GMT+8 we get:
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
System.out.println(new Date(-62135798400000L));
Output
Sat Jan 01 00:00:00 GMT+08:00 1
That is correctly year 1 AD.
Which means that you need to adjust the millisecond value by 8 hours, aka 28800000 milliseconds.
For the date 0001-01-01 00:00 UTC, the correct value for milliseconds is -62135769600000. Anything less than that will be rejected by the C# DateTime class.

TimeStamp.valueOf() method

public static void main(String[] args) {
Timestamp ts = new Timestamp(116, 02, 12, 20, 45, 0, 0);
Date d = new Date();
d.setTime(ts.getTime());
System.out.println(d);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//System.out.println(ts.getTime());
System.out.println(simpleDateFormat.format(ts));
System.out.println(Timestamp.valueOf(simpleDateFormat.format(ts)));
}
In above code last two lines print different values. Current time zone is CST, I wanted to convert it into UTC. When I convert it Last two lines print different values by one hour i.e., last but one print 13 mar 2:45 am and last print 13 Mar 3:45 am. Why they are different and How can I correct it.
Java 8
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
System.out.println(inst);
This prints
2016-03-13T02:45:00Z
Today you should not (normally) have a need for a Timestamp object. The java.sql.Timestamp class is long outdated. Once we used it for transferring timestamp values with nanosecond precision to and from SQL databases. Today we use the Instant class for this instead. Instant is one of the classes of java.time, the modern Java date and time API (sometimes we use LocalDateTime from the same API, it depends on your exact requirements and the datatype of your database column).
Neither a Timestamp nor an Instant have a time zone in them. Unlike Timestamp the Instant always prints in UTC (denoted by the Z at the end of the above output). As you can see, the above snippet has correctly converted your time of 20:45 CST to 02:45 the next day UTC.
If you do need a timestamp, typically for a legacy API that you cannot change or don’t want to change just now, conversion is easy:
Timestamp ts = Timestamp.from(inst);
System.out.println(ts);
2016-03-12 20:45:00.0
Timestamp.toString uses the JVM’s time zone setting for generating the string, so you recognize the time we started out from. So the Timestamp contains the correct point in time. There is no need to convert it in any way. If it gets inserted incorrectly into your database, the problem is with your JDBC driver, your database or somewhere else, and you should prefer to correct it there if you can.
Java 6 and 7
Code very similar to the above will work in Java 7 if you add ThreeTen Backport to your project. This is the backport of the java.time classes to Java 6 and 7, and I include a link at the bottom (it’s ThreeTen for JSR-310, where the modern API was first described).
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
Timestamp ts = DateTimeUtils.toSqlTimestamp(inst);
You notice that the only difference from Java 8 is the way we convert the Instant to a Timestamp. The result is the same, of course.
I you don’t want a dependency on ThreeTen Backport, there are of course still ways to obtain a Timestamp. I wouldn’t use the deprecated constructor, as you do in your code, even though it works as long as no one tampers with your JVM’s time zone setting. If you know you want a Timestamp equal to 02:45 UTC, one option is
Timestamp ts = Timestamp.valueOf("2016-03-12 20:45:00");
It still depends on your JVM’s time zone setting, though.
What went wrong in your code?
As mentioned a Timestamp hasn’t got a time zone in it, so converting a Timestamp to UTC does not make sense.
What happens in your code:
The deprecated Timestamp constructor uses your JVM’s time zone setting (America/Chicago, I presume) for constructing a Timestamp corresponding 12 March 2016 at 8.45 PM in your time zone (the same point in time as 13 March 2:45 AM UTC).
Your SimpleDateFormat correctly formats this into 2016-03-13 02:45:00 (UTC).
Timestamp.valueOf() too uses America/Chicago time zone. However, on the night between 12 and 13 March summer time (daylight saving time) begins in this time zone. At 2 AM the clock is moved forward to 3. So there is no 2:45 this night. Timestamp picks 3:45 instead.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7.
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

Jboss Java Date daylight saving time

Have an issue where, when clocks are moved due to a Daylight savings time (twice a year), dates are not correct in Java (I am based in Central Europe: GMT+2 in summer, GMT+1 in winter)
If time is moved 1 hour ahead, new Date() still returns old time (1 hour behind of current time).
In Java 7, can this be solved, without restarting the Jboss application servers?
If I change the time manually in Windows, reproduce the problem: Date is not updated to the system date unless jboss is restarted.
Calendar c = Calendar.getInstance();
c.setTime(new Date());
In Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes.
With this, you can handle DST changes easily.
First, you can use the org.threeten.bp.DateTimeUtils to convert from and to Calendar.
The following code converts the Calendar to org.threeten.bp.Instant, which is a class that represents an "UTC instant" (a timestamp independent of timezone: right now, at this moment, everybody in the world are in the same instant, although their local date and time might be different, depending on where they are).
Then, the Instant is converted to a org.threeten.bp.ZonedDateTime (which means: at this instant, what is the date and time at this timezone?). I also used the org.threeten.bp.ZoneId to get the timezone:
Calendar c = Calendar.getInstance();
c.setTime(new Date());
// get the current instant in UTC timestamp
Instant now = DateTimeUtils.toInstant(c);
// convert to some timezone
ZonedDateTime z = now.atZone(ZoneId.of("Europe/Berlin"));
// today is 08/06/2017, so Berlin is in DST (GMT+2)
System.out.println(z); // 2017-06-08T14:11:58.608+02:00[Europe/Berlin]
// testing with a date in January (not in DST, GMT+1)
System.out.println(z.withMonth(1)); // 2017-01-08T14:11:58.608+01:00[Europe/Berlin]
I've just picked some timezone that uses Central Europe timezone (Europe/Berlin): you can't use those 3-letter abbreviations, because they are ambiguous and not standard. You can change the code to the timezone that suits best for your system (you can get a list of all available timezones with ZoneId.getAvailableZoneIds()).
I prefer this solution because it's explicit what timezone we're using to display to the user (Date and Calendar's toString() methods use the default timezone behind the scenes and you never know what they're doing).
And internally, we can keep using the Instant, which is in UTC, so it's not affected by timezones (and you can always convert to and from timezones whenever you need) - if you want to convert the ZonedDateTime back to an Instant, just use the toInstant() method.
Actually, if you want to get the current date/time, just forget the old classes (Date and Calendar) and use just the Instant:
// get the current instant in UTC timestamp
Instant now = Instant.now();
But if you still need to use the old classes, just use DateTimeUtils to do the conversions.
The output of the examples above are the result of the ZonedDateTime.toString() method. If you want to change the format, use the org.threeten.bp.format.DateTimeFormatter class (take a look at the javadoc for more details about all the possible formats):
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss z X");
// DST (GMT+02)
System.out.println(formatter.format(z)); // 08/06/2017 14:11:58 CEST +02
// not DST (GMT+01)
System.out.println(formatter.format(z.withMonth(1))); // 08/01/2017 14:11:58 CET +01
Use ZonedDateTime class from JDK 8 java.time. It accommodates the Daylight Saving Time changes.
Refer the details at : https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html

Converting String to time, changing the timezone, then back to String

I have a String containing a time in the format: 08:00:00
This time is from US Eastern time and I want to convert it to London's timezone and end up with a String of that time.
I have converted the String to time using
Time.valueOf(t);
However after this I cannot get the timezone to change.
you can displace the time using withZoneSameInstant
LocalTime myLocalTime = LocalTime.parse("08:00:00", DateTimeFormatter.ofPattern("HH:mm:ss"));
LocalTime londonTime = LocalDateTime.of(LocalDate.now(), myLocalTime).atZone(ZoneId.of("America/New_York"))
.withZoneSameInstant(ZoneId.of("Europe/London")).toLocalTime();
System.out.println(myLocalTime);
System.out.println(londonTime);
There are lots of details regarding this question.
The Time class sets the date (day, month and year) to January 1st, 1970. But to convert from EST to London local time, you must consider Daylight Saving Time rules.
The difference in hours is not always the same; it can change depending on the date - considering this year (2017): from January 1st to March 11th, the difference will be 5 hours, then from March 12th to March 25th the difference is 4 hours, then it's back to 5 hours, then in October 29th it's 4 hours and in November 5th is 5 hours again, until the end of the year.
That's because of DST starting and ending in both timezones and at different dates. And each year, these dates change as well, so you need to know the date you're working with, to make the correct conversion.
Another thing is that Java 8 new API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or EST) because they are ambiguous and not standard.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
In the example below I'm using America/New_York - one of the many timezones that uses EST (there are more than 30 timezones that uses or had used it). You can call ZoneId.getAvailableZoneIds() to check all the timezones and choose one that suits best for your case.
The code is very similar to #ΦXocę 웃 Пepeúpa ツ answer, well, because it's straightforward and there's not much to change. I just wanted to add the insights above.
// timezones for US and UK
ZoneId us = ZoneId.of("America/New_York");
ZoneId uk = ZoneId.of("Europe/London");
// parse the time string
LocalTime localTimeUS = LocalTime.parse("08:00:00");
// the reference date (now is the current date)
LocalDate now = LocalDate.now(); // or LocalDate.of(2017, 5, 20) or any date you want
// the date and time in US timezone
ZonedDateTime usDateTime = ZonedDateTime.of(now, localTimeUS, us);
// converting to UK timezone
ZonedDateTime ukDateTime = usDateTime.withZoneSameInstant(uk);
// get UK local time
LocalTime localTimeUK = ukDateTime.toLocalTime();
System.out.println(localTimeUK);
The output will be 13:00 (the result of localTimeUK.toString()) because toString() omits the seconds if the value is zero.
If you want to always output the seconds, you can use a DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
String time = fmt.format(localTimeUK);
In this case, the string time will be 13:00:00.
LocalDate.now() returns the current date using your system's default timezone. If you want the current date in a specific zone, you could've called LocalDate.now(us) (or anyzone you want, or even explicit use the default: LocalDate.now(ZoneId.systemDefault()))

java.util.Date: seven days ago

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.
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).
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();
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.
Since no one has mentioned TimeUnit yet:
new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7))
Java 8 based solution:
new Date(
Instant.now().minus(7, ChronoUnit.DAYS)
.toEpochMilli()
)
Try this:
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, -7);
return c.getTime();
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();
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.
You can try this,
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, -7);
System.out.println(new java.sql.Date(c.getTimeInMillis()));
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.
I'm doing it this way :
Date oneWeekAgo = DateUtils.addDays(DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH), -7);

Categories

Resources