Use Calendar to get the number of days in February - java

The question is to get day numbers of February of any year. My code is like this:
public static void main(String[] args) {
System.out.println("2014-02 has " + getDaysOfFeb(2014) + "days");
System.out.println("2016-02 has " + getDaysOfFeb(2016) + "days");
}
public static int getDaysOfFeb(int year) {
Calendar c = Calendar.getInstance();
// set year-01-31
c.set(year, 0, 31);
long lastDayofJan = c.getTimeInMillis();
// set year-03-01
c.set(year, 2, 1);
long firstDayOfMar = c.getTimeInMillis();
int date = (int) ((firstDayOfMar - lastDayofJan) / 1000 / 60 / 60 / 24);
}
I got Jan 31st and Mar 1st, I use the difference of time to calculate the day numbers. But the result is:
2014-02 has 29days
2016-02 has 30days
I don't understand why.
When I do like this:
public static int getDaysOfFeb(int year) {
Calendar c = Calendar.getInstance();
// set year-01-31
c.set(year, 2, 1);
c.add(Calendar.DATE, -1); // last day of Feb
int date = c.get(Calendar.DATE);
return date;
}
The result is right, as follow:
2014-02 has 28days
2016-02 has 29days
Does anyone know what the difference is here?

It is exactly how it should be. The difference between March, 1 and January, 31 is one day more than the number of days in February. In general, the difference between the same days in two consecutive months is the number of days in the earliest of these two months. So, the difference between March, 1 and February, 1 is the number of days in February, as well as the difference between March, 10 and February, 10 (and any other day). The difference between April, 1 and March, 1 is always 31 (the number of days in March) and so on.

Not that this is an exact answer. But I wrote a quick Java program a while ago that will generate a calendar for pretty much whatever month/year you want. The example falls directly in line with what you're trying to do.
Here is the code running on TutorialsPoint:
Calendar in Java
Code:
import java.util.Calendar;
public class calDays {
/**
* #param args
*/
static Calendar today = Calendar.getInstance();
static int curDay = today.get(Calendar.DAY_OF_MONTH);
static int curMonth = today.get(Calendar.MONTH);
static int curYear = today.get(Calendar.YEAR);
public static void main(String[] args) {
drawCal(curMonth,curYear);
drawCal(5,1969);
drawCal(4,2001);
}
public static void drawCal(Integer monthIs, Integer yearIs){
System.out.println(""+getMonth(monthIs)+" "+yearIs);
System.out.println("S M T W T F S ");
int calDayBox =0;
Calendar monthtd = Calendar.getInstance();
monthtd.set(Calendar.DAY_OF_MONTH,1);
monthtd.set(Calendar.MONTH, monthIs);
monthtd.set(Calendar.YEAR, yearIs);
int daysInMonth = monthtd.getActualMaximum(Calendar.DAY_OF_MONTH);
int allboxes=0;
//Draw leading days
int CalDaxBoxVal=1;
for (int xx=0;xx<monthtd.get(Calendar.DAY_OF_WEEK)-1;xx++){
System.out.print("_ ");
calDayBox++;
allboxes++;
}
for (int xx=calDayBox;xx<daysInMonth+calDayBox;xx++){
System.out.print(""+CalDaxBoxVal+ " ");
if (CalDaxBoxVal<10) System.out.print(" ");
CalDaxBoxVal++;
allboxes++;
if (allboxes%7==0) System.out.println();
}
System.out.println();
System.out.println();
}
public static String getMonth(Integer whichMonth){
String monthsAre[] = new String[12];
monthsAre[0]="January";
monthsAre[1]="February";
monthsAre[2]="March";
monthsAre[3]="April";
monthsAre[4]="May";
monthsAre[5]="June";
monthsAre[6]="July";
monthsAre[7]="August";
monthsAre[8]="September";
monthsAre[9]="October";
monthsAre[10]="November";
monthsAre[11]="December";
return monthsAre[whichMonth];
}
}

Change your first method to something like this.
Calendar c = Calendar.getInstance();
c.set(year, 1, 1);
long firstDayOfFeb= c.getTimeInMillis();
c.set(year, 2, 1);
long firstDayOfMar = c.getTimeInMillis();
int date = (int) ((firstDayOfMar - firstDayOfFeb) / 1000 / 60 / 60 / 24);
return date;
In your calculation you are actually calculating from last day of january to 1 st dat of March, where as you should start from 1 st day of Feb to 1st day of march for correct answer. The problem is with calculation.

