I'm using the GregorianCalendar in Java, and I am wondering how I can use this to check whether or not a date is valid (E.g.: to check if Feb 29th is only in leap year, to check if the date is no sooner than the current data, etc).
I have created a GregorianCalendar object and passed it the values of the data I would like to check as follows:
GregorianCalendar cal1 = new GregorianCalendar(day,month,year);
If the date is valid, I'd like to return true. How could I do this?
Basic Idea: if you try to set the invalid date to Calendar instance, it would make it correct one,
For example if you set 45 as date it would not be the same once you set and retrieve
public boolean isValid(int d, int m, int y){
//since month is 0 based
m--;
//initilizes the calendar instance, by default the current date
Calendar cal = Calendar.getInstance();
//resetting the date to the one passed
cal.set(Calendar.YEAR, y);
cal.set(Calendar.MONTH, m);
cal.set(Calendar.DATE, d);
//now check if it is the same as we set then its valid, not otherwise
if(cal.get(Calendar.DATE)==d &&cal.get(Calendar.MONTH) ==m && cal.get(Calendar.YEAR) ==y){
return true;
}
//changed so not valid
return false;
}
Check that after creation, the day, month and year is still the same as the original values you passed. If the original values are incorrect, the date will get adjusted accordingly. E.g.. if you pass (29, 1, 2011) - note that the month value is 0-based so 1 is for February -, you will get back (1, 3, 2011).
tl;dr
java.time.LocalDate.of( 2018 , 2 , 31 )
➙ catch DateTimeException for invalid day-of-month number.
java.time
The GregorianCalendar class has been supplanted by the ZonedDateTime class as part of java.time built into Java 8 and later. A new method has been added to the old class for conversion.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
You want a date-only value, so use LocalDate, without time-of-day and without time zone.
You can extract a LocalDate from a ZonedDateTime time.
LocalDate ld = zdt.toLocalDate() ;
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Valid value
to check if Feb 29th is only in leap year
The documentation for `LocalDate.of( year , month , day ) says:
The day must be valid for the year and month, otherwise an exception will be thrown.
So catch the DateTimeException.
try {
LocalDate ld = LocalDate.of( 2018 , 2 , 31 ) ; // Invalid, February never has 31 days.
return Boolean.TRUE ;
} catch ( DateTimeException e ) {
return Boolean.FALSE ;
}
Leap Year
Yes, LocalDate checks for Leap Year to handle February 29 correctly.
try {
LocalDate ld = LocalDate.of( 2018 , 2 , 29 ) ; // Invalid, as 2018 is a common year.
return Boolean.TRUE ;
} catch ( DateTimeException e ) {
return Boolean.FALSE ;
}
false
…
LocalDate ld = LocalDate.of( 2020 , 2 , 29 ) ; // Valid, as 2020 is a leap year.
…
true
Compare dates
to check if the date is no sooner than the current data
I assume you meant "current 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.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
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 abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Compare with isBefore, isAfter, and isEqual.
boolean b = ld.isBefore( today ) ;
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Related
I need get the same day in this year.
Example: Now is 2019 year and the variable contains value 15 July 2022, so I need to get 15 July 2019 then. It works for all dates except February when it has an extra day in one year and doesn't have this day in this year, example: 29 February 2020 will return me the next day: 1 March 2019, but I need in this case to return the previous day: 28 February 2019. How I can adjust my logic so that it will work in this way?
public static java.util.Date getThisDateInThisYear(java.util.Date date) {
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
Date today = new Date();
GregorianCalendar gcToday = new GregorianCalendar();
gcToday.setTime(today);
gc.set(GregorianCalendar.YEAR, gcToday.get(GregorianCalendar.YEAR));
return gc.getTime();
}
first calc the difference of years and add the result to date
public Date getThisDateInThisYear(Date date) {
Calendar c = Calendar.getInstance();
int thisYear = c.get(Calendar.YEAR)
c.setTime(date);
int diff = thisYear - c.get(Calendar.YEAR);
c.add(Calendar.YEAR, diff);
return c.getTime();
}
I tested with 2016-02-29 and 2020-02-29, and both return 2019-02-28.
tl;dr
Use modern java.time classes. Never use Date/Calendar.
29 February 2020 will return me next day: 1st March 2019
LocalDate // Represent a date-only value, without time-of-day and without time zone.
.of( 2020 , Month.FEBRUARY , 29 ) // Specify a date. Here, Leap Day of 2020. Returns a `LocalDate` object.
.minusYears( 1 ) // Intelligently move backwards in time one year. Returns another `LocalDate` object, per immutable objects pattern.
.toString() // Generate text representing the value of this date, in standard ISO 8601 format of YYYY-MM-DD.
When run at IdeOne.com:
2019-02-28
Avoid legacy date-time classes
You are using terrible date-time classes that are now legacy, supplanted entirely by the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
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.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 2020 , 2 , 29 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety. Ditto for Year & YearMonth.
LocalDate ld = LocalDate.of( 2020 , Month.FEBRUARY , 29 ) ;
Date-time math
You can do date-time math in a few ways with *java.time. One way is by calling plus or minus and passing a Period or Duration. Another way is calling the convenience methods such as plusYears or minusYears.
The LocalDate class seems to give just the behavior you want with these methods.
To be clear:
2020 is a Leap Year. So 2020-02-29 is a valid date.
2018, 2019, and 2021 are not. The 29th is not a valid date in these years.
See the examples below run live at IdeOne.com.
From leap year
Let's start on Leap Day, the 29th, then add a year and subtract a year. We expect to see 28th on both.
LocalDate leapDay2020 = LocalDate.of( 2020 , Month.FEBRUARY , 29 );
LocalDate yearBeforeLeap = leapDay2020.minusYears( 1 );
LocalDate yearAfterLeap = leapDay2020.plusYears( 1 );
System.out.println( "leapDay2020.toString(): " + leapDay2020 );
System.out.println( "yearBeforeLeap.toString(): " + yearBeforeLeap );
System.out.println( "yearAfterLeap.toString(): " + yearAfterLeap );
Indeed that is what we get.
leapDay2020.toString(): 2020-02-29
yearBeforeLeap.toString(): 2019-02-28
yearAfterLeap.toString(): 2021-02-28
From non-Leap Year
Now let's start in a non-Leap Year on the 28th of February, then add & subtract a year. We expect to see 28th in all three. The 29th in the Leap year of 2020 is ignored.
LocalDate nonLeap2019 = LocalDate.of( 2019 , Month.FEBRUARY , 28 );
LocalDate yearBeforeNonLeapIntoNonLeap = nonLeap2019.minusYears( 1 );
LocalDate yearBeforeNonLeapIntoLeap = nonLeap2019.plusYears( 1 );
System.out.println( "nonLeap2019.toString(): " + nonLeap2019 );
System.out.println( "yearBeforeNonLeapIntoNonLeap.toString(): " + yearBeforeNonLeapIntoNonLeap );
System.out.println( "yearBeforeNonLeapIntoLeap.toString(): " + yearBeforeNonLeapIntoLeap );
nonLeap2019.toString(): 2019-02-28
yearBeforeNonLeapIntoNonLeap.toString(): 2018-02-28
yearBeforeNonLeapIntoLeap.toString(): 2020-02-28
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?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Also you can check if year is leap year based on that you can subtract the date
public static boolean isLeapYear(int year) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
}
I don't see any problem with java.util.Calendar. In JDK 1.8 this Java class got a major rework. So the following example code works fine:
SimpleDateFormat sf = new SimpleDateFormat("dd MMM yyyy");
Date date=sf.parse("29 Feb 2020");
System.out.println("date="+date);
Calendar calendar=Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.YEAR, -1);
System.out.println("date="+calendar.getTime());
calendar.add(Calendar.YEAR, 1);
System.out.println("date="+calendar.getTime());
It gives the same result as Basil Bourque wants it to have:
date=Sat Feb 29 00:00:00 CET 2020
date=Thu Feb 28 00:00:00 CET 2019
date=Fri Feb 28 00:00:00 CET 2020
Basically the Java class now uses the same ZoneInfo etc.. classes as the new classes also do.
i want to get the date after modifying the day of the week using Calender class in java
i want to print 16 7 2015(DD/MM/YYYY);
int monthIndex=6,weekIndex=2,dayIndex=4;
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, (monthIndex + 1));
c.set(Calendar.WEEK_OF_MONTH, weekIndex+1 );
c.set(Calendar.DAY_OF_WEEK, dayIndex+1);
int recurMonth = c.get(Calendar.MONTH);
int recWeek=c.get(Calendar.WEEK_OF_MONTH);
int recurDate = c.get(Calendar.DATE);
int recurYear = c.get(Calendar.YEAR);
int dayofMonth=c.get(Calendar.DAY_OF_MONTH);
int dayofWeek=c.get(Calendar.DAY_OF_WEEK);
int dayofweekinmonth=c.get(Calendar.DAY_OF_WEEK_IN_MONTH);
but its showing wrong date
Its pretty clear, I guess.
Calendar today = Calendar.getInstance();
today.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
today.set(Calendar.WEEK_OF_MONTH, 5);
System.out.println(today.get(Calendar.DATE));
The code is self explanatory.
Format date using SimpleDateFormat:
public void printDate(int weekOfMonth, int dayOFWeek) {
Calendar calendar = Calendar.getInstance(Locale.US);
calendar.set(Calendar.WEEK_OF_MONTH, weekOfMonth);
calendar.set(Calendar.DAY_OF_WEEK, dayOFWeek);
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
System.out.println(df.format(calendar.getTime()));
}
tl;dr
To move to the following Monday:
LocalDate.of( 1986 , 2 , 23 ) // Represent a certain date, without time-of-day and without time zone.
.with( TemporalAdjusters.next( DayOfWeek.MONDAY ) ) // Move to the following Monday.
.format( // Generate a string representing this object’s value, using an automatically localizing formatter.
DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )
)
…or, for "third Monday in the same month":
LocalDate.of( 1986 , 2 , 23 ) // Represent a certain date, without time-of-day and without time zone.
.with( TemporalAdjusters.dayOfWeekInMonth( 3 , DayOfWeek.MONDAY ) ) // Move to the third Monday of the same month.
.format( // Generate a string representing this object’s value, using an automatically localizing formatter.
DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )
)
java.time
The modern approach uses the java.time classes that supplanted the troublesome old legacy date-time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
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.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
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 abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Adjusters
To move to another date, use a TemporalAdjuster implementation found in the TemporalAdjusters class. Specify the desired day-of-week using a DayOfWeek enum object.
LocalDate nextMonday = ld.with( TemporalAdjusters.next( DayOfWeek.MONDAY ) ) ;
If your goal is something like "move to the third Monday of the month", use another TemporalAdjuster implementation.
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( 3 , DayOfWeek.MONDAY ) ;
LocalDate thirdMondayOfSameMonth = ld.with( ta ) ;
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.
With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
I wrote simple java program in which I get day of month, days in month and month
see below code :
//Calendar calendar = Calendar.getInstance();
Calendar calendar = new GregorianCalendar();
log.info("day of month: "+calendar.get(Calendar.DAY_OF_MONTH));
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
log.info("days in month: "+calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
log.info("month: "+calendar.get(Calendar.MONTH));
Running above code I get this output:
day of month: 7
days in month: 31
month: 2
But when I put below statement
log.info("month: "+calendar.get(Calendar.MONTH));
before
log.info("day of month: "+calendar.get(Calendar.DAY_OF_MONTH));
I get this output: (which is what I want)
day of month: 7
days in month: 31
month: 5
Can any body help me understand why I get month: 2 ?
Youre setting the Calendar field to Calendar.MONTH (value 2) here
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
^
You can do this
calendar.set(2014, Calendar.JUNE, 1);
although the Month 5 is June (since month field starts from 0 for Calendar) which only has 30 days
Look at the source code of Calendar.java of JDK.
public final static int MONTH = 2;
Here, Calendar.MONTH = 2, Calendar.YEAR=1 and Calendar.DAY_OF_MONTH = 5. You set these constant value to calender using set method like.
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
| | |
1 2 5
tl;dr
LocalDate.now()
.getDayOfMonth()
…and…
YearMonth.from(
LocalDate.now()
).lengthOfMonth() // .getMonthValue() .getYear()
java.time
The modern approach uses the industry-leading java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
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.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
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 abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Parts
Interrogate for the parts as needed.
int dayOfMonth = ld.getDayOfMonth() ;
int month = ld.getMonthValue() ;
int year = ld.getYear() ;
YearMonth
To work with the month as a whole, use YearMonth class.
YearMonth ym = YearMonth.from( ld ) ;
Ask for length of month.
int lengthOfMonth = ym.lengthOfMonth() ;
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
I am having problems with the Calendar Class.
Calendar cal = Calendar.getInstance ();
int iYear = cal.get (Calendar.YEAR); // get the current year
int iMonth = cal.get (Calendar.MONTH); // month...
int iDay = cal.get (Calendar.); // current day in the month
This... No Workie!! :-(
I used the debugger and found that the YEAR and the DAY_OF_MONTH are correct,
however, the MONTH is 1 (January) when it SHOULD BE 2 (February).
Here is where it gets even more WEIRD:
I then tried cal.clear ();
followed by cal.set (2014, 2, 27); // Today's Date - Feb 27, 2014
and the month was still 1 (i.e. January)
I set the date to days in January, (2014, 1, 1), (2014, 1, 16),etc
It correctly gave me a 1 for the month
After reading and trying many things (and pulling my hair out..)
I set it to a date in the future, my Birthday (2014, 5, 23) and other days.
For those dates, Month was correctly set to 5 (May)
Month in Calendar begins at 0, which means 0 is January, 1 is February, etc.
Java Date and Time API sucks. Use Joda-Time instead.
use constants in Calendar for month: Calendar.JANUARY etc
For example:
cal.set(2014, Calendar.FEBRUARY, 27);
Please see the description provided for MONTH Constant in Calendar Class.
Calendar.MONTH
public static final int MONTH
Field number for get and set indicating the month. This is a calendar-specific value. The first month of the year in the Gregorian and Julian calendars is JANUARY which is 0; the last depends on the number of months in a year.
So if you want to set the date in calendar than use below code snippet.
cal.set(2014, Calendar.FEBRUARY, 28);
I think it will help you.
tl;dr
LocalDate.now()
.getYear()
java.time
The modern approach uses the industry-leading java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
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.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
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 abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Parts
Interrogate for the parts as needed.
int dayOfMonth = ld.getDayOfMonth() ;
int month = ld.getMonthValue() ;
int year = ld.getYear() ;
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Let try this simple program:
import java.util.Calendar;
class CalendarExample {
public static void main(String args[]) {
Calendar calendar = Calendar.getInstance();
System.out.println("Current Date : " + calendar.get(Calendar.DATE));
System.out.println("Current Month : " + calendar.get(Calendar.MONTH));
System.out.println("Current Year : " + calendar.get(Calendar.YEAR));
System.out.print("Current Time : ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
System.out.print(calendar.get(Calendar.SECOND));
}
}
You get the o/p:
Current Date : 28
Current Month : 1
Current Year : 2014
Current Time : 11:18:3
In Calender class Jan as constant int is 0 , Feb is 1 ... .month constant int value is from 0,1,2..
How to check whether the given date is earlier than a month ago? What is the fastest algorithm? I have to take into account that different months have different numbers of days.
Updated to Java 8
The class LocalDate class can be used:
LocalDate aDate = LocalDate.parse("2017-01-01");
return aDate.isBefore( LocalDate.now().minusMonths(1));
For previous versions, the Calendar class would work.
Calendar calendar = Calendar.getInstance();
calendar.add( Calendar.MONTH , -1 );
return aDate.compareTo( calendar.getTime() ) < 0;
Sample code:
import static java.lang.System.out;
import java.time.LocalDate;
public class Sample {
public static void main( String [] args ) {
LocalDate aMonthAgo = LocalDate.now().minusMonths(1);
out.println( LocalDate.parse("2009-12-16").isBefore(aMonthAgo));
out.println( LocalDate.now().isBefore(aMonthAgo));
out.println( LocalDate.parse("2017-12-24").isBefore(aMonthAgo));
}
}
Prints
true
false
false
Using Joda Time:
DateTime dt1 = new DateTime(); //Now
DateTime dt2 = new DateTime(2009,9,1,0,0,0,0); //Other date
if (dt1.plusMonths(-1) > dt2) {
//Date is earlier than a month ago
}
tl;dr
LocalDate.now( ZoneId.of( "America/Montreal" )
.minusMonths( 1 )
.isAfter( LocalDate.parse( "2017-01-23" ) )
java.time
The modern approach uses the java.time classes rather than the troublesome legacy classes such as Date & Calendar.
Today
First get the current date. The LocalDate class represents a date-only value without time-of-day and without time zone.
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 abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
Calculating month-ago
Next, determine the date a month ago.
LocalDate monthAgo = today.minusMonths( 1 ) ;
Here are the rules used by LocalDate::minusMonths, quoted from Java 8 class doc:
This method subtracts the specified amount from the months field in three steps:
Subtract the input months from the month-of-year field
Check if the resulting date would be invalid
Adjust the day-of-month to the last valid day if necessary
For example, 2007-03-31 minus one month would result in the invalid date 2007-02-31. Instead of returning an invalid result, the last valid day of the month, 2007-02-28, is selected instead.
Or, perhaps in your business rules you meant "30 days" instead of a calendar month.
LocalDate thirtyDaysAgo = today.minusDays( 30 ) ;
Input
You are given a date. That should be passed to your code as a LocalDate object.
LocalDate ld = LocalDate.of( 2017 , Month.JANUARY , 23 ) ;
If coming from a String, use the standard ISO 8601 formats. For other formats, search Stack Overflow for DateTimeFormatter class.
LocalDate ld = LocalDate.parse( "2017-01-23" ) ;
Comparison
Now compare. Call the isBefore, isEqual, isAfter methods.
Boolean outdated = ld.isBefore( monthAgo ) ;
Performance
As for the issue of performance raised in the Question: Don't worry about it. This month-ago calculation and comparison is very unlikely to be a bottleneck in your app. Avoid premature optimization.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
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.