I need to be able to calculate the "Friday before" today in Java or Groovy.
For example, if today is Monday, February 21, the "Friday before" would be Friday, February 18.
And if today was Tuesday, February 1, the "Friday before" would be Friday, January 28.
What would be the best way to do this? What existing classes can I most effectively leverage?
You can use a loop:
Calendar c = Calendar.getInstance();
while(c.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY)
{
c.add(Calendar.DAY_OF_WEEK, -1)
}
Or
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_WEEK, -((c.get(Calendar.DAY_OF_WEEK) + 1) % 7));
I would make a method that gave me the number of days that have passed since the given day.
// Uses now by default
public static int daysSince(int day) {
return daysSince(day, Calendar.getInstance());
}
// Gives you the number of days since the given day of the week from the given day.
public static int daysSince(int day, Calendar now) {
int today = now.get(Calendar.DAY_OF_WEEK);
int difference = today - day;
if(difference <= 0) difference += 7;
return difference;
}
// Simple use example
public static void callingMethod() {
int daysPassed = daysSince(Calendar.FRIDAY);
Calendar lastFriday = Calendar.getInstance().add(Calendar.DAY_OF_WEEK, -daysPassed);
}
Related
How can you calculate the number of weeks between two dates in Android? I have done something like this
int week1 = calendar1.get(Calendar.WEEK_OF_YEAR);
int week2 = calendar2.get(Calendar.WEEK_OF_YEAR);
int calendarWeekDifference = week2 - week1;
However this does not work when the two dates are in different years. How can I achieve a solution so that it will work across different years?
EDIT
I have tried doing the following with Joda-Time:
public static int weeksTouched(Calendar fromDate, Calendar toDate){
DateTime fromDateTime = new DateTime(fromDate);
DateTime toDateTime = new DateTime(toDate);
DateTime epoch = new DateTime(0);
Weeks fromWeeks = Weeks.weeksBetween(epoch, fromDateTime);
Weeks toWeeks = Weeks.weeksBetween(epoch, toDateTime);
int betweenWeeks = toWeeks.getWeeks() - fromWeeks.getWeeks();
return betweenWeeks;
}
This almost works but for some reason it thinks the start of a week is Thursday. I want the start of a week to be Monday so that a Monday to the next Saturday would return 0 (same week) but a Saturday to the next day Sunday would return 1 (different weeks).
public int getWeekDifference(long fromDateInMills, long toDateInMills) {
int weeks = Weeks.weeksBetween(new DateTime(fromDateInMills), new DateTime(toDateInMills)).getWeeks();
// when we select any future date than week difference comes in negative so
// just interchange millisecond You will get week difference in positive
if (weeks < 0) {
weeks = Weeks.weeksBetween(new DateTime(toDateInMills), new DateTime(fromDateInMills)).getWeeks();
}
return weeks;
}
Some answers here give wrong results, and some require an extra library. I managed to come up with a method that calculates the week-diff using standard Calendar APIs.
It correctly handles edge cases like 2000-01-01 to 2000-12-31 (54 weeks implies a difference of 53).
getWeeksBetween() using Calendar API
public static int getWeeksBetween(final Date start, final Date end) {
final Calendar c1 = Calendar.getInstance(Locale.US);
final Calendar c2 = Calendar.getInstance(Locale.US);
// Skip time part! Not sure if this is needed, but I wanted clean dates.
CalendarUtils.setDateWithNoTime(c1, start);
CalendarUtils.setDateWithNoTime(c2, end);
CalendarUtils.goToFirstDayOfWeek(c1);
CalendarUtils.goToFirstDayOfWeek(c2);
int weeks = 0;
while (c1.compareTo(c2) < 0) {
c1.add(Calendar.WEEK_OF_YEAR, 1);
weeks++;
}
return weeks;
}
And some helper methods:
public static int goToFirstDayOfWeek(final Calendar calendar) {
final int firstDayOfWeek = calendar.getFirstDayOfWeek();
calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
return firstDayOfWeek;
}
public static void setDateWithNoTime(final Calendar calendar, final Date date) {
calendar.setTime(date);
clearTime(calendar);
}
public static void clearTime(final Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
Without using JodaTime, I came up with this solution to calculate number of weeks:
private fun calculateNumberOfWeeks() {
val calendarFrom = Calendar.getInstance()
calendarFrom.set(Calendar.HOUR_OF_DAY, 0)
calendarFrom.set(Calendar.MINUTE, 0)
calendarFrom.set(Calendar.SECOND, 0)
calendarFrom.set(Calendar.MILLISECOND, 0)
val calendarTo = Calendar.getInstance()
calendarTo.add(Calendar.MONTH, months)
calendarTo.set(Calendar.HOUR_OF_DAY, 0)
calendarTo.set(Calendar.MINUTE, 0)
calendarTo.set(Calendar.SECOND, 0)
calendarTo.set(Calendar.MILLISECOND, 0)
var weeks = -1
while (calendarFrom.timeInMillis < calendarTo.timeInMillis) {
calendarFrom.add(Calendar.DATE, 7)
weeks++
Log.d(Constants.LOG_TAG, "weeks $weeks")
}
}
I would recommend that instead of calculating the difference in weeks you should try to find the difference in days and the result you can divide by 7.
So it would be weeks = (daysBetweenDates / 7)
using java 8
public void weeks_between_two_dates_in_java_with_java8 () {
LocalDate startDate = LocalDate.of(2005, Month.JANUARY, 1);
LocalDate endDate = LocalDate.of(2006, Month.JANUARY, 1);
long weeksInYear = ChronoUnit.WEEKS.between(startDate, endDate);
}
or using joda time api
public void weeks_between_two_dates_in_java_with_joda () {
DateTime start = new DateTime(2005, 1, 1, 0, 0, 0, 0);
DateTime end = new DateTime(2006, 1, 1, 0, 0, 0, 0);
Weeks weeks = Weeks.weeksBetween(start, end);
int weeksInYear = weeks.getWeeks();
}
What about a sort of low tech solution just using maths?
You have the Week_OF_YEAR from each date. Also the the YEAR number for each.
Multiply each Year number by 52, add that to the WEEK_OF_YEAR then subtract the two numbers.
for example....
2018 Week 50
to
2019 Week 2
2018*52 = 104936 + 50 weeks = 104986
2019*52 = 104988 + 2 weeks = 104990
104990 - 104986 = 4 weeks
Another alternative solution. My basic concept is:
Trim given dates to the respective Mondays 00:00:00.000
Calculate milliseconds between those trimmed dates and then divide it by milliseconds of a week.
A sample in Java:
public class Main {
public static void main(String[] args) {
Calendar Monday = Calendar.getInstance();
Monday.set(2020, 11, 28, 12, 34, 56); // 2020-12-28T12:34:56
Calendar Saturday = Calendar.getInstance();
Saturday.set(2021, 0, 2, 21, 43, 57); // 2021-01-02T21:43:57
Calendar Sunday = Calendar.getInstance();
Sunday.set(2021, 0, 3, 0, 1, 2); // 2021-01-03T00:01:02
Calendar NextMonday = Calendar.getInstance();
NextMonday.set(2021, 0, 4, 1, 23, 45); // 2021-01-04T01:23:45
System.out.println(String.format(": %d week(s)", weeksTouched(Monday, Sunday)));
System.out.println(String.format(": %d week(s)", weeksTouched(Saturday, Sunday)));
System.out.println(String.format(": %d week(s)", weeksTouched(Sunday, NextMonday)));
}
public static int weeksTouched(Calendar fromDate, Calendar toDate){
System.out.print(String.format("%s -> %s", fromDate.getTime(), toDate.getTime()));
return (int) (
(trimToMonday(toDate).getTimeInMillis() - trimToMonday(fromDate).getTimeInMillis())
/ (1000 * 60 * 60 * 24 * 7)
);
}
private static Calendar trimToMonday(Calendar input) {
Calendar output = (Calendar) input.clone();
switch (output.get(Calendar.DAY_OF_WEEK)) {
case Calendar.TUESDAY:
output.add(Calendar.DAY_OF_MONTH, -1);
break;
case Calendar.WEDNESDAY:
output.add(Calendar.DAY_OF_MONTH, -2);
break;
case Calendar.THURSDAY:
output.add(Calendar.DAY_OF_MONTH, -3);
break;
case Calendar.FRIDAY:
output.add(Calendar.DAY_OF_MONTH, -4);
break;
case Calendar.SATURDAY:
output.add(Calendar.DAY_OF_MONTH, -5);
break;
case Calendar.SUNDAY:
output.add(Calendar.DAY_OF_MONTH, -6);
break;
}
output.set(Calendar.HOUR_OF_DAY, 0);
output.set(Calendar.MINUTE, 0);
output.set(Calendar.SECOND, 0);
output.set(Calendar.MILLISECOND, 0);
return output;
}
}
Output:
Mon Dec 28 12:34:56 JST 2020 -> Sun Jan 03 00:01:02 JST 2021: 0 week(s)
Sat Jan 02 21:43:57 JST 2021 -> Sun Jan 03 00:01:02 JST 2021: 0 week(s)
Sun Jan 03 00:01:02 JST 2021 -> Mon Jan 04 01:23:45 JST 2021: 1 week(s)
This will give you number of weeks b/w two dates.
public void getNoOfWeek()
{
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.clear();
date1.set(2015, 12, 29); // set date 1 (yyyy,mm,dd)
date2.clear();
date2.set(2016, 02, 7); //set date 2 (yyyy,mm,dd)
long diff = date2.getTimeInMillis() - date1.getTimeInMillis();
float dayCount = (float) diff / (24 * 60 * 60 * 1000);
int week = (int) (dayCount / 7);
System.out.println(week);
}
I've made a function that should get the number of weeks for a given month. For January, May, July and October, it should return 5 weeks.
However, it returns 5 for March, June, September. and November. Surprisingly, the total amount of weeks are correct (52).
public static int getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(Calendar calendar) {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
calendar.roll(Calendar.DATE, true);
}
int currentMonth = calendar.get(Calendar.MONTH);
int nextMonth = (currentMonth + 1) % 12;
int prePreviousMonth = (currentMonth + 12 - 2) % 12;
int nofWeeks = 0;
do {
int month = calendar.get(Calendar.MONTH);
if (month == nextMonth) {
nofWeeks++;
}
if (month == prePreviousMonth) {
break;
}
calendar.roll(Calendar.WEEK_OF_YEAR, true);
} while (true);
return nofWeeks;
}
public static void main(String[] args) {
int numWeeks;
int totalWeeks=0;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.MONTH, Calendar.MAY);
numWeeks=getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(calendar);
System.out.println("no of weeks " + numWeeks);
}
Output:
no of weeks 4
Month start is in Week that has first day. e.g.:
25 - 1 May
2 - 8 May
9 - 15 May
16 - 22 May
23 - 29 May
5 Weeks in May:
It sounds to me like you should:
Work out the first day of the month
Determine from that how many "extra" days are "borrowed" from the previous month (e.g. 0 if day 1 is a Monday; 1 if day 1 is a Tuesday etc)
Add that to the number of days in the regular month
Divide by 7 (with implicit truncation towards 0)
There's no need to do half the work you're currently doing.
Using java.util.Calendar, it would be something like:
// Note: day-of-week runs from Sunday (1) to Saturday (7).
// Entry 0 here is not used. We could do this without an array lookup
// if desired, but it's whatever code you think is clearest.
private static final int[] EXTRA_DAYS = { 0, 6, 0, 1, 2, 3, 4, 5 };
// Note: 0-based month as per the rest of java.util.Calendar
public static int getWeekCount(int year, int month) {
Calendar calendar = new GregorianCalendar(year, month, 1);
int dayOfWeekOfStartOfMonth = calendar.get(Calendar.DAY_OF_WEEK);
int extraDays = EXTRA_DAYS[dayOfWeekOfStartOfMonth];
int regularDaysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int effectiveDaysInMonth = regularDaysInMonth + extraDays;
return effectiveDaysInMonth / 7;
}
If at all possible, I'd recommend using Joda Time or java.time instead, however.
With that code, the results for 2016 are:
January: 5
February: 4
March: 4
April: 4
May: 5
June: 4
July: 5
August: 4
September: 4
October: 5
November: 4
December: 4
From the comments I deduce that you want to count the number of weeks in a month starting at the 1st of the month.
You need to:
Set the day of the month to 1
add forward, not roll backward
start on Sunday instead of Monday
The code would be something like this:
public static int getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(Calendar calendar) {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
calendar.roll(Calendar.DATE, true);
}
int currentMonth = calendar.get(Calendar.MONTH);
int nextMonth = (currentMonth + 1) % 12;
int prePreviousMonth = (currentMonth + 12 - 2) % 12;
int nofWeeks = 0;
do {
int month = calendar.get(Calendar.MONTH);
if (month == currentMonth) {
nofWeeks++;
} else {
break;
}
calendar.add(Calendar.WEEK_OF_YEAR, 1);
} while (true);
return nofWeeks;
}
public static void main(String[] args) {
int numWeeks;
int totalWeeks=0;
for (int i = 0; i < 12; i++) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.MONTH, i);
numWeeks=getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(calendar);
System.out.println("no of weeks " + numWeeks);
}
}
Output:
no of weeks 5
no of weeks 4
no of weeks 4
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 4
I need to claculate the number of days between two dates without using any date or calendar classes provided by any library.
Here's my idea:
numberOfDays = Math.abs((toYear - fromYear) * 365);
numberOfDays = numberOfDays + Math.abs((toMonth - fromMonth) * 12);
numberOfDays = numberOfDays + Math.abs((toDay - fromDay));
Thoughts?
How many days between the start date and the end of the month?
How many days in each full month until the end of the year?
How many days in each full year until the year of the end date (counting leap years)?
How many days in each full month until the last month?
How many days from the start of the last month until the end date?
Some of these numbers may be zero.
In Java 8 you can do the following:
long days = ChronoUnit.DAYS.between(LocalDate.of(2014, Month.MARCH, 01), LocalDate.of(2014, Month.FEBRUARY, 15));
Would something like this do?
//get 2 random dates
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = new Date();
Date date2 = sdf.parse("2014-9-12");
final long msInADay = 24*60*60*1000; //turn a day to ms
//divide time difference by the ms of a day
int difference = (int)((date2.getTime() - date1.getTime()) / msInADay);
System.out.println(Math.abs(difference));//Math.abs so you can subtract dates in any order.
EDIT after updating your question:
You can do this:
static int calcDayDiff(int startY, int startM, int startD, int endY, int endM, int endD){
int result = (startY - endY) * 365;
result += (startM - endM) * 31;
result += (startD - endD);
return Math.abs(result);
}
Testing with: System.out.println(calcDayDiff(2014,9,13,2013,8,12)); will print 397
Note though that this is not a very good solution since not every month contains 31 days and not every year 365. You can fix the month day difference by adding some simple logic inside the method to not always multiply by 31. Since it's an assignment i guess you will be ok to consider every year having 365 days.
public class test {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.set(2014, 8, 1, 0, 0, 0);
Date s = cal.getTime();
Date e = new Date();
System.out.println(days(s,e));
}
public static int days(Date start, Date end){
double aTms = Math.floor(start.getTime() - end.getTime());
return (int) (aTms/(24*60*+60*1000));
}
}
How to calculate number of Tuesday in one month?
Using calender.set we can set particular month, after that how to calculate number of Mondays, Tuesdays etc. in that month?
Code is :
public static void main(String[] args )
{
Calendar calendar = Calendar.getInstance();
int month = calendar.MAY;
int year = 2012;
int date = 1 ;
calendar.set(year, month, date);
int MaxDay = calendar.getActualMaximum(calendar.DAY_OF_MONTH);
int mon=0;
for(int i = 1 ; i < MaxDay ; i++)
{
calendar.set(Calendar.DAY_OF_MONTH, i);
if (calendar.get(Calendar.DAY_OF_WEEK) == calendar.MONDAY )
mon++;
}
System.out.println("days : " + MaxDay);
System.out.println("MOndays :" + mon);
}
Without writing whole code here is the general idea:
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, Calendar.MAY); // may is just an example
c.set(Calendar.YEAR, 2012);
int th = 0;
int maxDayInMonth = c.getMaximum(Calendar.MONTH);
for (int d = 1; d <= maxDayInMonth; d++) {
c.set(Calendar.DAY_OF_MONTH, d);
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
if (Calendar.THURSDAY == dayOfWeek) {
th++;
}
}
This code should count number of Thursday. I believe you can modify it to count number of all days of week.
Obviously this code is not efficient. It iterates over all the days in the month. You can optimize it by getting just get day of the week of the first day, the number of days in month and (I believe) you can write code that calculates number of each day of week without iterating over the whole month.
With Java 8+, you could write it in a more concise way:
public static int countDayOccurenceInMonth(DayOfWeek dow, YearMonth month) {
LocalDate start = month.atDay(1).with(TemporalAdjusters.nextOrSame(dow));
return (int) ChronoUnit.WEEKS.between(start, month.atEndOfMonth()) + 1;
}
Which you can call with:
int count = countDayOccurenceInMonth(DayOfWeek.TUESDAY, YearMonth.of(2012, 1));
System.out.println(count); //prints 5
AlexR mentioned the more efficient version. Thought I would give it a whirl:
private int getNumThursdays() {
// create instance of Gregorian calendar
Calendar gc = new GregorianCalendar(TimeZone.getTimeZone("EST"), Locale.US);
int currentWeekday = gc.get(Calendar.DAY_OF_WEEK);
// get number of days left in month
int daysLeft = gc.getActualMaximum(Calendar.DAY_OF_MONTH) -
gc.get(Calendar.DAY_OF_MONTH);
// move to closest thursday (either today or ahead)
while(currentWeekday != Calendar.THURSDAY) {
if (currentWeekday < 7) currentWeekday++;
else currentWeekday = 1;
daysLeft--;
}
// calculate the number of Thursdays left
return daysLeft / 7 + 1;
}
note: When getting the current year, month, day etc. it is dependent on your environment. For example if someone manually set the time on their phone to something wrong, then this calculation could be wrong. To ensure correctness, it is best to pull data about the current month, year, day, time from a trusted source.
Java calendar actually has a built in property for that Calendar.DAY_OF_WEEK_IN_MONTH
Calendar calendar = Calendar.getInstance(); //get instance
calendar.set(Calendar.DAY_OF_WEEK, 3); //make it be a Tuesday (crucial)
//optionally set the month you want here
calendar.set(Calendar.MONTH, 4) //May
calendar.getActualMaximum(Calendar.DAY_OF_WEEK_IN_MONTH); //for this month (what you want)
calendar.getMaximum(Calendar.DAY_OF_WEEK_IN_MONTH); //for any month (not so useful)
I'm trying to come up with a way to calculate the number of days between two different dates, however there will be certain days of the week that are only to be accounted for. For example, let's say we want to calculate the number of work days between 8/1 and 8/31, but employee only works Monday, Tuesday and Wednesday. The result would be that this employee only works 15 days during that period.
Has anyone put together something similar using the java Calendar class?
Try Joda Time, is the best solution to manage Date and Time.
The code of dogbane corrected:
final Calendar current = Calendar.getInstance();
current.set(2011, 7, 1);
final Calendar end = Calendar.getInstance();
end.set(2011, 7, 31);
int count = 0;
while (!current.after(end)) {
int dayOfWeek = current.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek == Calendar.MONDAY ||
dayOfWeek == Calendar.TUESDAY ||
dayOfWeek == Calendar.WEDNESDAY) {
count++;
}
current.add(Calendar.DAY_OF_MONTH, 1);
}
System.out.println(count);
If use Joda Time:
DateTime current = new DateTime(2011, 8, 1, 0, 0, 0, 0);
DateTime end = new DateTime(2011, 8, 31, 0, 0, 0, 0);
int count = 0;
while (!current.isAfter(end)) {
int dayOfWeek = current.getDayOfWeek();
if (dayOfWeek == DateTimeConstants.MONDAY || dayOfWeek == DateTimeConstants.TUESDAY
|| dayOfWeek == DateTimeConstants.WEDNESDAY) {
count++;
}
current = current.plusDays(1);
}
System.out.println(count);
You can do this by incrementing the date by one day until you reach the end date. At each iteration, check if the day is Mon, Tue or Wed and increment a counter.
For example:
final Calendar current = Calendar.getInstance();
current.set(2011, 7, 1);
final Calendar end = Calendar.getInstance();
end.set(2011, 7, 31);
int count = 0;
while (current.compareTo(end) != 0) {
current.add(Calendar.DAY_OF_MONTH, 1);
int dayOfWeek = current.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek == Calendar.MONDAY ||
dayOfWeek == Calendar.TUESDAY ||
dayOfWeek == Calendar.WEDNESDAY) {
count++;
}
}
System.out.println(count);
You could roll your own solution with java.util.Calendar; however, I suggest looking at some existing library, such as ObjectLab Kit date utilities.