How to recreate compareTo method in java? - java

How does the compareTo() method for Dates work here in java? I know that when you compare two dates the result will always be 0 if equal, 1 if the date being
compared inside the compareTo() parameter is older, and -1 if the date inside the parameter is more recent.
//Just an example
String[] da = {"01/14/1975", "08/20/1975", "08/20/1975"};
SimpleDateFormat f = new SimpleDateFormat("MM/dd/yyyy");
Date d1 = new Date();
Date d2 = new Date();
//this outputs 1 because d2 is older than d1
d1 = f.parse(da[1]);
d2 = f.parse(da[0]);
System.out.println(d1.compareTo(d2));
//this outputs 0 because dates are the same
d1 = f.parse(da[1]);
d2 = f.parse(da[2]);
System.out.println(d1.compareTo(d2));
//this outputs -1 because d2 is more recent than d1
d1 = f.parse(da[0]);
d2 = f.parse(da[1]);
System.out.println(d1.compareTo(d2));
Now I want to compare dates without using compareTo() method or any built-in method in java. As much as possible I want to use just the basic operators in java.
What is the computation or the algorithm of the compareTo() method in comparing dates that enable it to return -1, 0, and 1?
Edit:
In the case at the sample problem at my book, using java.util.Date is forbidden, what is supposed to be done is to create your own date object like this:
public class DatesObj
{
protected int day, month, year;
public DatesObj (int mm, int dd, int yyyy) {
month = mm;
day = dd;
year = yyyy;
}
public int getMonth() { return month; }
public int getDay() { return day; }
public int getYear() { return year; }
}
Now how do I compare this as if like they're int and determine which is old and which is newer??

If you want to compare two dates just as if they were just plain-old integers, you must first turn each date into a plain-old integer. The easiest way to turn a year/month/day representation of a date into a plain-old integer, that can be effectively compared with plain-old integers from other dates, is to line the pieces up in exactly that order: year first, month next, day last:
// in DateObj class....
public int getDateInt() {
return (yyyy * 10000) + (mm * 100) + dd;
}
So for March 19, 2019, you get 20190319, and for December 7, 1941 you get 19411207; by comparing the "integerized" versions of the dates you can see that:
19411207 < 20190319, just as December 7, 1941 is earlier than March 19, 2019;
20190319 > 19411207, just as March 19, 2019 is later than December 7, 1941;
19411207 != 20190319, just as December 7, 1941 and March 19, 2019 are different dates
You're limited to dates within the Common Era and no more than about 200,000 years into the future with this particular implementation. But with a little tweaking, you could easily easily handle dates outside these ranges, an exercise that I will, as the textbooks so often say, leave as an exercise for the reader.

Implement Comparable and override compareTo().
class DatesObj implements Comparable<DatesObj>{
protected int day, month, year;
public DatesObj(int mm, int dd, int yyyy) {
month = mm;
day = dd;
year = yyyy;
}
public int getMonth() {
return month;
}
public int getDay() {
return day;
}
public int getYear() { return year; }
#Override
public int compareTo(DatesObj o) {
int diff = this.year - o.year;
if(diff != 0) {
return diff;
}
diff = this.month - o.month;
if(diff != 0) {
return diff;
}
return this.day - o.day;
}
}

Compare the years. If the years of both the dates are same, compare the months.
If the months are same, compare the dates.
public int compareDate(DatesObj d) {
if (this.year != d.year) {
if (this.year > d.year)
return 1;
else
return -1;
}
if (this.month != d.month) {
if (this.month > d.month)
return 1;
else
return -1;
}
if (this.day != d.day) {
if (this.day > d.day)
return 1;
else
return -1;
}
return 0;
}

Ref : https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html
Ref : https://developer.android.com/reference/java/util/Calendar
create own class with Interface Comparable
class DateCompare implements Comparable<Date>
{
protected int day, month, year;
public DateCompare(int mm, int dd, int yyyy) {
month = mm;
day = dd;
year = yyyy;
}
#Override
public int compareTo(Date o) {
Calendar cal = Calendar.getInstance();
cal.setTime(o);
int diff = this.year - cal.get(Calendar.YEAR);
if(diff != 0) {
return diff;
}
diff = this.month - cal.get(Calendar.MONTH);
if(diff != 0) {
return diff;
}
return this.day - cal.get(Calendar.DAY_OF_MONTH);
}
public int getMonth() {
return month;
}
public int getDay() {
return day;
}
public int getYear() { return year; }
}
And Other More Helpful
https://gist.github.com/Ashusolanki/fed3b6a680092985ac0ab93ed70fcd7c
private String postTime(Date date)
{
long postTime = date.getTime();
long atTime = System.currentTimeMillis();
long diff = atTime - postTime;
long sec = TimeUnit.SECONDS.convert(diff, TimeUnit.MILLISECONDS);
if (sec >= 60) {
long minit = TimeUnit.MINUTES.convert(diff, TimeUnit.MILLISECONDS);
if (minit >= 60) {
long hours = TimeUnit.HOURS.convert(diff, TimeUnit.MILLISECONDS);
if (hours >= 24) {
long days = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
return days + " Days Ago";
} else {
return hours + " Hours Ago";
}
} else {
return minit + " Minutes Ago";
}
} else {
return sec + " Secounds Ago";
}
}