This can be easily answered with simple mathematics.
If you are subtracting 0 from 30, (30 - 0 = ?) you get 30.
If you are subtracting 1 from 30, (30 - 1 = ?) you get 29.
Pretend 0 is February 0th (which is equivalent to January 31st)
Pretend 30 is February 30th (which is equivalent to March 1st on a leap year)
So therefore, March 1st - January 31st must be 30 days.
In order to get the desired number of days, you must subtract 1 from 30, and not 0 from 30.
Pretend 1 is February 1st
Pretend 30 is February 30th (which is equivalent to March 1st on a leap year)
Therefore, you would need to subtract March 1st from February 1st in order to get the correct number of days in February.

tl;dr
YearMonth.parse( "2014-02" ).lengthOfMonth()
Avoid old date-time classes
The Question and other Answers use troublesome old legacy date-time classes bundled with the earliest versions of Java. Now supplanted by the java.time classes.
YearMonth
Among the java.time classes is YearMonth to represent, well, a year and month.
Note that in java.time the months have sane numbering, 1-12 for January-December (unlike the crazy 0-11 in old date-time classes).
YearMonth ym = YearMonth.parse( "2014-02" );
Or you can make use of the handy Month enum.
YearMonth ym = YearMonth.of( 2014 , Month.FEBRUARY );
Interrogate for the number of days in that month by calling lengthOfMonth.
int lengthOfMonth = ym.lengthOfMonth() ;
You can ask if the year of that year-month is a Leap Year by calling isLeapYear.
boolean isLeapYear = ym.isLeapYear();
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
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

How to find total weeks of a year in Java?

