How to subtract X days from a date using Java calendar?
Asked Answered
D

11

202

Anyone know a simple way using Java calendar to subtract X days from a date?

I have not been able to find any function which allows me to directly subtract X days from a date in Java. Can someone point me to the right direction?

Dulcedulcea answered 17/10, 2008 at 14:14 Comment(1)
FYI, the troublesome old date-time classes such as java.util.Calendar are now legacy, supplanted by the java.time classes. See Tutorial by Oracle.Retinol
C
344

Taken from the docs here:

Adds or subtracts the specified amount of time to the given calendar field, based on the calendar's rules. For example, to subtract 5 days from the current time of the calendar, you can achieve it by calling:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).
Cordes answered 17/10, 2008 at 14:17 Comment(8)
Just be careful doing this since it doesn't always roll like you expect it to.Redmon
This answers has many upvotes, but is it safe to use? or this is better: https://mcmap.net/q/121576/-how-to-subtract-n-days-from-current-date-in-java-duplicateLammond
You would not use Calendar.DAY_OF_MONTH in this case since it will not handle the roll between months as you would like to. Use Calendar.DAY_OF_YEAR insteadWilkerson
This should be safe, apparently when you're adding it doesn't matter if it's DAY_OF_MONTH or DAY_OF_YEAR https://mcmap.net/q/121577/-what-39-s-the-difference-between-adding-day_of_month-or-day_of_year-to-a-calendar-object/32453Subtrahend
@Redmon what are some of the problems with this approach?Shaylynn
FYI, the troublesome old date-time classes such as java.util.Calendar are now legacy, supplanted by the java.time classes. See Tutorial by Oracle.Retinol
The best way to avoid the issues with Calendar. DAY_OF_MONTH and other day formats is to subtract by number of hours. Using calendar.add(Calendar.HOUR, -5*24) for subtracting 5 days will work regardless of any crossover between years/months/weeks.Amalee
I don't know why this has so many upvotes because it does not give me the correct result when I test it:Xenophobia
P
38

You could use the add method and pass it a negative number. However, you could also write a simpler method that doesn't use the Calendar class such as the following

public static void addDays(Date d, int days)
{
    d.setTime( d.getTime() + (long)days*1000*60*60*24 );
}

This gets the timestamp value of the date (milliseconds since the epoch) and adds the proper number of milliseconds. You could pass a negative integer for the days parameter to do subtraction. This would be simpler than the "proper" calendar solution:

public static void addDays(Date d, int days)
{
    Calendar c = Calendar.getInstance();
    c.setTime(d);
    c.add(Calendar.DATE, days);
    d.setTime( c.getTime().getTime() );
}

Note that both of these solutions change the Date object passed as a parameter rather than returning a completely new Date. Either function could be easily changed to do it the other way if desired.

Palikar answered 17/10, 2008 at 14:22 Comment(4)
Don't believe .setTime and .add are static methods of Calendar. You should be using the instance variable c.Jecho
@Edward: you are correct, thanks for pointing out my mistake, I've fixed the code so that it should now work properly.Palikar
Be careful with the first way, for instance when dealing with leapyear days it may fail: https://mcmap.net/q/67953/-how-to-add-one-day-to-a-date-duplicateSubtrahend
FYI, the troublesome old date-time classes such as java.util.Calendar are now legacy, supplanted by the java.time classes. See Tutorial by Oracle.Retinol
A
36

Anson's answer will work fine for the simple case, but if you're going to do any more complex date calculations I'd recommend checking out Joda Time. It will make your life much easier.

FYI in Joda Time you could do

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);
Alight answered 17/10, 2008 at 14:24 Comment(3)
@ShahzadImam, check out DateTimeFormat. It will allow you to convert DateTime instances to strings using arbitrary formats. It's very similar to the java.text.DateFormat class.Alight
As of Java 8 consider using java.time docs.oracle.com/javase/8/docs/api/java/time/…Jorin
FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. See Tutorial by Oracle.Retinol
R
24

tl;dr

LocalDate.now().minusDays( 10 )

Better to specify time zone.

LocalDate.now( ZoneId.of( "America/Montreal" ) ).minusDays( 10 )

Details

The old date-time classes bundled with early versions of Java, such as java.util.Date/.Calendar, have proven to be troublesome, confusing, and flawed. Avoid them.

java.time

Java 8 and later supplants those old classes with the new java.time framework. See Tutorial. Defined by JSR 310, inspired by Joda-Time, and extended by theThreeTen-Extra project. The ThreeTen-Backport project back-ports the classes to Java 6 & 7; the ThreeTenABP project to Android.

The Question is vague, not clear if it asks for a date-only or a date-time.

LocalDate

For a date-only, without time-of-day, use the LocalDate class. Note that a time zone in crucial in determining a date such as "today".

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate tenDaysAgo = today.minusDays( 10 );

ZonedDateTime

If you meant a date-time, then use the Instant class to get a moment on the timeline in UTC. From there, adjust to a time zone to get a ZonedDateTime object.

Instant now = Instant.now();  // UTC.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime tenDaysAgo = zdt.minusDays( 10 );

Table of date-time types in Java, both modern and legacy.


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.