Related

How to fix date in Gregorian Calendar

I want to fix the date to month/day/year in my class (Gregorian Calendar) so it works with my tester program. I get errors when running my tester program, I think it has to do with my string toString() method but I have tried to fix it but keep getting errors. I do not understand how having my string output to month + day + year would not work correctly in outputting mmmm/dd/yyyy. Thank you for your help.
Errors:
Exception in thread "main" java.lang.IllegalArgumentException
at Date.<init>(Date.java:15)
at Assign8B.main(Assign8B.java:14)
Class
public class Date {
private int day, month, year;
public Date() {
this.day = 1;
this.month = 1;
this.year = 1970;
}
public Date(int year, int month, int day) {
if (year < 1582) {
throw new IllegalArgumentException();
} else if (month <= 0 && month > 12) {
throw new IllegalArgumentException();
} else if (!isLeapYear(year) && (month == 2 && day == 29)) {
throw new IllegalArgumentException();
} else {
this.day = day;
this.month = month;
this.year = year;
}
}
public void addDays(int days) {
int[] daysOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int step = 1;
if(days < 0)
step = -1;
if(isLeapYear(year))
daysOfMonth[1] = 29;
int d = 0;
while(d < days){
d++;
day += step;
if(day > daysOfMonth[month-1]){
day = 1;
month++;
if(month > 12){
year++;
month = 1;
if(isLeapYear(year))
daysOfMonth[1] = 29;
else
daysOfMonth[1] = 28;
}
}
else if(day < 1) {
month--;
if(month == 0) {
month = 12;
year--;
if(isLeapYear(year))
daysOfMonth[1] = 29;
else
daysOfMonth[1] = 28;
}
day = daysOfMonth[month-1];
}
}
}
public void addWeeks(int weeks) {
addDays(weeks * 7);
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public boolean isLeapYear() {
return isLeapYear(this.year);
}
public boolean isLeapYear(int year) {
return(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0));
}
public int daysTo(Date other) {
int days = 0;
int d1, m1, y1, d2, m2, y2;
int sign = 1;
if(this.toString().compareTo(other.toString()) > 0){
d1 = other.day;
m1 = other.month;
y1 = other.year;
d2 = day;
m2 = month;
y2 = year;
sign = -1;
} else {
d1 = day;
m1 = month;
y1 = year;
d2 = other.day;
m2 = other.month;
y2 = other.year;
}
int[] daysOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(isLeapYear(y1))
daysOfMonth[1] = 29;
while(d1 != d2 || m1 != m2 || y1 != y2){
days++;
d1++;
if(d1 > daysOfMonth[m1-1]){
d1 = 1;
m1++;
if(m1 > 12){
y1++;
m1 = 1;
if(isLeapYear(y1))
daysOfMonth[1] = 29;
else
daysOfMonth[1] = 28;
}
}
}
days = days * sign;
return days;
}
public String longDate() {
String[] months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
return months[month-1] + " " + day + ", " + year;
}
public String toString() {
String s = month + "/" + day + "/" + year;
return s;
}
public static int daysTo(Date one, Date two) {
return one.daysTo(two);
}
}
Tester Program
public class Assign8B {
// Part of the main method I'll use to test your class
// NO imports allowed from the JAVA API
public static void main(String[] a) {
Date one = new Date(10,15,1582); // start of Gregorian
Date two = new Date(1,28,2020); // 2020 is a leap year
one.addDays(1); // advance one day (negative subtracts days)
one.addWeeks(10); // advance one week (negative allowed, yes)
System.out.println(two.daysTo(one)); // -159645 days (negative)
System.out.println(one.getDay()); // day is now the 25th (advanced)
System.out.println(one.getMonth()); // returns 12, January is 1
System.out.println(one.getYear()); // still 1582 from start
System.out.println(one.isLeapYear()); // false for 1582
System.out.println(one.toString()); // style is 12/25/1582
try {
Date three = new Date(12,33,1956); // obviously illegal
Date four = new Date(2,29,2013); // illegal leap year
three.setDay(31); // fixes that day of month, OK
four.setMonth(3); // fixes the month, year still wrong
four.setYear(1929); // fixes the year, code not reached
} catch (IllegalArgumentException e) {
System.out.println("Illegal day attempted");
}
// Use UNIX zero of 01/01/70 for default, and create "longDate" output
// I thought a long date was dinner with a person you don't like?
Date five = new Date();
System.out.println(five.longDate()); // January 1, 1970
// Finally, let's understand what static methods are most commonly used for:
System.out.println(Date.daysTo(one, two)); // still 159645 days (positive)
}
}
As #madprogrammer mentioned in the comments, you have to change your Date call because of the order of year month day in your own class constructor, and then look at your add days function and change how you add years in your code.

Is their any simplified Java to find palindome dates between year 0000 and 9999?