I am working on a project. There I should find the total weeks of a year. I tried with the following code, but I get the wrong answer: 2020 has 53 weeks, but this code gives 52 weeks.
Where have I gone wrong in this code?
package com.hib.mapping;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.joda.time.DateTime;
public class TestWeek {
public static void main(String args[]) {
System.out.println(getWeeks());
}
public static int getWeeks() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2020);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
GregorianCalendar gregorianCalendar = new GregorianCalendar();
int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (gregorianCalendar.isLeapYear(2020)) {
if (weekDay == Calendar.THURSDAY || weekDay == Calendar.WEDNESDAY)
return 53;
else
return 52;
} else {
if (weekDay == Calendar.THURSDAY)
return 53;
else
return 52;
}
}
}
Output:
52
tl;dr
For a standard ISO 8601 week, use the YearWeek class from ThreeTen-Extra library with a ternary statement.
YearWeek // Represents an entire week of a week-based-year.
.of( 2020 , 1 ) // Pass the number of the week-based-year (*not* calendar year), and a week number ranging from 1 to 52 or 1 to 53.
.is53WeekYear() // Every standard week-based-year has either 52 or 52 complete weeks.
? 53 // Ternary statement returns 53 if the predicate returns True, …
: 52 // … otherwise returns 52.
That is, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52
Define “week”
You need to define a week. In your code sample, the definition of week varies by the JVM’s current default Locale. So your results may vary at runtime.
Your code also uses terrible date-time classes that were supplanted years ago by the modern java.time classes. Stop using GregorianCalendar & Calendar; they were replaced for good reasons.
ISO 8601 week
The ISO 8601 standard defines a week as:
Weeks start on Monday, end on Sunday.
Week # 1 has the first Thursday of the calendar-year.
That definition means:
The first and last few days of a week-based-year may be the trailing/leading days of the previous/following calendar-year.
The week-based-year has either 52 or 53 complete weeks.
If your definition differs, see the Answer by Ole V.V..
YearWeek:is53WeekYear
If this matches your definition, then add the ThreeTen-Extra library to your project to extend the java.time functionality built into Java 8 and later. You then have access to the YearWeek class.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearWeek yearWeekNow = YearWeek.now( z ) ;
boolean is53WeekYear = yearWeekNow.is53WeekYear() ;
int weeksLong = yearWeekNow.is53WeekYear() ? 53 : 52 ;
To ask about a particular week-based-year, just arbitrarily pick any week of the year. For example, for the week-based year 2020 we ask for week # 1.
int weeksLong = YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52 ;
LocalDate weekStart = YearWeek.of( 2020 , 1 ).atDay( DayOfWeek.MONDAY ) ;
weeksLong = 53
weekStart = 2019-12-30
Notice how the first day of the week-based-year of 2020 is from the calendar-year 2019.
Using the Wikipedia definition here. A year has 53 weeks if 1st Jan is a Thursday, or 31st Dec is a Thursday, otherwise it has 52 weeks. This definition is equivalent to the one you used. I think this is a way easier condition to check for, as you don't need to check for leap years.
Using the Java 8 java.time APIs:
int year = 2020;
boolean is53weekYear = LocalDate.of(year, 1, 1).getDayOfWeek() == DayOfWeek.THURSDAY ||
LocalDate.of(year, 12, 31).getDayOfWeek() == DayOfWeek.THURSDAY;
int weekCount = is53weekYear ? 53 : 52;
The flexible solution
This should work for any week numbering scheme that can be represented in a WeekFields object.
public static int noOfWeeks(WeekFields wf, int year) {
LocalDate lastDayOfYear = YearMonth.of(year, Month.DECEMBER).atEndOfMonth();
if (lastDayOfYear.get(wf.weekBasedYear()) > year) { // belongs to following week year
return lastDayOfYear.minusWeeks(1).get(wf.weekOfWeekBasedYear());
}
else {
return lastDayOfYear.get(wf.weekOfWeekBasedYear());
}
}
The idea is to find the week number of the last week of the week based year. I try first with 31 December, but that may be in the first week of the following year. If so, I go one week back.
I have tested pretty thoroughly with WeekFields.ISO, not so much with other WeekFields objects, but as I said, I believe it works.
If you know for a fact that you will always need ISO 8601 weeks, I think you should go with one of the good answers by Sweeper and by Basil Bourque. I posted this in case you needed a more flexible solution that would work with other week numbering schemes too.
Use java.time
The code in your question is funny in that it imports classes both from Joda-Time and from java.time, yet uses the old Calendar and GregorianCalendar from Java 1.1. These classes were poorly designed and are now long outdated, you should not use them. Joda-Time is in maintenance mode, java.time has taken over after it. Which is what I use and recommend that you use.
I think this should work just fine as well:
int year = 2020;
long numOfWeeks = LocalDate.of(year, 1, 1).datesUntil(LocalDate.of(year, 12, 31), Period.ofDays(7)).count();
System.out.println("Weeks: " + numOfWeeks);
Below code works for me.
public static int getTotalWeeksInYear(int year){
int totalWeeks=0;
Calendar calendar=Calendar.getInstance();
for(int month=0;month<12;mmonth++){
int day=1;
do{
calendar.set(year, month, day);
if(calendar.get(Calendar.DAY_OF_WEEK)==5)
totalWeeks++;
day++;
}while (day <=calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
}
return totalWeeks;
}
Using Java.time
public static long getTotalWeekByLocalDate(LocalDate ldate) {
long weeksInYear = IsoFields.WEEK_OF_WEEK_BASED_YEAR.rangeRefinedBy(ldate).getMaximum();
return weeksInYear;
}
After trying a lot in java 8. I could not find a solution. then I prepared Joda date and time dependency. It gave me a good answer as I expected
code:
for (int i = 2020; i < 2100; i++) {
int weeks = new DateTime().withYear(i).weekOfWeekyear().getMaximumValue();
System.out.println(i + " years : " + weeks);
}
Maven Dependency:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.5</version>
</dependency>

Apache DateUtils truncate day of month

I would like to create a DateHelper class and for that I'm using DateUtils from Apache Commons Lang 2.6.
I'm having problems understanding the result returned when extract field from a date. Here is my test class which extract the day of month after truncate the date :
public class DateTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// Date date = createDate(2000, 1, 2, 3, 4, 5, 6);
Calendar calendar = createEmptyUTCCalendar();
calendar.set(Calendar.YEAR, 2000);
calendar.set(Calendar.MONTH, 0); // january
calendar.set(Calendar.DAY_OF_MONTH, 2);
calendar.set(Calendar.HOUR_OF_DAY, 3);
calendar.set(Calendar.MINUTE, 4);
calendar.set(Calendar.SECOND, 5);
calendar.set(Calendar.MILLISECOND, 6);
Date date = calendar.getTime();
System.out.println("Input date\n" + date);
// Truncate from day of month.
Date dateTruncate = getDatePart(date);
System.out.println("Truncate the date\n" + dateTruncate);
System.out.println("\n*** Extract day of month ***");
// Extract the field day of month from the truncated date.
int fieldDayOfMonth = getField(dateTruncate, Calendar.DAY_OF_MONTH);
System.out.println("Expected result is 2\nActual result is " + fieldDayOfMonth);
assert fieldDayOfMonth == 2;
}
public static int getField(Date date, int calendarField) {
Calendar calendar = createEmptyUTCCalendar();
calendar.setTime(date);
int value = calendar.get(calendarField);
if (calendarField == Calendar.MONTH) {
value++;
}
return value;
}
public static Date getDatePart(Date date) {
return DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
}
private static Calendar createEmptyUTCCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
return calendar;
}
}
I expect the result of extracting the field Calendar.DAY_OF_MONTH to be 2 but I got 1.
Input date
Sun Jan 02 04:04:05 CET 2000
Truncate the date
Sun Jan 02 00:00:00 CET 2000
*** Extract day of month ***
Expected result is 2
Actual result is 1
tl;dr
LocalDate.of( 2000 , Month.JANUARY , 2 )
.getDayOfMonth()
2
java.time
You can just use Java now, no need for Apache DateUtils. And truncation is the wrong way to think about it; just interrogate for the day-of-month property.
Specify your date using LocalDate class. Note that java.time uses sane month numbering, 1-12 for January to December.
LocalDate ld = LocalDate.of( 2000 , 1 , 2 ) ; // January 2, 2000.
Or use the Month enum.
LocalDate ld = LocalDate.of( 2000 , Month.JANUARY , 2 ) ; // January 2, 2000.
2000-01-02
Interrogate for day-of-month. You can call getDayOfMonth on a LocalDate, OffsetDateTime, and ZonedDateTime.
int dayOfMonth = ld.getDayOfMonth​() ;
2
If receiving a Calendar object, it is likely a GregorianCalendar. If so, you can easily convert to java.time classes.
if( myCalendar instanceOf GregorianCalendar ) {
GregorianCalendar gc = ( GregorianCalendar ) myCalendar ; // Cast.
ZonedDateTime zdt = gc.toZonedDateTime() ; // Convert from legacy class to modern class.
int dayOfMonth = zdt.getDayOfMonth​() ;
}
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.
It seems that the thing is on the timezones. Your calendar is on UTC and your date on your local zone, if you avoid the line:
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
the thing should work.
When you pass calendar to Date, the date object gets default time zone CET in your case. Then you truncate and pass again to a UTC calendar, and due to the diffenrence between CET and UTC you day is the previous one.