Retinol answered 4/11, 2015 at 19:56 Comment(1)
This is a much better improvement over the other options (it is also much newer and makes use of new methods). If you are visiting this issue now, This is the way to go.Ascham
E
8
int x = -1;
Calendar cal = ...;
cal.add(Calendar.DATE, x);

See java.util.Calendar#add(int,int)

Emmalineemmalyn answered 17/10, 2008 at 14:17 Comment(0)
I
5

Instead of writing my own addDays as suggested by Eli, I would prefer to use DateUtils from Apache. It is handy especially when you have to use it multiple places in your project.

The API says:

addDays(Date date, int amount)

Adds a number of days to a date returning a new object.

Note that it returns a new Date object and does not make changes to the previous one itself.

Impoverished answered 13/8, 2012 at 12:29 Comment(0)
S
4

I faced the same challenge where I needed to go back by 1 day (should be able to roll back by one even if previous day falls into previous year or months).

I did following, basically subtracted by 24 hours for 1 day. someDateInGregorianCalendar.add(Calendar.HOUR, -24);

Alternatively, I could also do

GregorianCalendar cal = new GregorianCalendar();
    cal.set(Calendar.YEAR, 2021);
    cal.set(Calendar.MONTH, 0);
    cal.set(Calendar.DATE, 1);
    System.out.println("Original: " + cal.getTime());
    cal.add(Calendar.DATE, -1);
    System.out.println("After adding DATE: " + cal.getTime());

OUTPUT:

Original: Fri Jan 01 15:08:33 CET 2021
After adding DATE: Thu Dec 31 15:08:33 CET 2020
Savell answered 25/10, 2021 at 12:59 Comment(0)
A
2

It can be done easily by the following

Calendar calendar = Calendar.getInstance();
        // from current time
        long curTimeInMills = new Date().getTime();
        long timeInMills = curTimeInMills - 5 * (24*60*60*1000);    // `enter code here`subtract like 5 days
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

        // from specific time like (08 05 2015)
        calendar.set(Calendar.DAY_OF_MONTH, 8);
        calendar.set(Calendar.MONTH, (5-1));
        calendar.set(Calendar.YEAR, 2015);
        timeInMills = calendar.getTimeInMillis() - 5 * (24*60*60*1000);
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());
Abatis answered 19/12, 2017 at 6:37 Comment(1)
This Answer is ill-advised, using terrible old date-time classes that are now legacy, supplanted by the java.time classes. Also, this code ignores the crucial issue of time zone, naïvely assuming 24-hour days. Another problem is using a date-time class to solve a date-only problem. Using LocalDate is much simpler and more appropriate.Retinol
A
2

I believe a clean and nice way to perform subtraction or addition of any time unit (months, days, hours, minutes, seconds, ...) can be achieved using the java.time.Instant class.

Example for subtracting 5 days from the current time and getting the result as Date:

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

Another example for subtracting 1 hour and adding 15 minutes:

Date.from(Instant.now().minus(Duration.ofHours(1)).plus(Duration.ofMinutes(15)));

If you need more accuracy, Instance measures up to nanoseconds. Methods manipulating nanosecond part:

minusNano()
plusNano()
getNano()

Also, keep in mind, that Date is not as accurate as Instant. My advice is to stay within the Instant class, when possible.

Amabel answered 9/12, 2019 at 13:11 Comment(2)
Or depending on taste, a bit shorter: Date.from(Instant.now().minus(5, ChronoUnit.DAYS))Bridgers
Nice! You are right. I actually updated the answer to use this this and also show a usage of java.time.Duration class, which in this case is also very potent.Amabel
H
1

Someone recommended Joda Time so - I have been using this CalendarDate class http://calendardate.sourceforge.net

It's a somewhat competing project to Joda Time, but much more basic at only 2 classes. It's very handy and worked great for what I needed since I didn't want to use a package bigger than my project. Unlike the Java counterparts, its smallest unit is the day so it is really a date (not having it down to milliseconds or something). Once you create the date, all you do to subtract is something like myDay.addDays(-5) to go back 5 days. You can use it to find the day of the week and things like that. Another example:

CalendarDate someDay = new CalendarDate(2011, 10, 27);
CalendarDate someLaterDay = today.addDays(77);

And:

//print 4 previous days of the week and today
String dayLabel = "";
CalendarDate today = new CalendarDate(TimeZone.getDefault());
CalendarDateFormat cdf = new CalendarDateFormat("EEE");//day of the week like "Mon"
CalendarDate currDay = today.addDays(-4);
while(!currDay.isAfter(today)) {
    dayLabel = cdf.format(currDay);
    if (currDay.equals(today))
        dayLabel = "Today";//print "Today" instead of the weekday name
    System.out.println(dayLabel);
    currDay = currDay.addDays(1);//go to next day
}
Hug answered 27/10, 2011 at 20:33 Comment(0)
H
0

Eli Courtwright second solution is wrong, it should be:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());
Hailstone answered 25/9, 2009 at 9:30 Comment(2)
The name of the function in Eli's solution is addDays; his solution is correct. If you want to subtract days from the date, you pass in a negative value for days.Arista
Well, that is something that the programmer has to specify when creating the function, no? :PHailstone

© 2022 - 2025 — McMap. All rights reserved.