import java.util.Arrays;
public class PalindromeDates {
static final int STARTINGYEAR = 0000;
static final int ENDINGYEAR = 9999;
public static void main(String[] args) {
int year, month, date;
int dateArray[];
boolean flag;
System.out.println(" Date --> Array Format\n");
for (year = STARTINGYEAR; year <= ENDINGYEAR; year++) {
for (month = 01; month <= 12; month++) {
for (date = 1; date <= 31; date++) {
if (checkValidDate(year, date, month)) {
dateArray = createDateArray(date, month, year);
flag = checkPalindrome(dateArray);
if (flag) {
System.out.print(year + "." + month + "." + date + " --> ");
System.out.println(Arrays.toString(dateArray));
}
}
}
}
}
}
public static int[] createDateArray(int date, int month, int year) { //Inserting the whole date to an array
int dateArray[] = new int[8];
dateArray[0] = year / 1000;
year = year % 1000;
dateArray[1] = year / 100;
year = year % 100;
dateArray[2] = year / 10;
dateArray[3] = year % 10;
dateArray[4] = month / 10;
dateArray[5] = month % 10;
dateArray[6] = date / 10;
dateArray[7] = date % 10;
return dateArray;
}
public static boolean checkPalindrome(int dateArray[]) {
for (int i = 0; i <= 3; i++) {
if (dateArray[i] == dateArray[7 - i]) {
} else {
return false;
}
}
return true;
}
public static boolean checkValidDate(int year, int month, int date) {
if (month == 2 && date == 30)
return false;
if ((month == 2 || month == 4 || month == 6 || month == 9 || month == 11) && (date == 31)) {
return false;
}
if ((month == 2) && (date == 29))
return (checkLeapYear(year));
return true;
}
public static boolean checkLeapYear(int year) {
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0)
return true;
else
return false;
} else
return true;
} else {
return false;
}
}
}
This program is written by me to find the palindrome dates since 0000 to 9999. Is their any simplifies program to do this?. What are the modifications for this code? And I want to know whether my leap year finding code is correct.
There is a method called createDateArray(). It is used to put the integer digits in year, month, date to an array. Is there any simple method to do that?
I am inferring from your code that a palindrome date is a date that formatted into yyyyMMdd format is a palindrome string. For example the day before yesterday, February 2, 2020, was a palindrome date because it’s formatted into 20200202, a palindrome.
Is their any simplifies program to do this? …
Yes there is. See below.
… And I want to know whether my leap year finding code is correct.
Yes, it is correct. I have tested its result against the result of Year.of(y).isLeap() for y ranging from 0 through 9999.
And the issue you didn’t ask about: as jrook hinted in a comment, beware of octal numbers.
static final int STARTINGYEAR = 0000;
While this works in this case, it works for reasons that I am afraid that you don’t fully understand. You will get surprises if some day you try 0500 for year 500 and get 320, or you use 0008 for year 8 and get a compile time error. When a Java integer literal begins with 0 (and has more digits following it), it is an octal number, not a number in the decimal number system. So in your code you should use 0 for the year that you want printed as 0000:
static final int STARTINGYEAR = 0;
java.time
On one side Andreas is correct in the other answer that this goes a lot more smoothly when using the date classes that are built into Java. On the other side the Calendar class used in that answer is poorly designed and long outdated. So I recommend we don’t use it and instead present a solution using java.time, the modern Java date and time API.
List<LocalDate> palindromeDates = Arrays.stream(Month.values())
.flatMap(m -> IntStream.rangeClosed(1, m.length(true)).mapToObj(d -> MonthDay.of(m, d)))
.map(md -> md.atYear(reverseStringToInt(md.format(monthDayFormatter))))
.sorted()
.collect(Collectors.toList());
palindromeDates.forEach(ld -> System.out.println(ld.format(dateFormatter)));
This code uses a few auxiliaries:
private static DateTimeFormatter monthDayFormatter = DateTimeFormatter.ofPattern("MMdd");
private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuuMMdd");
private static int reverseStringToInt(String s) {
StringBuilder buf = new StringBuilder(s);
buf.reverse();
return Integer.parseInt(buf.toString());
}
Excerpt from the output:
01011010
01100110
01111110
01200210
…
20111102
20200202
20211202
…
92800829
92900929
The algorithm idea is stolen from Andreas’ answer since it is so well thought.
Link
Oracle tutorial: Date Time explaining how to use java.time.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuuMMdd");
for (LocalDate d = LocalDate.of(0, 1, 1); d.isBefore(LocalDate.of(10000, 1, 1)); d = d.plusDays(1)) {
String dateString = dateFormatter.format(d);
if (dateString.equals(new StringBuilder(dateString).reverse().toString())) {
System.out.println(d);
}
}
Since the year can be any 4-digit year, there is no constraint there, so just go through all 3661 MMdd values of a year, reverse it and use as the year.
1) Since the leap date of 0229 reversed is 9220, it is a leap year, and hence a valid palindrome date.
As code, using Calendar, in year order:
List<String> palimdromeDates = new ArrayList<>();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"/*No DST*/));
cal.clear();
cal.set(2000/*Leap Year*/, Calendar.JANUARY, 1);
for (; cal.get(Calendar.YEAR) == 2000; cal.add(Calendar.DAY_OF_YEAR, 1)) {
int day = cal.get(Calendar.DAY_OF_MONTH);
int month = cal.get(Calendar.MONTH) + 1;
int year = 0; // Calculate: year = reverse(MMdd)
for (int i = 0, n = month * 100 + day; i < 4; i++, n /= 10)
year = year * 10 + n % 10;
palimdromeDates.add(String.format("%04d-%02d-%02d", year, month, day));
}
Collections.sort(palimdromeDates); // Sort by year
for (String date : palimdromeDates)
System.out.println(date);
Note that this code only loops 366 times, and does not create any unnecessary String objects or other type of objects, so it is very fast, and generates minimum garbage.
Output
0101-10-10
0110-01-10
0111-11-10
0120-02-10
0121-12-10
0130-03-10
0140-04-10
0150-05-10
0160-06-10
0170-07-10
0180-08-10
0190-09-10
0201-10-20
0210-01-20
0211-11-20
0220-02-20
0221-12-20
0230-03-20
0240-04-20
0250-05-20
0260-06-20
0270-07-20
0280-08-20
0290-09-20
0301-10-30
0310-01-30
0311-11-30
0321-12-30
0330-03-30
0340-04-30
0350-05-30
0360-06-30
0370-07-30
0380-08-30
0390-09-30
1001-10-01
1010-01-01
1011-11-01
1020-02-01
1021-12-01
1030-03-01
1040-04-01
1050-05-01
1060-06-01
1070-07-01
1080-08-01
1090-09-01
1101-10-11
1110-01-11
1111-11-11
1120-02-11
1121-12-11
1130-03-11
1140-04-11
1150-05-11
1160-06-11
1170-07-11
1180-08-11
1190-09-11
1201-10-21
1210-01-21
1211-11-21
1220-02-21
1221-12-21
1230-03-21
1240-04-21
1250-05-21
1260-06-21
1270-07-21
1280-08-21
1290-09-21
1301-10-31
1310-01-31
1321-12-31
1330-03-31
1350-05-31
1370-07-31
1380-08-31
2001-10-02
2010-01-02
2011-11-02
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12
2150-05-12
2160-06-12
2170-07-12
2180-08-12
2190-09-12
2201-10-22
2210-01-22
2211-11-22
2220-02-22
2221-12-22
2230-03-22
2240-04-22
2250-05-22
2260-06-22
2270-07-22
2280-08-22
2290-09-22
3001-10-03
3010-01-03
3011-11-03
3020-02-03
3021-12-03
3030-03-03
3040-04-03
3050-05-03
3060-06-03
3070-07-03
3080-08-03
3090-09-03
3101-10-13
3110-01-13
3111-11-13
3120-02-13
3121-12-13
3130-03-13
3140-04-13
3150-05-13
3160-06-13
3170-07-13
3180-08-13
3190-09-13
3201-10-23
3210-01-23
3211-11-23
3220-02-23
3221-12-23
3230-03-23
3240-04-23
3250-05-23
3260-06-23
3270-07-23
3280-08-23
3290-09-23
4001-10-04
4010-01-04
4011-11-04
4020-02-04
4021-12-04
4030-03-04
4040-04-04
4050-05-04
4060-06-04
4070-07-04
4080-08-04
4090-09-04
4101-10-14
4110-01-14
4111-11-14
4120-02-14
4121-12-14
4130-03-14
4140-04-14
4150-05-14
4160-06-14
4170-07-14
4180-08-14
4190-09-14
4201-10-24
4210-01-24
4211-11-24
4220-02-24
4221-12-24
4230-03-24
4240-04-24
4250-05-24
4260-06-24
4270-07-24
4280-08-24
4290-09-24
5001-10-05
5010-01-05
5011-11-05
5020-02-05
5021-12-05
5030-03-05
5040-04-05
5050-05-05
5060-06-05
5070-07-05
5080-08-05
5090-09-05
5101-10-15
5110-01-15
5111-11-15
5120-02-15
5121-12-15
5130-03-15
5140-04-15
5150-05-15
5160-06-15
5170-07-15
5180-08-15
5190-09-15
5201-10-25
5210-01-25
5211-11-25
5220-02-25
5221-12-25
5230-03-25
5240-04-25
5250-05-25
5260-06-25
5270-07-25
5280-08-25
5290-09-25
6001-10-06
6010-01-06
6011-11-06
6020-02-06
6021-12-06
6030-03-06
6040-04-06
6050-05-06
6060-06-06
6070-07-06
6080-08-06
6090-09-06
6101-10-16
6110-01-16
6111-11-16
6120-02-16
6121-12-16
6130-03-16
6140-04-16
6150-05-16
6160-06-16
6170-07-16
6180-08-16
6190-09-16
6201-10-26
6210-01-26
6211-11-26
6220-02-26
6221-12-26
6230-03-26
6240-04-26
6250-05-26
6260-06-26
6270-07-26
6280-08-26
6290-09-26
7001-10-07
7010-01-07
7011-11-07
7020-02-07
7021-12-07
7030-03-07
7040-04-07
7050-05-07
7060-06-07
7070-07-07
7080-08-07
7090-09-07
7101-10-17
7110-01-17
7111-11-17
7120-02-17
7121-12-17
7130-03-17
7140-04-17
7150-05-17
7160-06-17
7170-07-17
7180-08-17
7190-09-17
7201-10-27
7210-01-27
7211-11-27
7220-02-27
7221-12-27
7230-03-27
7240-04-27
7250-05-27
7260-06-27
7270-07-27
7280-08-27
7290-09-27
8001-10-08
8010-01-08
8011-11-08
8020-02-08
8021-12-08
8030-03-08
8040-04-08
8050-05-08
8060-06-08
8070-07-08
8080-08-08
8090-09-08
8101-10-18
8110-01-18
8111-11-18
8120-02-18
8121-12-18
8130-03-18
8140-04-18
8150-05-18
8160-06-18
8170-07-18
8180-08-18
8190-09-18
8201-10-28
8210-01-28
8211-11-28
8220-02-28
8221-12-28
8230-03-28
8240-04-28
8250-05-28
8260-06-28
8270-07-28
8280-08-28
8290-09-28
9001-10-09
9010-01-09
9011-11-09
9020-02-09
9021-12-09
9030-03-09
9040-04-09
9050-05-09
9060-06-09
9070-07-09
9080-08-09
9090-09-09
9101-10-19
9110-01-19
9111-11-19
9120-02-19
9121-12-19
9130-03-19
9140-04-19
9150-05-19
9160-06-19
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