Java get half month number

I would to get the number of the half month od the year starting from a date.
For example, I have 13-Mar-2012, and I have 6 as result.
I've tried with Calendar class, but doesn't work properly:
Calendar cal = (GregorianCalendar) Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH,13);
cal.set(Calendar.MONTH, 2);
cal.set(Calendar.YEAR, 2012);
int weekNum = cal.get(Calendar.WEEK_OF_YEAR);
System.out.println("Weeknum:" + ((weekNum/2)));
Can anyone help me?
Assuming Half month as defined here: http://en.wikipedia.org/wiki/Half-month
Calendar cal = (GregorianCalendar) Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 13);
cal.set(Calendar.MONTH, 2);
cal.set(Calendar.YEAR, 2012);
// remember, we have a zero based month
int halfMonth = cal.get( Calendar.MONTH ) * 2 + 1;
// 1-15 is first half-month 16-end of month is second
int remainder = cal.get( Calendar.DAY_OF_MONTH ) / 16;
halfMonth += remainder;
System.out.println( halfMonth );
Calendar cal = (GregorianCalendar) Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH,13);
cal.set(Calendar.MONTH, 2);
cal.set(Calendar.YEAR, 2012);
int hafMonthCount = cal.get(Calendar.DAY_OF_YEAR) / 14 ;
//here you must multiply by 2 :)
System.out.println("HalfMonthCount:" + hafMonthCount );
---updated
As the concept you use is not implemented in Java (in french we have this concept of quizaine for 14 days but in english I can't say), you must compute it by yourself.
Details to show by example what happens with your code. Assume we have the following four different values of WEEK_OF_YEAR:
WEEK_OF_YEAR: 1
WEEK_OF_YEAR: 2
WEEK_OF_YEAR: 3
WEEK_OF_YEAR: 4
What will happen if we divide these values by 2?
WEEK_OF_YEAR: 1 (weekNum/2) = 1/2 = 0
WEEK_OF_YEAR: 2 (weekNum/2) = 2/2 = 1
WEEK_OF_YEAR: 3 (weekNum/2) = 3/2 = 1
WEEK_OF_YEAR: 4 (weekNum/2) = 4/2 = 2
So the issue with your code is that it will result in the first week of the year resulting in a value 0. So what you'd want to be doing in your code is to replace the (weekNum/2) with ((weekNum + 1)/2).
If the astronomy Half-Month is intended (not to be confused with an astronomy fortnight), then the Answer by jarrad is correct. But we have more modern classes at our disposal now, the 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.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.now( z );
Get the month number, 1-12 for January-December.
int monthNumber = ld.getMonthValue(); // 1-12.
Multiply that month number by two, as there are two month-halves in every month. If early in the month, subtract one (so 6 becomes 5, for example).
int adjustment = ( ld.getDayOfMonth() < 16 ) ? 1 : 0 ; // If first half of month, back off the half-month-number by 1.
int halfMonthNumber = ( ( monthNumber * 2 ) - adjustment ); // 1-24.
The astronomy Half-Month labels each with a English letter, A-Y while omitting I. So we extract a letter from this subset alphabet of 24 letters by the half-month-number.
int index = ( halfMonthNumber - 1 ); // Subtract one for zero-based counting.
String alphaCode = "ABCDEFGHJKLMNOPQRSTUVWXY".substring( index , index + 1 );
I have not run that code, just typed off the top of my head. Use at your own risk, and please fix if needed.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
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.

Java, get days between two dates

In java, I want to get the number of days between two dates, excluding those two dates.
For example:
If first date = 11 November 2011 and the second date = 13 November 2011
then it should be 1.
This is the code I am using but doesn't work (secondDate and firstDate are Calendar objects):
long diff=secondDate.getTimeInMillis()-firstDate.getTimeInMillis();
float day_count=(float)diff / (24 * 60 * 60 * 1000);
daysCount.setText((int)day_count+"");
I even tried rounding the results but that didn't help.
How do I get the number of days between dates in java excluding the days themselves?
I've just tested on SDK 8 (Android 2.2) the following code snippet:
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.clear();
date1.set(
datePicker1.getYear(),
datePicker1.getMonth(),
datePicker1.getDayOfMonth());
date2.clear();
date2.set(
datePicker2.getYear(),
datePicker2.getMonth(),
datePicker2.getDayOfMonth());
long diff = date2.getTimeInMillis() - date1.getTimeInMillis();
float dayCount = (float) diff / (24 * 60 * 60 * 1000);
textView.setText(Long.toString(diff) + " " + (int) dayCount);
it works perfectly and in both cases (Nov 10,2011 - Nov 8,2011) and (Nov 13,2011 - Nov 11,2011) gives dayCount = 2.0
Get Days between java.util.Dates, ignoring daylight savings time
Quick and dirty hack:
public int get_days_between_dates(Date date1, Date date2)
{
//if date2 is more in the future than date1 then the result will be negative
//if date1 is more in the future than date2 then the result will be positive.
return (int)((date2.getTime() - date1.getTime()) / (1000*60*60*24l));
}
This function will work 99.99% of the time, except when it surprises you later on in the edge cases during leap-seconds, daylight savings, timezone changes leap years and the like. If you are OK with the calculation being off by 1 (or 2) hours once in a while, this will suffice.
Get Days between Dates taking into account leapseconds, daylight savings, timezones, etc
If you are asking this question you need to slap yourself. What does it mean for two dates to be at least 1 day apart? It's very confusing. What if one Date is midnight in one timezone, and the other date is 1AM in another timezone? Depending on how you interpret it, the answer is both 1 and 0.
You think you can just force the dates you pass into the above function as Universal time format; that will fix some of your problems. But then you just relocate the problem into how you convert your local time to a universal time. The logical conversion from your timezone to universal time may not be what is intuitive. In some cases you will get a day difference when the dates passed in are obviously two days apart.
And you think you can deal with that? There are some simplistic calendar systems in the world which are constantly changing depending on the harvest season and installed political rulers. If you want to convert their time to UTC, java.util.Date is going to fail you at the worst moment.
If you need to calculate the days between dates and it is critical that everything come out right, you need to get an external library called Joda Time: (They have taken care of all the details for you, so you can stay blissfully unaware of them): http://joda-time.sourceforge.net/index.html
java.time
The java.time API, released with Java-8 in March 2014, supplanted the error-prone legacy date-time API. Since then, using this modern date-time API has been strongly recommended.
Solution using modern date-time API
Using Calendar#toInstant, convert your java.util.Calendar instances into java.time.Instant and then into java.time.ZonedDateTime instances and then use ChronoUnit.DAYS.between to get the number of days between them.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
// Sample start and end dates as java.util.Date
Calendar startCal = Calendar.getInstance();
startCal.set(2011, 10, 11); // 11 November 2011
Calendar endCal = Calendar.getInstance();
endCal.set(2011, 10, 13); // 13 November 2011
// Convert the java.util.Calendar into java.time.ZonedDateTime
// Replace ZoneId.systemDefault() with the applicable ZoneId
ZonedDateTime startDateTime = startCal.toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime endDateTime = endCal.toInstant().atZone(ZoneId.systemDefault());
// The end date is excluded by default. Subtract 1 to exclude the start date
long days = ChronoUnit.DAYS.between(startDateTime, endDateTime) - 1;
System.out.println(days);
}
}
Output:
1
Learn more about the modern Date-Time API from Trail: Date Time.
Don't use floats for integer calculations.
Are you sure your dates are days? The precision of the Date type is milliseconds. So the first thing you need to do is round the date to something which doesn't have hours. Example: It's just one hour from 23:30 2011-11-01 to 00:30 2011-11-02 but the two dates are on different days.
If you are only going to be dealing with dates between the years 1900 and 2100, there is a simple calculation which will give you the number of days since 1900:
public static int daysSince1900(Date date) {
Calendar c = new GregorianCalendar();
c.setTime(date);
int year = c.get(Calendar.YEAR);
if (year < 1900 || year > 2099) {
throw new IllegalArgumentException("daysSince1900 - Date must be between 1900 and 2099");
}
year -= 1900;
int month = c.get(Calendar.MONTH) + 1;
int days = c.get(Calendar.DAY_OF_MONTH);
if (month < 3) {
month += 12;
year--;
}
int yearDays = (int) (year * 365.25);
int monthDays = (int) ((month + 1) * 30.61);
return (yearDays + monthDays + days - 63);
}
Thus, to get the difference in days between two dates, you calculate their days since 1900 and calc the difference. Our daysBetween method looks like this:
public static Integer getDaysBetween(Date date1, Date date2) {
if (date1 == null || date2 == null) {
return null;
}
int days1 = daysSince1900(date1);
int days2 = daysSince1900(date2);
if (days1 < days2) {
return days2 - days1;
} else {
return days1 - days2;
}
}
In your case you would need to subtract an extra day (if the days are not equal).
And don't ask me where this calculation came from because we've used it since the early '90s.
I have two suggestions:
Make sure your float day_count is calculated correctly
float day_count = ((float)diff) / (24f * 60f * 60f * 1000f);
If it's rounding error, try using floor method
daysCount.setText("" + (int)Math.floor(day_count));

