I want to take all Saturday and Sunday from given date range...
my inputs are
Start Date : 01/01/2011
End Date : 01/01/2012
now search date which is in between given start date and end date and day would be Saturday or Sunday.
Please Suggest...
Firstly, I'd recommend using Joda Time if you possibly can. It's a much better date and time API than the one built into Java.
Secondly, unless you're really worried about efficiency I would personally go for the incredibly-simple-but-somewhat-wasteful approach of simply iterating over every day in the time period, and including those which fall on the right days. Alternating between adding one day and adding six days would certainly be more efficient, but harder to change.
Sample code:
import java.util.*;
import org.joda.time.*;
public class Test
{
public static void main(String[] args)
{
List<LocalDate> dates = getWeekendDates
(new LocalDate(2011, 1, 1), new LocalDate(2011, 12, 1));
for (LocalDate date : dates)
{
System.out.println(date);
}
}
private static List<LocalDate> getWeekendDates
(LocalDate start, LocalDate end)
{
List<LocalDate> result = new ArrayList<LocalDate>();
for (LocalDate date = start;
date.isBefore(end);
date = date.plusDays(1))
{
int day = date.getDayOfWeek();
// These could be passed in...
if (day == DateTimeConstants.SATURDAY ||
day == DateTimeConstants.SUNDAY)
{
result.add(date);
}
}
return result;
}
}
I recommend to take a look at this RFC-2445 Java open-source library. You can create a weekly recurrence rule with repeating on Sat and Sun, then iterate over the specified period to get all dates.
I think, you can use following way - it's really simple and you don't need to use other libraries.
Take weekday number (for Monday = 1, Sunday = 7). Then - choose new start date, which is first Sunday occurence -> it is startDate + (7 - weekdayNum). By the same algorithm, you can take last Sunday from interval (by substracting EndDate - weekdayNum - 1, I think). And now you can go in for loop through all occurences (use incremental step 7). Or if you want specific occurence, e.g. 3rd sunday, you can simply do newStartDate + 3 * 7.
I hope, this is clear. I'm not sure, if numbers are correct. Hope this helps for understanding the problem.
Here is the complete example.
Please do suggest if we can make it better.
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
*
* #author varun.vishwakarma
*/
public class FindWeekendsInDateRange {
static HashMap<Integer, String> daysOfWeek=null;
static {
daysOfWeek = new HashMap<Integer, String>();
daysOfWeek.put(new Integer(1), "Sun");
daysOfWeek.put(new Integer(2), "Mon");
daysOfWeek.put(new Integer(3), "Tue");
daysOfWeek.put(new Integer(4), "Wed");
daysOfWeek.put(new Integer(5), "Thu");
daysOfWeek.put(new Integer(6), "Fri");
daysOfWeek.put(new Integer(7), "Sat");
}
/**
*
* #param from_date
* #param to_date
* #return
*/
public static List<Date> calculateWeekendsInDateReange(Date fromDate, Date toDate) {
List<Date> listOfWeekends = new ArrayList<Date>();
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
from.setTime(fromDate);
to.setTime(toDate);
while (from.getTimeInMillis() < to.getTimeInMillis()) {
if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sat") {
Date sat = from.getTime();
listOfWeekends.add(sat);
} else if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sun") {
Date sun = from.getTime();
listOfWeekends.add(sun);
}
from.add(Calendar.DAY_OF_MONTH, 1);
}
return listOfWeekends;
}
public static void main(String[] args) {
String fromDate = "7-Oct-2019";
String toDate = "25-Oct-2019";
System.out.println(FindWeekendsInDateRange.calculateWeekendsInDateReange(new Date(fromDate), new Date(toDate)));
}
}
I'm assuming your start and end dates are given in milliseconds. Loop through the dates and check whether days are 'Saturday' or 'Sunday'. Below I'm returning the total no. of Saturday and Sunday in given date range.
private int totalWeekendDays(long start, long end)
{
int result=0;
long dayInMS = TimeUnit.DAYS.toMillis(1);
for (long i = start; i<=end; i = i + dayInMS)
{
String dayOfTheWeek = (String) DateFormat.format("EEEE", i);
if (dayOfTheWeek.equals("Sunday")||dayOfTheWeek.equals("Saturday"))
{
result = result+1;
}
}
return result;
}
Related
I have a date and a time of a month, for example 31/01/2020 at 14:00:00, this is the last friday of January. How can I get the date for the last Friday of Feb, March, etc.? It should be dynamic because any date can come in, like the second Tuesday of any month and so on.
I am trying with the following with no luck:
LocalDateTime startTime = LocalDateTime.of(2020, 1, 31, 14, 0, 0);
final Calendar calendar = Calendar.getInstance();
calendar.set(startTime.getYear(), startTime.getMonthValue() - 1, startTime.getDayOfMonth(), startTime.getHour(), startTime.getMinute(), startTime.getSecond());
int ordinal = calendar.get(Calendar.WEEK_OF_MONTH);
startTime = startTime.plusMonths(1).with(TemporalAdjusters.dayOfWeekInMonth(ordinal, startTime.getDayOfWeek();
System.out.println(startTime);
it's printing 06/03/2020 (six of march) at 14:00:00 which is wrong and should be 28/02/2020
What am I missing?
Thanks!
As mentioned before, there is some ambiguity in which day of the week of the month you mean, that is, whether you mean the nth day of week or the last nth day of week of the month.
One such example is Monday, February 24th, 2020. It is the fourth and last Monday of February 2020. If you are going to try to determine this for March 2020, which Monday would you pick? The fourth Monday is 23 March, but the last Monday is 30 March.
So apparently, you'll need to distinguish between whether you count forward or backward.
You could, for instance, create a class which represents a certain day of week in a month. This holds three fields: a day-of-week, a position, and whether the position is backwards or not. E.g.
"The second Monday of the month" would have
dayOfWeek = DayOfWeek.MONDAY
position = 2
backwards = false
and
"The last Thursday of the month" would have
dayOfWeek = DayOfWeek.THURSDAY
position = 1
backwards = true
public class WeekdayInMonth {
private final boolean backwards;
private final DayOfWeek dayOfWeek;
private final int position;
private WeekdayInMonth(DayOfWeek dayOfWeek, int position, boolean backwards) {
if (position < 1 || position > 5) {
throw new DateTimeException("Position in month must be between 1 and 5 inclusive");
}
this.dayOfWeek = dayOfWeek;
this.position = position;
this.backwards = backwards;
}
}
We could add factory methods to create WeekdayInMonths from LocalDates:
public static WeekdayInMonth of(LocalDate date) {
int positionInMonth = (date.getDayOfMonth() - 1) / 7 + 1;
return new WeekdayInMonth(date.getDayOfWeek(), positionInMonth, false);
}
private static WeekdayInMonth ofReversing(LocalDate date) {
int lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
int positionInMonth = (lastDayOfMonth - date.getDayOfMonth()) / 7 + 1;
return new WeekdayInMonth(date.getDayOfWeek(), positionInMonth, true);
}
At last, we add a method to get a LocalDate from a YearMonth adjusted to the WeekdayInMonth.
public LocalDate toLocalDate(YearMonth yearMonth) {
// Get a temporal adjuster to adjust a LocalDate to match a day-of-the-week
TemporalAdjuster adjuster = this.backwards ? TemporalAdjusters.lastInMonth(this.dayOfWeek) : TemporalAdjusters.firstInMonth(this.dayOfWeek);
int weeks = this.position - 1;
LocalDate date = yearMonth.atDay(1)
.with(adjuster)
.plusWeeks(this.backwards ? 0 - weeks : weeks);
if (!Objects.equals(yearMonth, YearMonth.from(date))) {
throw new DateTimeException(String.format("%s #%s in %s does not exist", this.dayOfWeek, this.position, yearMonth));
}
return date;
}
Working example
Here a working example at Ideone.
Addendum
I am getting errors like this if the initial date is Jan 1 2020: java.time.DateTimeException: FRIDAY #5 in 2020-02 does not exist. How could I get the previous weekday in case this happens? In this case, how would I get the previous Friday?
Well, then you need to adjust your LocalDate so that it falls within the specified yearmonth. Since every month has at least four day-of-the-weeks and no more than five of them, the difference is never more than a week. We could, after removing the throw new DateTimeException line, simply adjust the returned LocalDate using plusWeeks.
I've forked the abovementioned example and added the toAdjustingLocalDate method.
This solution is kind of complicated but this is because "last of" or "third in" etc aren't always well defined and might not even exists under some conditions. So here is a solution that looks at the initial date and depending of the day of the month it either performs calculations from the start of the month, calculating forward, or the end of the month, calculating backwards.
From my testing it seems to generate the right results and I am sure some code refactoring could be done as well to improve the code but I leave that for the reader.
public static LocalDateTime nextWithSameDayOfMonth(LocalDateTime indate) {
if (indate.getDayOfMonth() < 15) {
return getForStartOfMonth(indate);
}
return getForEndOfMonth(indate);
}
private static LocalDateTime getForEndOfMonth(LocalDateTime indate) {
DayOfWeek dayOfWeek = indate.getDayOfWeek();
LocalDateTime workDate = indate.with(TemporalAdjusters.lastDayOfMonth());
int count = 0;
while (workDate.isAfter(indate)) {
count++;
workDate = workDate.minusWeeks(1);
}
LocalDateTime nextDate = indate.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
while (nextDate.getDayOfWeek() != dayOfWeek) {
nextDate = nextDate.minusDays(1);
}
return count == 0 ? nextDate : nextDate.minusWeeks(count - 1);
}
private static LocalDateTime getForStartOfMonth(LocalDateTime indate) {
DayOfWeek dayOfWeek = indate.getDayOfWeek();
LocalDateTime workDate = indate.with(TemporalAdjusters.firstDayOfMonth());
int count = 0;
while (workDate.isBefore(indate)) {
count++;
workDate = workDate.plusWeeks(1);
}
LocalDateTime nextDate = indate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
while (nextDate.getDayOfWeek() != dayOfWeek) {
nextDate = nextDate.plusDays(1);
}
return count == 0 ? nextDate : nextDate.plusWeeks(count - 1);
}
Could you check if the function work for you?
public class FindSameDayNextMonth {
public static void main(String[] args) {
System.out.println("Next month of 'today' is " + FindSameDayNextMonth.getSameDayNextMonth());
}
public static Date getSameDayNextMonth() {
LocalDateTime dt = LocalDateTime.now();
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, dt.getMonthValue()-1);
c.set(Calendar.DAY_OF_MONTH, dt.getDayOfMonth());
c.add(Calendar.MONTH, 1);
return c.getTime();
}
}
The output is
Next month of today is Mon Sep 23 07:18:09 CDT 2019
I'm trying to get the first day of the next month from a LocalDate object but have run into some issues.
I have a datepicker where a user can pick any date they want, without restriction and I need to get the next month's first day, this is what I've thought about doing:
LocalDate localDate = myDatePicker.getValue();
LocalTime startTime = LocalTime.of(0, 0);
LocalDate endDate = LocalDate.of(localDate.getYear(), localDate.getMonthValue() + 1, 0);
However I see a problem that may occur when choosing the month December, if that happens then the call
LocalDate.of(localDate.getYear(), localDate.getMonthValue() + 1, 0);
Should fail because I'm passing it a month value of 13. Now I could choose to check if the month value is December and if so I could add 1 to the year and start at 0 like so:
if(localDate.getMonthValue() >= 12)
LocalDate.of(localDate.getYear() + 1, 0, 0);
However I feel like there must be a way to get around this within the class itself. Does anyone know if my presumptions about passing 13 to LocalDate.of month value will cause an error? If so is there a way to do what I want to do that doesn't look so bad and uses a build in method?
Fortunately, Java makes this really easy with the idea of adjusters and TemporalAdjusters.firstDayOfNextMonth():
import java.time.*;
import java.time.temporal.*;
public class Test {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2018, 12, 3);
LocalDate date2 = date1.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(date2); // 2019-01-01
}
}
Custom way with :
.plusMonths(1) to get the next month
.withDayOfMonth(1) to get the first day
LocalDate localDate = LocalDate.of(2018, 12, 15);
LocalDate firstNext = localDate.plusMonths(1).withDayOfMonth(1);
// or firstNext = localDate.withDayOfMonth(1).plusMonths(1);
System.out.println(firstNext); //2019-01-01
Built-in way with :
TemporalAdjusters.firstDayOfNextMonth()
firstNext = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
// does a temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS); operation
Using LocalDate you can get firstDayofNextMonth withTemporalAdjusters.firstDayOfNextMonth()
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class Test {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalDate firstDayOfNextMonth = date.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(firstDayOfNextMonth);
}
}
I'm teaching myself Java and I am working on this application that will count the days until Christmas. The HOUR_OF_DAY, MONTH, and SECOND values of the GregorianCalendar and Date objects for today and Christmas are all set to zero. By debugging I can see the variable for the difference in days in milliseconds and it gives me a time of 1641599724 milliseconds which comes out to be 18.99999 days but it wont round up to 19 no matter what I try!
I have tried Math.ceil method to try and round up but I can't get it to equal 19.
FIRST: DataUtils class stores/modifies input from the user
package chapter13datesstrings;
import java.util.*;
public class DateUtils {
static final int MILLS_IN_DAY = 24 * 60 * 60 * 1000;
public static Date getCurrentDate(){
GregorianCalendar currentDate = new GregorianCalendar();
currentDate.set(Calendar.HOUR_OF_DAY, 0);
currentDate.set(Calendar.MINUTE, 0);
currentDate.set(Calendar.SECOND, 0);
return currentDate.getTime();
}
public static Date createDate(int year, int month, int day){
GregorianCalendar date = new GregorianCalendar(year, month, day);
return date.getTime();
}
public static Date stripTime(Date date){
GregorianCalendar noTimeDate = new GregorianCalendar();
noTimeDate.setTime(date);
noTimeDate.set(Calendar.HOUR, 0);
noTimeDate.set(Calendar.MINUTE,0);
noTimeDate.set(Calendar.SECOND, 0);
return noTimeDate.getTime();
}
public static double daysDiff(Date date1, Date date2){
date1 = stripTime(date1);
date2 = stripTime(date2);
long longDate1 = date1.getTime();
long longDate2 = date2.getTime();
long longDiff = longDate2 - longDate1;
return (int) (Math.ceil(longDiff / MILLS_IN_DAY));
}
}
SECOND: DateUtilExample class provides input to the DataUtils class
package chapter13datesstrings;
import java.util.*;
import java.text.*;
public class DateUtilExample {
public void thisIsCode(){
GregorianCalendar currentGC = new GregorianCalendar();
int currentYear = currentGC.get(Calendar.YEAR); //sets current year
Date currentDate = DateUtils.getCurrentDate(); //create current date object
Date christmas = DateUtils.createDate(currentYear, Calendar.DECEMBER, 25); //set christmas date
int daysToChristmas = DateUtils.daysDiff(currentDate, christmas); // days until christmas
DateFormat date = DateFormat.getDateInstance(Calendar.LONG);
String formattedToday = date.format(currentDate);
/**** Output Items *****/
System.out.println("Today is " + formattedToday);
System.out.println("Number of Days 'Till Xmas: " + daysToChristmas + " days");
}
}
MAIN METHOD CLASS
package chapter13datesstrings;
import java.util.Date;
import java.text.DateFormat;
public class Chapter13DatesStrings {
public static void theDates(){
DateUtilExample dateUtilExample = new DateUtilExample();
dateUtilExample.thisIsCode();
}
public static void main(String[] args) {
theDates();
}
}
When you divide two integers in Java, the result is rounded down ("truncated") automatically.
The expression longDiff / MILLS_IN_DAY isn't equal to 18.99999, it is equal to 18. Java essentially calculates 18.99999 and then throws everything after the decimal point away, before you can do anything with it. Rounding up with ceil won't help at that point, because you just end up calculating ceil(18) which is just 18.
One solution to this is to cast the numbers to double before you divide them. double's are floating point values, so dividing them does not round the result down. To use doubles, replace
longDiff / MILLS_IN_DAY
with
((double)longDiff) / ((double)MILLS_IN_DAY)
Another solution, which may be more computationally efficient but a little bit less elegant is to simply add 1 to the result. This isn't strictly equivalent, because when you are within a millisecond of midnight the result will be a day more than you expected, but this is essentially unnoticeable. To take this approach, you would replace the line:
return (int) (Math.ceil(longDiff / MILLS_IN_DAY));
with
return longDiff / MILLS_IN_DAY + 1;
Alternatively to what SelectricSimian said,
this is something that can be done in a couple of lines using the Calendar API provided by java.
To simply get the day difference between the current time and a given day, you can use:
public static void main(String[] args) {
System.out.println(getDaysUntil(Calendar.DECEMBER, 25) + " day(s).");
// If the date is December 25th, this will output "365 day(s)"
// If the date is December 24th, this will output "1 day(s)"
}
public static int getDaysUntil(int month, int day) {
/**
* First get a properly formatted calendar representing right now. This
* should include leap years and local. With this calendar, we get the
* day of the year.
*/
Calendar calendar = Calendar.getInstance();
int today = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Now change the day and month of the current calendar to the given day
* and month.
*/
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
int desiredDay = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Then we just get the difference between now and then.
*/
int difference = desiredDay - today;
/**
* If the desiredDay has passed already, or it's currently the
* desiredDay, we need to recalculate the difference.
*/
if (difference <= 0) {
/**
* We start by getting the days until the end of the year.
*/
calendar.set(Calendar.MONTH, 11);
calendar.set(Calendar.DAY_OF_MONTH, 31);
int daysUntilEnd = calendar.get(Calendar.DAY_OF_YEAR) - today;
/**
* Then, move the calendar forward a year and get the day of year
* for the desired day again. We recalculate the number of days just
* in case next year is a leap year.
*/
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
desiredDay = calendar.get(Calendar.DAY_OF_YEAR);
/**
* Finally, just add daysUntilEnd and desiredDay to get the updated
* difference.
*/
difference = daysUntilEnd + desiredDay;
}
return difference;
}
I have 2 dates:
Calendar c1 = Calendar.getInstance();
c1.set(2014, 1, 1);
Calendar c2 = Calendar.getInstance();
c2.set(2013, 11, 1);
How can I get a list of all the valid dates in between (and including) these two dates?
I would in general also recommend using joda-time, but here's a pure Java solution:
Calendar c1 = Calendar.getInstance();
c1.set(2013, 1, 1);
Calendar c2 = Calendar.getInstance();
c2.set(2014, 11, 1);
while (!c1.after(c2)) {
System.out.println(c1.getTime());
c1.add(Calendar.DAY_OF_YEAR, 1);
}
In essence: keep incrementing the earlier date until it falls after the later date. If you want to keep them in an actual List<Calendar>, you'll need to copy c1 on every iteration and add the copy to the list.
Try with Joda-Time
List<LocalDate> dates = new ArrayList<LocalDate>();
int days = Days.daysBetween(startDate, endDate).getDays();
for (int i=0; i < days; i++) {
LocalDate d = startDate.withFieldAdded(DurationFieldType.days(), i);
dates.add(d);
}
The following functions should do what you want without having to include any other dependencies:
#Nonnull
public static List<Date> getDaysBetween(#Nonnull final Date start, #Nonnull final Date end)
{
final List<Date> dates = new ArrayList<Date>();
dates.add(start);
Date nextDay = dayAfter(start);
while (nextDay.compareTo(end) <= 0)
{
dates.add(nextDay);
}
return dates;
}
#Nonnull
public static Date dayAfter(final Date date)
{
final GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
gc.roll(Calendar.DAY_OF_YEAR, true);
return gc.getTime();
}
Start by determining which of the two dates is earlier. If c1 comes after c2, swap the objects.
After that make a loop that prints the current date from c1, and then calls c1.add(Calendar.DAY_OF_MONTH, 1). When c1 exceeds c2, end the loop.
Here is a demo on ideone. Note that month numbers are zero-based, so your example enumerates dates between Dec-1, 2013 and Feb-1, 2014, inclusive, and not between Nov-1, 2013 and Jan-1, 2014, as the numbers in the program might suggest.
Is it possible to add weekdays to joda time?
For instance, if current date is Friday 01/03, date + 1 should return Monday 04/03, rather than 02/03.
As far as I know there is no built-in method to automatically do this for you in Joda Time. However, you could write your own method, that increments the date in a loop until you get to a weekday.
Note that, depending on what you need it for exactly, this could be (much) more complicated than you think. For example, should it skip holidays too? Which days are holidays depends on which country you're in. Also, in some countries (for example, Arabic countries) the weekend is on Thursday and Friday, not Saturday and Sunday.
LocalDate newDate = new LocalDate();
int i=0;
while(i<days)//days == as many days as u want too
{
newDate = newDate.plusDays(1);//here even sat and sun are added
//but at the end it goes to the correct week day.
//because i is only increased if it is week day
if(newDate.getDayOfWeek()<=5)
{
i++;
}
}
System.out.println("new date"+newDate);
Be aware that iterating through adding N days one at a time can be relatively expensive. For small values of N and/or non performance sensitive code, this is probably not an issue. Where it is, I'd recommend minimizing the add operations by working out how many weeks and days you need to adjust by:
/**
* Returns the date that is {#code n} weekdays after the specified date.
* <p>
* Weekdays are Monday through Friday.
* <p>
* If {#code date} is a weekend, 1 weekday after is Monday.
*/
public static LocalDate weekdaysAfter(int n, LocalDate date) {
if (n == 0)
return date;
if (n < 0)
return weekdaysBefore(-n, date);
LocalDate newDate = date;
int dow = date.getDayOfWeek();
if (dow >= DateTimeConstants.SATURDAY) {
newDate = date.plusDays(8 - dow);
n--;
}
int nWeeks = n / 5;
int nDays = n % 5;
newDate = newDate.plusWeeks(nWeeks);
return ( (newDate.getDayOfWeek() + nDays) > DateTimeConstants.FRIDAY)
? newDate.plusDays(nDays + 2)
: newDate.plusDays(nDays);
public LocalDate getBusinessDaysAddedDate(LocalDate localDate, int businessDays){
LocalDate result;
if(localDate.getDayOfWeek().getValue() + businessDays > 5) {
result = localDate.plusDays(2);
}
result = localDate.plusDays(businessDays);
return result;
}
In order to work with Date instead of LocalDate, refer https://stackoverflow.com/a/47719540/12794444 for the conversions.
Class YearMonthDay is deprecated and you shouldn't use it. If you change to simple DateTime you can obtain the week day by calling:
dateTime.getDayOfWeek();
For Friday it will be 5.
One of the approaches can be making a custom addDays method which should look something like that:
addDays(DateTime dateTime, int days) {
for(int i=0;i<days;i++){
dateTime.plusDays(1);
if(dateTime.getDayOfWeek()==6) dateTime.plusDays(2); // if Saturday add 2 more days }
}