check if given date time is in scope (+/- 1 hours) of current date time

I have a given date, with the format dd. MMMM yyyy HH:mm 'Uhr'
Now I want to check this date with the current date, checking if its in the scope of +1 hour and -1 hour of the current date time, when its in this scope, the if condition should be statisfied.
I would appreciate it, when someone could help me!
Btw, I have no opportunity to use JODA.
Eric posted in another answer: Here's the link for credit. A rather simple method that get's the time apart using the Calendar class. If anything you can pick it apart to learn a bit about getting the differences between two times.
public static int hoursAgo(String datetime) {
Calendar date = Calendar.getInstance();
date.setTime(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.ENGLISH).parse(datetime)); // Parse into Date object
Calendar now = Calendar.getInstance(); // Get time now
long differenceInMillis = now.getTimeInMillis() - date.getTimeInMillis();
long differenceInHours = (differenceInMillis) / 1000L / 60L / 60L; // Divide by millis/sec, secs/min, mins/hr
return (int)differenceInHours;
}
DateFormat format = new SimpleDateFormat("dd. MM yyyy HH:mm");
String dateString= "16. 10 2015 11:05";
Date date = format.parse(dateString);
private static boolean DateInScope(Date date) {
Date currentTime = new Date();
long hours = TimeUnit.MILLISECONDS.toHours(currentTime.getTime());
long hours2 = TimeUnit.MILLISECONDS.toHours(date.getTime());
return hours - 1 == hours2 || hours + 1 == hours2;
}
May be the following method could help you.
public static String getDiffBtwnDates(Date date1, Date date2){
long date1InMillis = date1.getTime();
long date2InMillis;
if (date2==null){
date2InMillis = System.currentTimeMillis();
}else{
date2InMillis = date2.getTime();
}
long dateDiffInMillis = date2InMillis-date1InMillis;
StringBuffer sTimeSince = new StringBuffer("");
if(dateDiffInMillis > YEAR){
if(dateDiffInMillis/YEAR>1){
sTimeSince.append(dateDiffInMillis / YEAR).append(" Years ");
dateDiffInMillis %= YEAR;
}else {
sTimeSince.append(dateDiffInMillis / YEAR).append(" Year ");
dateDiffInMillis %= YEAR;
}
}
if (dateDiffInMillis > DAY) {
if(dateDiffInMillis/DAY > 1){
sTimeSince.append(dateDiffInMillis / DAY).append(" Days ");
dateDiffInMillis %= DAY;
}else {
sTimeSince.append(dateDiffInMillis / DAY).append(" Day ");
dateDiffInMillis %= DAY;
}
}
if (dateDiffInMillis > HOUR) {
if(dateDiffInMillis/HOUR>1){
sTimeSince.append(dateDiffInMillis / HOUR).append(" Hrs ");
dateDiffInMillis %= HOUR;
}else{
sTimeSince.append(dateDiffInMillis / HOUR).append(" Hr ");
dateDiffInMillis %= HOUR;
}
}
if (dateDiffInMillis > MINUTE) {
if (dateDiffInMillis / MINUTE > 1) {
sTimeSince.append(dateDiffInMillis / MINUTE).append(" Mins ");
dateDiffInMillis %= MINUTE;
} else {
sTimeSince.append(dateDiffInMillis / MINUTE).append(" Min ");
dateDiffInMillis %= MINUTE;
}
}
if (dateDiffInMillis > SECOND) {
sTimeSince.append(dateDiffInMillis / SECOND).append(" Sec ");
dateDiffInMillis %= SECOND;
}
sTimeSince.append(dateDiffInMillis + " ms");
sTimeSince.toString();
return sTimeSince.toString();
}
Here is a very simple method that does the exact comparison you need, i did some tests and it seems to work:
package test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class TestDateDiff {
public static void main(String[] args) throws Exception {
if (isWhitinOneHOur("16. October 2015 16:30")) {
System.out.println("Date OK");
} else {
System.out.println("Date KO");
}
}
public static boolean isWhitinOneHOur(String dateAsStr) throws Exception {
SimpleDateFormat sdf= new SimpleDateFormat("dd. MMMM yyyy HH:mm", Locale.US);
Date date=sdf.parse(dateAsStr);
Date now=new Date();
long oneHour=1000*60*60;
if ((now.getTime()+oneHour)>=date.getTime() && (now.getTime()-oneHour)<=date.getTime()) {
return true;
} else {
return false;
}
}
}