Java: How do I get the date of x day in a month ( e.g. Third Monday in February 2012)

I am somewhat struggling with this.
I want to setup my Calendar to let's say: Third Monday in February 2012.
And I didn't find any way of doing this using Java.
For example, if I wanted to set my calendar for Christmas 2011, I can do this easily, this way:
Calendar when = Calendar.getInstance();
when.set (Calendar.MONTH, Calendar.DECEMBER);
when.set (Calendar.DAY_OF_MONTH, 25)
when.set (Calendar.YEAR, 2011);
But I am lost as to how to set it up for let's say Memorial Day 2012, which is the last Monday of May. This is my code, but it's obviously wrong, because I simply can't assume that the last Monday of May will be in the 4th week of May that year:
Calendar when = Calendar.getInstance ();
when.set (Calendar.DAY_OF_WEEK,Calendar.MONDAY);
when.set (Calendar.MONTH, Calendar.MAY);
when.set (Calendar.WEEK_OF_MONTH, 4)
when.set (Calendar.YEAR, 2012);
Any suggestions as to how I can programatically find out, in which week of the month of May 2012 (in example above) is the last Monday? Assuming I can get that information, I should be able to get my code above to work.
I need something which would basically work for any other examples. Something which could give an exact day for the same scenarios. Examples:
Which date is:
3rd Thursday of May 2015
1st Monday of June 2050
4th Tuesday of December 2012
2nd Wednesday of July 2000
I really need this for my project and I am sure it's simple, but I am breaking my head on this without any real results to show for :) And also couldn't find anything on the net.
Added:
Ok, this is where I've got for the last Monday in a month:
when.set (GregorianCalendar.MONTH, GregorianCalendar.MAY);
when.set (GregorianCalendar.DAY_OF_WEEK, Calendar.MONDAY);
when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, -1);
when.set (Calendar.YEAR, 2012);
But I am not sure how would I go about doing for example seconds Monday in the same month, like this?
when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2);
Any suggestions?
To do date arithmetic in Java (and in general, to do anything with datetimes, except for the most trivial things) Joda-Time is the answer:
public static LocalDate getNDayOfMonth(int dayweek,int nthweek,int month,int year) {
LocalDate d = new LocalDate(year, month, 1).withDayOfWeek(dayweek);
if(d.getMonthOfYear() != month) d = d.plusWeeks(1);
return d.plusWeeks(nthweek-1);
}
public static LocalDate getLastWeekdayOfMonth(int dayweek,int month,int year) {
LocalDate d = new LocalDate(year, month, 1).plusMonths(1).withDayOfWeek(dayweek);
if(d.getMonthOfYear() != month) d = d.minusWeeks(1);
return d;
}
public static void main(String[] args) {
// second wednesday of oct-2011
LocalDate d = getNDayOfMonth( DateTimeConstants.WEDNESDAY, 2, 10, 2011);
System.out.println(d);
// last wednesday of oct-2011
LocalDate dlast = getLastWeekdayOfMonth( DateTimeConstants.WEDNESDAY, 10, 2011);
System.out.println(dlast);
}
Edit: Since Java 8 (2014) the new Date API (package java.time), which is inspired by/similar to Jodatime, should be preferred.
The following code was successfully tested for all holidays in 2013 and 2014. I realize that this doesn't really answer the original question, but I think it might be useful for people who come across this post in hopes of figuring out how to work with holidays using Calendar.
public static boolean isMajorHoliday(java.util.Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// check if New Year's Day
if (cal.get(Calendar.MONTH) == Calendar.JANUARY
&& cal.get(Calendar.DAY_OF_MONTH) == 1) {
return true;
}
// check if Christmas
if (cal.get(Calendar.MONTH) == Calendar.DECEMBER
&& cal.get(Calendar.DAY_OF_MONTH) == 25) {
return true;
}
// check if 4th of July
if (cal.get(Calendar.MONTH) == Calendar.JULY
&& cal.get(Calendar.DAY_OF_MONTH) == 4) {
return true;
}
// check Thanksgiving (4th Thursday of November)
if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER
&& cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 4
&& cal.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
return true;
}
// check Memorial Day (last Monday of May)
if (cal.get(Calendar.MONTH) == Calendar.MAY
&& cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
&& cal.get(Calendar.DAY_OF_MONTH) > (31 - 7) ) {
return true;
}
// check Labor Day (1st Monday of September)
if (cal.get(Calendar.MONTH) == Calendar.SEPTEMBER
&& cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 1
&& cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
return true;
}
// check President's Day (3rd Monday of February)
if (cal.get(Calendar.MONTH) == Calendar.FEBRUARY
&& cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3
&& cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
return true;
}
// check Veterans Day (November 11)
if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER
&& cal.get(Calendar.DAY_OF_MONTH) == 11) {
return true;
}
// check MLK Day (3rd Monday of January)
if (cal.get(Calendar.MONTH) == Calendar.JANUARY
&& cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3
&& cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
return true;
}
return false;
}
I do not know the "easy" way but I can suggest you the following.
Set calendar to the first day of the month.
Retrieve its day of the week
Calculate the date of the first Monday of the month.
Add 14 days using calendar.add() method. You will get the third Monday.
tl;dr
LocalDate thirdMondayInFebruary2012 =
YearMonth.of( 2012 , Month.FEBRUARY )
.atDay( 1 )
.with( TemporalAdjusters.dayOfWeekInMonth( 3 , DayOfWeek.MONDAY ) );
…and…
LocalDate lastMondayInMay2012 =
YearMonth.of( 2012 , Month.MAY )
.atDay( 1 );
.with( TemporalAdjusters.lastInMonth( DayOfWeek.MONDAY ) );
java.time
Very easy to do using the java.time classes that now supplant both Joda-Time and the troublesome old date-time classes bundled with the earliest versions of Java.
First we need to specify the desired month. The YearMonth class can do that. From there we get a LocalDate, a date without a time-of-day and without a time zone.
YearMonth ym = YearMonth.of( 2012 , Month.FEBRUARY ); // Or pass '2' for 'February'.
LocalDate ld = ym.atDay( 1 );
The TemporalAdjuster interface provides for adjusting a date-time value into another date-time value. Implementations provided by the TemporalAdjusters class (notice the plural 's'). Specify a day of week using the handy DayOfWeek enum.
int ordinal = 3 ; // Use '3' for 'third occurrence in month' such as '3rd Monday'.
LocalDate thirdMondayInFebruary2012 = ld.with( TemporalAdjusters.dayOfWeekInMonth( ordinal , DayOfWeek.MONDAY ) );
Tip: Rather than pass mere integers for year and month across your code base, pass objects such as YearMonth, Year, Month, and DayOfWeek. Doing so eliminates ambiguity, makes your code more self-documenting, provides types-safety, and ensures valid values.
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, 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 (<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.
All you need is a loop:
public class CalculateDate {
public static void main( String ... args ) {
Calendar c = Calendar.getInstance();
c.set( Calendar.YEAR, 2012 );
c.set( Calendar.MONTH , Calendar.MAY);
c.set( Calendar.DAY_OF_MONTH, 0 );
c.add( Calendar.DAY_OF_MONTH, -1 );
System.out.println( c.getTime() );
int mondaysCount = 0;
while ( mondaysCount != 4 ) {
c.add( Calendar.DAY_OF_MONTH, 1 );
if ( c.get( Calendar.DAY_OF_WEEK ) == Calendar.MONDAY ) {
mondaysCount++;
}
}
System.out.printf( "The fourth monday of may is %s", c.getTime() );
}
}
Any chances you are using Quartz scheduler?
public Date date(String cronExpression) {
return new org.quartz.CronExpression(cronExpression).
getNextValidTimeAfter(new Date(0));
}
System.out.println(date("0 0 0 ? May Thu#3 2015"));
System.out.println(date("0 0 0 ? Jun Mon#1 2050"));
System.out.println(date("0 0 0 ? Dec Tue#4 2012"));
System.out.println(date("0 0 0 ? Jul Wed#2 2000"));
This simple code prints correct (?) results:
Thu May 21 00:00:00 CEST 2015
Mon Jun 06 00:00:00 CEST 2050
Tue Dec 25 00:00:00 CET 2012
Wed Jul 12 00:00:00 CEST 2000
The required CronExpression doesn't have any dependencies on the rest of Quartz, so you might consider copying it to your project (watch out for license!)
Side note: the internal implementation of getNextValidTimeAfter() is 400 lines of code...
public String nDow(int year, int month, int nweek, int nday)
{
Calendar cdt = Calendar.getInstance();
cdt.set(year, month -1, 1);
return year + "-" + month + "-" + (getPosOfWeekday(cdt.get(Calendar.DAY_OF_WEEK), nday) + ((nweek - 1) *7));
}
private int getPosOfWeekday(int startday, int nday)
{
nday = weekDayValue(nday);
return constructCircularArray(startday).indexOf(nday) + 1;
}
private ArrayList<Integer> constructCircularArray(int weekday)
{
ArrayList<Integer> circularArray = new ArrayList<Integer>();
for(int i = 0; i < 7; i++)
{
circularArray.add(i, weekDayValue(weekday++));
}
return circularArray;
}
private int weekDayValue(int x)
{
return ((x-1) % 7) + 1;
}
Here is an alternative. What it does is: Get which week you want (n), and the other parameters, and return the date of the day in that week. Since Calendar gives the date of the previous month (for example 29th of February instead of 7th of March, since the 1st week of March collides with last week of Feb), the function computes the 2nd week if the date goes beyond 7 or multiples of it for each week thereof. Hope that helps.
public static int getNthWeekDay (int n, int day, int month, int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, day);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.WEEK_OF_MONTH,n);
calendar.set(Calendar.YEAR, year);
if (calendar.get(Calendar.DATE) > n * 7) {
calendar.set(Calendar.DAY_OF_WEEK,day);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.WEEK_OF_MONTH,day+1);
}
return calendar.get(Calendar.DATE);
}

Categories