I am working in an integrated environment (IBM Process Server) and I am not able to import anything, can only use standard java functionality.
How can I add x number of months to a given date?
I am working in an integrated environment (IBM Process Server) and I am not able to import anything, can only use standard java functionality.
How can I add x number of months to a given date?
Given that you have Date imported by default, you can add a number of months to the date object by the following:
public void addMonths(Date date, int numMonths){
date.setMonth((date.getMonth() - 1 + numMonths) % 12 + 1);
}
NOTE
You can use external classes from Java SE by using their full package name. i.e., even if you cannot add import java.util.Calendar;
to the top of you .java
file, you can still create a calendar object by executing java.util.Calendar cal = java.util.Calendar.getInstance();
@ewok's answer does not work always when going past the year end, only with numMonths
set to values lower or equal to the months until next January:
SSCCE:
public static void main(String[] args) {
for(int i=0;i<10; i++) {
Date date = new Date();
Date updated = (Date)date.clone();
addMonths(updated, i);
System.out.println(" original: " + date+ " adding " +i+ " months: " + updated);
}
}
public static void addMonths(Date date, int numMonths){
date.setMonth((date.getMonth() - 1 + numMonths) % 12 + 1);
}
Output:
original: Sat Aug 24 14:02:17 CEST 2013 adding 0 months: Sat Aug 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 1 months: Tue Sep 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 2 months: Thu Oct 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 3 months: Sun Nov 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 4 months: Tue Dec 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 5 months: Fri Jan 24 14:02:17 CET 2014
original: Sat Aug 24 14:02:17 CEST 2013 adding 6 months: Sun Feb 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 7 months: Sun Mar 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 8 months: Wed Apr 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 9 months: Fri May 24 14:02:17 CEST 2013
Notice the February, March, etc dates are back in 2013! The code is flawed because of the strange arithmetics... setMonth handles values > 12 too...
Corrected (though still using the deprecated method...):
date.setMonth((date.getMonth() + numMonths) );
Output:
original: Sat Aug 24 14:13:09 CEST 2013 adding 0 months: Sat Aug 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 1 months: Tue Sep 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 2 months: Thu Oct 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 3 months: Sun Nov 24 14:13:09 CET 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 4 months: Tue Dec 24 14:13:09 CET 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 5 months: Fri Jan 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 6 months: Mon Feb 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 7 months: Mon Mar 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 8 months: Thu Apr 24 14:13:09 CEST 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 9 months: Sat May 24 14:13:09 CEST 2014
Things to consider
Last days of months, from the Java doc of setMonth():
Sets the month of this date to the specified value. This Date object is modified so that it represents a point in time within the specified month, with the year, date, hour, minute, and second the same as before, as interpreted in the local time zone. If the date was October 31, for example, and the month is set to June, then the new date will be treated as if it were on July 1, because June has only 30 days.
Still deprecated - Solving the problem properly would be overly time consuming however (exceptional cases, leap days, leap seconds, whatever), not to mention total reinvention of the wheel... Maybe trimming Calendar to the bare minimum, and pasting it into the code would solve it - but even that is not worth the hassle...
Should definitely try the second approach what @ewok suggested, the fully qualified classname thing.
If you want to implement without calendar use @ewok suggestion if working with deprecated method a problem then use the following code:
SimpleDateFormat dt1 = new SimpleDateFormat("yyyy-MM-dd"); //Date format
SimpleDateFormat dt = new SimpleDateFormat("MM");
Date date = dt1.parse("2013-12-31");
int dm=0;
int m = Integer.parseInt(dt.format(date));
switch(m){
case 2:
m = 27;
break;
case 4:
case 6:
case 9:
case 11:
m = 29;
break;
default:
m = 30;
break;
}// Closing switch block
long month = Math.round(1000*60*60*24.25*m);
long oneMonthTime = date.getTime()+month;
System.out.println(dt1.format(oneMonthTime));
This code is not for leap year. I know its non perfect one but still working code.
myJavaUtilDate.toInstant() // Convert troublesome legacy `java.util.Date` object to a modern java.time object, `Instant`.
.atZone( ZoneId.of( "Pacific/Auckland" ) ) // Adjust that `Instant` object from UTC to a particular time zone thereby instantiating a `ZonedDateTime` object, to determine dates.
.plus( Period.ofMonths( 6 ) ) // Add six months represented by a `Period` to instantiate another `ZonedDateTime` object.
The java.time classes are built into Java 8, Java 9, and later. These supplant the troublesome old date-time classes such as Date
and Calendar
.
If you must inter-operate with an existing Date
object, convert to java.time. The equivalent is Instant
. The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). Convert using new methods added to the old classes.
Instant instant = myJavaUtilDate.toInstant() ;
An Instant
is a moment in UTC. Adding six months requires a date. A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter pseudo-zones such as EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
Adjust your Instant
into that time zone, applying a ZoneId
to get a ZonedDateTime
object.
ZonedDateTime zdt = instant.atZone( z ) ;
Define six months as a Period
.
Period p = Period.ofMonths( 6 ) ;
Add that Period
object to generate a new ZonedDateTime
object.
ZonedDateTime later = zdt.plus( p ) ;
See this code run live at IdeOne.com.
instant.toString(): 2018-01-31T06:26:34.580Z
zdt.toString(): 2018-01-31T01:26:34.580-05:00[America/Montreal]
p.toString(): P6M
later.toString()2018-07-31T01:26:34.580-04:00[America/Montreal]
If you need to get back to a value in UTC, extract a Instant
.
Instant instant = later.toInstant() ;
If you need a Date
, convert. But try to avoid this class if possible.
Date d = Date.from( instant ) ;
If you have date-only value without time-of-day, use LocalDate
. The LocalDate
class represents a date-only value without time-of-day and without time zone.
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ; // January 23, 2018.
LocalDate later = ld.plusMonths( 6 ) ;
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.
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.