Count days between two dates with Java 8 while ignoring certain days of week

Below I have 3 methods. The first is very simple. It just counts the total number of days. The second, however, will not only count the days, but will ignore the days of the week that are passed in to the method.
My problem is that the third method is not always correct. It should match the second method. I am guessing it has something to do with leap years, because the difference is usually +=3|4 when it is incorrect.
Additional Info
I am attempting to mock Excel's weekday(serial_number,[return_type]) formula in a way.
serial_number = startDate:Date - daysOfWeekToInclude:Array<Integer>
Example
| A | B | C
+---------+----------------------------------------------------+-----------
1 | Start | =DATE(2014,9,7) | 9/7/2014
2 | End | =DATE(2025,6,13) | 6/13/2025
3 | Include | ={1,2,4,6} (Mon, Tue, Thu, & Sat) | <Disp Only>
4 | Days | =SUM(INT((WEEKDAY($B$1-{1,2,4,6},1)+$B$2-$B$1)/7)) | 2248
There is more information on this function here: How to count / calculate the number of days between two dates in Excel?
Raw Image
Methods
Simply count the number of days between two dates.
public static int simpleDaysBetween(final LocalDate start,
final LocalDate end) {
return (int) ChronoUnit.DAYS.between(start, end);
}
Count number of days, ignoring certain days of week, using a loop.
public static int betterDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int count = 0;
LocalDate curr = start.plusDays(0);
while (curr.isBefore(end)) {
if (!ignore.contains(curr.getDayOfWeek())) {
count++;
}
curr = curr.plusDays(1); // Increment by a day.
}
return count;
}
Count number of days. again but without a loop.
public static int bestDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int days = simpleDaysBetween(start, end);
if (days == 0) {
return 0;
}
if (!ignore.isEmpty()) {
int weeks = days / 7;
int startDay = start.getDayOfWeek().getValue();
int endDay = end.getDayOfWeek().getValue();
int diff = weeks * ignore.size();
for (DayOfWeek day : ignore) {
int currDay = day.getValue();
if (startDay <= currDay) {
diff++;
}
if (endDay > currDay) {
diff++;
}
}
if (endDay > startDay) {
diff -= endDay - startDay;
}
return days - diff;
}
return days;
}
Full code
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
public class DayCounter {
public static void main(String[] args) {
final LocalDate start = LocalDate.of(2014, 9, 7);
final LocalDate end = LocalDate.of(2025, 6, 13);
List<DayOfWeek> ignore = Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY);
print(start);
print(end);
System.out.println(simpleDaysBetween(start, end));
System.out.println(betterDaysBetween(start, end, ignore));
System.out.println(bestDaysBetween(start, end, ignore));
}
public static void print(LocalDate date) {
System.out.printf("%s -> %s%n", date, date.getDayOfWeek());
}
public static int simpleDaysBetween(final LocalDate start,
final LocalDate end) {
return (int) ChronoUnit.DAYS.between(start, end);
}
public static int betterDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int count = 0;
LocalDate curr = start.plusDays(0);
while (curr.isBefore(end)) {
if (!ignore.contains(curr.getDayOfWeek())) {
count++;
}
curr = curr.plusDays(1); // Increment by a day.
}
return count;
}
public static int bestDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int days = simpleDaysBetween(start, end);
if (days == 0) {
return 0;
}
if (!ignore.isEmpty()) {
int weeks = days / 7;
int startDay = start.getDayOfWeek().getValue();
int endDay = end.getDayOfWeek().getValue();
int diff = weeks * ignore.size();
for (DayOfWeek day : ignore) {
int currDay = day.getValue();
if (startDay <= currDay) {
diff++;
}
if (endDay > currDay) {
diff++;
}
}
if (endDay > startDay) {
diff -= endDay - startDay;
}
return days - diff;
}
return days;
}
}
If we talk about a Java 8 API, why not use the Java 8 features consequently…
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return Stream.iterate(start, d->d.plusDays(1))
.limit(start.until(end, ChronoUnit.DAYS))
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
Starting with Java 9, we can use the even simpler
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
Though, it might be worth using a Set with a better-than-linear lookup rather than the List:
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
if(ignore.isEmpty()) return start.until(end, ChronoUnit.DAYS);
EnumSet<DayOfWeek> set = EnumSet.copyOf(ignore);
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
You may consider changing the parameter to Set<DayOfWeek>, as it is not only more efficient but better suited to the actual use cases. Instead of Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY), you can pass EnumSet.of(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY), but you can also use constructs like EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY), to denote the typical working days.
You can avoid iterating over all days, but it requires special care about corner cases and hence, thorough testing. And will only pay off for really large ranges. For completeness, this is the optimized variant:
static long daysBetween(LocalDate start, LocalDate end, Set<DayOfWeek> ignore) {
long d1 = start.toEpochDay(), d2 = end.toEpochDay();
if(d1 > d2) throw new IllegalArgumentException();
if(ignore.isEmpty()) return d2 - d1;
int incompleteWeek = 0;
DayOfWeek startDoW = start.getDayOfWeek(), endDoW = end.getDayOfWeek();
if(startDoW != endDoW) {
for(int v1 = startDoW.getValue(), v2 = endDoW.getValue();
v1 != v2 && d1 < d2; v1 = v1%7+1, d1++) {
if(!ignore.contains(DayOfWeek.of(v1))) incompleteWeek++;
}
}
return incompleteWeek + (d2 - d1) * (7 - ignore.size()) / 7;
}
Here, the performance of the ignore set’s lookup doesn’t matter, as we only look up at most six values, however, enforcing a Set, i.e. no duplicates, allows us to use the set’s size to calculate the number of days contained in complete weeks of the range. Complete weeks have the same day of week for the start and (exclusive) end date. So the code only needs to iterate the days, until the start and end day of week match.
You you are using wrong Excel formula. See the section "Using SUM and INT function to count the number of workdays" of the site that you have provided. It is stating the formula as:
=SUM(INT((WEEKDAY(A2-{2,3,4,5,6})+B2-A2)/7))
In Excel, Sunday is 1 and Saturday is 7. The numbers inside the curly braces indicates the day-of-weeks to be included. So for your case the formula will be:
=SUM(INT((WEEKDAY(A2-{2,3,5,7})+B2-A2)/7))
Please see the attached screenshot:
It is returning 2247 as the following code returns:
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class SO25798876 {
public static void main(String[] args) {
String strStartDate = "09/07/2014";
String strEndDate = "06/13/2025";
String pattern = "MM/dd/yyyy";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
LocalDate startDate = LocalDate.parse(strStartDate, formatter);
LocalDate endDate = LocalDate.parse(strEndDate, formatter);
int count = 0;
while(startDate.isBefore(endDate) || startDate.isEqual(endDate)) { // you may want to not to use the isEqual method
DayOfWeek dayOfWeek = startDate.getDayOfWeek();
if(!(dayOfWeek == DayOfWeek.SUNDAY || dayOfWeek == DayOfWeek.WEDNESDAY || dayOfWeek == DayOfWeek.FRIDAY)) {
count++;
}
startDate = startDate.plusDays(1);
}
System.out.println(count);
}
}
You also have mentioned your doubt that the java.time may be not considering leap year, which is wrong, if you add the following piece of code
long year = startDate.getYear();
if(Year.isLeap(year)) {
Month month = startDate.getMonth();
if(month == Month.FEBRUARY && startDate.getDayOfMonth() == 29) {
System.out.println("Calculated 29th Feb for the year: " + year);
}
}
You will see that it is printing:
Calculated 29th Feb for the year: 2016
Calculated 29th Feb for the year: 2020
Calculated 29th Feb for the year: 2024
Lastly the count will be 2247 which matches the Excel result.
Happy coding.
-Tapas

Using Java Dates, Given a year, I want a method that should return a list of dates representing a given day of the week, all 52 times

A method receives and integer representing a year and an integer representing a day of the week. The method should return a list of dates representing a given day of the week. For example, if the year is 2014 and the day of week is 2 then the method should return a list of dates representing all the Mondays in 2014.
public List<Date> getDatesforDayOfWeek(int year, int dayOfWeek) throws InvalidDateException
I'm not too sure what the best code would be. Any suggestions?
if (year <= 0) {
throw new InvalidDateException("Invalid year.");
}
if ((dayOfWeek < 1) || (dayOfWeek > 7)) {
throw new InvalidDateException("Invalid day.");
}
DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
Check this implementation that would work for non-leap years (and for leap years with some modification)
public List<Date> getDatesforDayOfWeek(int year, int dayOfWeek)
throws InvalidDateException {
if (year <= 0) {
throw new InvalidDateException("Invalid year.");
}
if ((dayOfWeek < 1) || (dayOfWeek > 7)) {
throw new InvalidDateException("Invalid day.");
}
List<Date> dates = new ArrayList<Date>();
// Start with the given inputs
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, Calendar.JANUARY);
int day = cal.get(Calendar.DAY_OF_WEEK);
while (day != dayOfWeek) {
cal.add(Calendar.DATE, 1);
day = cal.get(Calendar.DAY_OF_WEEK);
}
// Make this 366 for a leap year
for (int i = 0; i < 365; i += 7) {
if (cal.get(Calendar.DAY_OF_WEEK) == dayOfWeek
&& cal.get(Calendar.YEAR) == year) {
dates.add(cal.getTime());
cal.add(Calendar.DATE, 7);
}
}
return dates;
}
public static void main(String[] args) throws InvalidDateException {
for (Date date : new DateList().getDatesforDayOfWeek(2014, 4)) {
System.out.println(date);
}
}
}
class InvalidDateException extends Exception {
public InvalidDateException(String string) {
super(string);
}
private static final long serialVersionUID = 1L;
}
If I understand your question, I would use a Calendar to solve this problem (actually I'd first pick Joda-Time, but otherwise Calendar because there are a lot of corner cases to handle) -
public static List<Date> getDatesforDayOfWeek(int year, int dayOfWeek) {
List<Date> al = new ArrayList<>();
if (dayOfWeek >= 1 && dayOfWeek <= 7) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
while (cal.get(Calendar.DAY_OF_WEEK) != dayOfWeek) {
cal.add(Calendar.DAY_OF_MONTH, 1);
}
for (int i = 0; i < 52; i++) {
al.add(cal.getTime());
cal.add(Calendar.DAY_OF_MONTH, 7);
}
}
return al;
}
public static void main(String[] args) {
System.out.println(getDatesforDayOfWeek(2014, 2));
}
Output is (formatted, and 50 lines omitted, for display)
[Mon Jan 06 23:52:16 EST 2014,
...
Mon Dec 29 23:52:16 EST 2014]
Looking through all the answers they will provide you what you're looking for. Here is another approach I believe to be a little more efficient then the previous answers.
public static List<Date> GetDatesForDayOfWeek(int year, int dayOfWeek)
{
// Days in the week
final int DAYS_IN_WEEK = 7;
List<Date> dates = new ArrayList<Date>();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, 0); // January
c.set(Calendar.DAY_OF_MONTH, 1); // The first
// Find the first day we are interested in
int offset = c.get(Calendar.DAY_OF_WEEK);
if(offset!= dayOfWeek)
{
c.add(Calendar.DATE, (dayOfWeek < offset ? (offset + 7) % 7 : (dayOfWeek - offset)));
}
while(c.get(Calendar.YEAR) == year)
{
dates.add(c.getTime());
c.add(Calendar.DATE, DAYS_IN_WEEK);
}
return dates;
}
public static void main(String[] args){
System.out.println("A list of all Sundays in 2014.");
List<Date> days = GetDatesForDayOfWeek(2014, Calendar.SUNDAY);
for(Date ad : days){
System.out.println(ad);
}
}
Running the above would give you every sunday in 2014 with the output of.
A list of all Sundays in 2014.
Sun Jan 05 23:49:56 EST 2014
...
Sun Dec 28 23:49:56 EST 2014
New Java8 DateTime API gives very clean methods to use for any Date, Time related code.
Below is my part on your query.
public class ExampleDayOfYear {
public static void main(String[] args) throws InvalidDateException {
List<LocalDate> list=getDatesforDayOfWeek(2020,2);
list.forEach(System.out::println);
System.out.println("Total dates: "+list.size());
}
public static String getDay(int day, int month, int year) {
LocalDate dt=LocalDate.of(year,month,day);
return dt.getDayOfWeek().toString();
}
private static int getDayOfYear(int year){
LocalDate dt = LocalDate.parse(year+"-01-01");
return dt.getDayOfWeek().getValue();
}
public static List<LocalDate> getDatesforDayOfWeek(int year, int dayOfWeek) throws
InvalidDateException{
List<LocalDate> list=new ArrayList<LocalDate>();
int differenceOfdaysToDayofWeek=0;
int firstDayOfYear= getDayOfYear(year); // Wednesday
int count=1;
// This method call gives the date of first Monday. Also, this method requires the differenceOfDate which we have found out from getDaysDifference.
LocalDate firstDateOfWeek=getFirstDateOfWeek(year,getDaysDifference(firstDayOfYear));
list.add(firstDateOfWeek);
while(firstDateOfWeek.getYear()== year){
firstDateOfWeek= getDateWeekWise(firstDateOfWeek);
if(firstDateOfWeek.getYear()==year){
count++;
list.add(firstDateOfWeek); }
}
return list;
}
// First Day is Wednesday, so we need ot get first date of the January, 2020.
private static int getDaysDifference(int firstDayOfYear){
int difDays=0;
int dayofWeekNum=Integer.valueOf(DayOfWeek.MONDAY.ordinal()+1);
// It gives the int value of DayOfWeek. e.g. if it's Monday it will give 0 because week ordinal value starts from 0.
if(firstDayOfYear==dayofWeekNum) {
}if(firstDayOfYear>dayofWeekNum){
difDays= dayofWeekNum+7 -firstDayOfYear;
}if(firstDayOfYear<dayofWeekNum)
{
difDays= dayofWeekNum -firstDayOfYear;
}
return difDays;
}
private static LocalDate getFirstDateOfWeek(int year,int differenceOfWeekDays){
LocalDate dt = LocalDate.of(year,01,01).plusDays(differenceOfWeekDays);
return dt;
}
private static LocalDate getDateWeekWise(LocalDate dt){
dt=dt.plusWeeks(1);
return dt;
}
}
class InvalidDateException extends Exception{
InvalidDateException(String s){
super(s);
}
}

Categories