Java get a date by the given day name [duplicate] - java

This question already has answers here:
Is there a good way to get the date of the coming Wednesday?
(6 answers)
Closed 1 year ago.
How can I get a date by day's name?
For example:
Input: Monday
Output: 02/08/2021
Input: Tuesday
Output: 03/08/2021
I want to get the closest date of the day.

This is my understanding of what the OP wants -
Given a day of the week as input, print the date (having the same day of the week as the input) which is closest to today.
We can do this using LocalDate, DayOfWeek and TemporalAdjuster.
The logic is -
Convert the input day of week to an instance of DayOfWeek.
If today is the same day of week as the input, print today's date and stop, else proceed to the next steps.
Get the date of the same day of the week in the previous week.
Get the date of the same day of the week in the next week.
Check which day is closer to today by using .toEpochDay().
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public static void main(String[] args) {
String inputDayOfWeekString = "SUNDAY";
DayOfWeek inputDayOfWeek = DayOfWeek.valueOf(inputDayOfWeekString);
LocalDate today = LocalDate.now();
if (today.getDayOfWeek().equals(inputDayOfWeek)) {
System.out.println(today);
} else {
LocalDate sameDayNextWeek = today.with(TemporalAdjusters.next(inputDayOfWeek));
LocalDate sameDayPreviousWeek = today.with(TemporalAdjusters.previous(inputDayOfWeek));
LocalDate dateCloserToToday = (sameDayNextWeek.toEpochDay() - today.toEpochDay()) < (today.toEpochDay() - sameDayPreviousWeek.toEpochDay()) ? sameDayNextWeek : sameDayPreviousWeek;
System.out.println(dateCloserToToday);
}
}

Assuming that you want to find the closest day from today that has a specific day of week, one way to do this is to compute both the next and previous day from today that has that day of week, and compare them:
private static LocalDate closestDOW(DayOfWeek dow) {
LocalDate today = LocalDate.now();
LocalDate next = today.with(TemporalAdjusters.nextOrSame(dow));
LocalDate previous = today.with(TemporalAdjusters.previousOrSame(dow));
if (ChronoUnit.DAYS.between(today, next) < ChronoUnit.DAYS.between(previous, today)) {
return next;
} else {
return previous;
}
}
Alternatively, work out whether the next such day is at most three days away. If it is, then it is closer than the previous such day.
private static LocalDate closestDOW(DayOfWeek dow) {
LocalDate today = LocalDate.now();
int daysDiff = today.getDayOfWeek().getValue() - dow.getValue();
int daysUntilNextDOW = daysDiff >= 0 ? 7 - daysDiff : -daysDiff;
if (daysUntilNextDOW <= 3) {
return today.plusDays(daysUntilNextDOW);
} else {
return today.with(TemporalAdjusters.previousOrSame(dow));
}
}

Related

Get weeks between 2 dates with weeks crossing 2 months

I would like to get all the weeks between 2 dates with weeks that cross 2 months counted twice for each month. For example, in 2021 week 14 of the year hosted both March and April so in this case, I would like that week counted twice (once for March and once for April). I've looked and found just libraries that count the number of weeks between 2 dates. I think I could get week numbers and month numbers and form a unique array but this seems a bit over the top. Has anyone got any suggestions?
weeks that cross 2 months counted twice
The code below allows to do that by utilizing only the standard LocalDate class and it's methods isBefore(), plusWeeks(), plusDays().
Keep in mind the days of the week and months are represented by enums from the java.time package.
I've made a couple of assumptions:
week starts with Sunday;
chunks of the week at the start and at the end of the given period have to be taken into account as well as full-length weeks.
public static void main(String[] args) {
System.out.println(getWeekCount(LocalDate.of(2022, 1, 1),
LocalDate.of(2022, 2, 1)));
System.out.println(getWeekCount(LocalDate.of(2022, 1, 1),
LocalDate.of(2022, 3, 1)));
}
public static int getWeekCount(LocalDate date1, LocalDate date2) {
int weekCount = 0;
LocalDate cur = date1;
LocalDate finish = date2;
// assumption: week starts with sunday
// assumption: chunk of week at the start and at the end have to be taken into account as well as full weeks
if (cur.getDayOfWeek() != DayOfWeek.SUNDAY) { // adjusting current date
LocalDate next = cur.plusDays(DayOfWeek.SUNDAY.ordinal() - cur.getDayOfWeek().ordinal() + 1);
weekCount += getWeeksIncrement(cur, next);
cur = next;
}
if (finish.getDayOfWeek() != DayOfWeek.SUNDAY) { // adjusting finish date
LocalDate previous = finish.minusDays(finish.getDayOfWeek().ordinal() + 1);
weekCount += getWeeksIncrement(previous, finish);
finish = previous;
}
while (cur.isBefore(finish) || cur.equals(finish)) {
LocalDate next = cur.plusWeeks(1);
weekCount += getWeeksIncrement(cur, next);
cur = next;
}
return weekCount;
}
public static int getWeeksIncrement(LocalDate cur, LocalDate next) {
return weekIsSharedBetweenTwoMonth(cur, next) ? 2 : 1;
}
public static boolean weekIsSharedBetweenTwoMonth(LocalDate cur, LocalDate next) {
return next.getMonth() != cur.getMonth() &&
next.withDayOfMonth(1).isAfter(cur);
}
Output
7 - weeks between: 2022-01-01 and 2022-02-01
12 - weeks between: 2022-01-01 and 2022-03-01
Well, this is achievable with a combination of the Java Date and Time API (java.time) and the Java Streams API (java.util.stream):
long weeksBetween(LocalDate start, LocalDate endInclusive) {
LocalDate normalizedStart = start.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
LocalDate normalizedEndExclusive = endInclusive.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
return Stream.iterate(normalizedStart, d -> d.plusWeeks(1))
.takeWhile(d -> d.isBefore(normalizedEndExclusive))
.mapToInt(d -> d.getMonthValue() == d.plusDays(6).getMonthValue() ? 1 : 2)
.sum();
}
What happens here, is as follows.
First, the dates are normalized, that is, they are set to the start of the week (Monday according to ISO standards).
Then we walk over the Monday of each week, and check if its last day of the week (Sunday) lies within the same month. If it is, then it yields 1, otherwise it yields 2.
At last, we sum all yielded values.
Note that I assumed that a week starts on Monday (ISO). The code also considers the week of both the start date as the end date as full ones.
You can get the weeknumber like this using java.time:
LocalDate date = LocalDate.of(year, month, day);
int weekOfYear = date.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
You did not mention which java version you are using. java.time was introduced in java 8. There are other solutions available for pre-java 8.
Based on the above, you should be able to solve your problem.

Java 8 calculate months between two dates

NOTE THIS IS NOT A DUPLICATE OF EITHER OF THE FOLLOWING
Calculating the difference between two Java date instances
calculate months between two dates in java [duplicate]
I have two dates:
Start date: "2016-08-31"
End date: "2016-11-30"
Its 91 days duration between the above two dates, I expected my code to return 3 months duration, but the below methods only returned 2 months. Does anyone have a better suggestion? Or do you guys think this is a bug in Java 8? 91 days the duration only return 2 months.
Thank you very much for the help.
Method 1:
Period diff = Period.between(LocalDate.parse("2016-08-31"),
LocalDate.parse("2016-11-30"));
Method 2:
long daysBetween = ChronoUnit.MONTHS.between(LocalDate.parse("2016-08-31"),
LocalDate.parse("2016-11-30"));
Method 3:
I tried to use Joda library instead of Java 8 APIs, it works. it loos will return 3, It looks like Java duration months calculation also used days value. But in my case, i cannot use the Joda at my project. So still looking for other solutions.
LocalDate dateBefore= LocalDate.parse("2016-08-31");
LocalDate dateAfter = LocalDate.parse("2016-11-30");
int months = Months.monthsBetween(dateBefore, dateAfter).getMonths();
System.out.println(months);
Since you don't care about the days in your case. You only want the number of month between two dates, use the documentation of the period to adapt the dates, it used the days as explain by Jacob. Simply set the days of both instance to the same value (the first day of the month)
Period diff = Period.between(
LocalDate.parse("2016-08-31").withDayOfMonth(1),
LocalDate.parse("2016-11-30").withDayOfMonth(1));
System.out.println(diff); //P3M
Same with the other solution :
long monthsBetween = ChronoUnit.MONTHS.between(
LocalDate.parse("2016-08-31").withDayOfMonth(1),
LocalDate.parse("2016-11-30").withDayOfMonth(1));
System.out.println(monthsBetween); //3
Edit from #Olivier Grégoire comment:
Instead of using a LocalDate and set the day to the first of the month, we can use YearMonth that doesn't use the unit of days.
long monthsBetween = ChronoUnit.MONTHS.between(
YearMonth.from(LocalDate.parse("2016-08-31")),
YearMonth.from(LocalDate.parse("2016-11-30"))
)
System.out.println(monthsBetween); //3
Since Java8:
ChronoUnit.MONTHS.between(startDate, endDate);
//Backward compatible with older Java
public static int monthsBetween(Date d1, Date d2){
if(d2==null || d1==null){
return -1;//Error
}
Calendar m_calendar=Calendar.getInstance();
m_calendar.setTime(d1);
int nMonth1=12*m_calendar.get(Calendar.YEAR)+m_calendar.get(Calendar.MONTH);
m_calendar.setTime(d2);
int nMonth2=12*m_calendar.get(Calendar.YEAR)+m_calendar.get(Calendar.MONTH);
return java.lang.Math.abs(nMonth2-nMonth1);
}
The documentation of Period#between states the following:
The start date is included, but the end date is not.
Furthermore:
A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
Your end day-of-month 30 is not greater than or equal to your start day-of-month 31, so a third month is not considered.
Note the parameter names:
public static Period between​(LocalDate startDateInclusive, LocalDate endDateExclusive)
To return 3 months, you can increment the endDateExclusive by a single day.
In case you want stick to java.time.Period API
As per java.time.Period documentation
Period between(LocalDate startDateInclusive, LocalDate endDateExclusive)
where
#param startDateInclusive the start date, inclusive, not null
#param endDateExclusive the end date, exclusive, not null
So it is better to adjust your implementation to make your end date inclusive and get your desired result
Period diff = Period.between(LocalDate.parse("2016-08-31"),
LocalDate.parse("2016-11-30").plusDays(1));
System.out.println("Months : " + diff.getMonths());
//Output -> Months : 3
You have to be careful, never use LocalDateTime to calculate months between two dates the result is weird and incorrect, always use LocalDate !
here's is some code to prove the above:
package stack.time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class TestMonthsDateTime {
public static void main(String[] args) {
/**------------------Date Time----------------------------*/
LocalDateTime t1 = LocalDateTime.now();
LocalDateTime t2 = LocalDateTime.now().minusMonths(3);
long dateTimeDiff = ChronoUnit.MONTHS.between(t2, t1);
System.out.println("diff dateTime : " + dateTimeDiff); // diff dateTime : 2
/**-------------------------Date----------------------------*/
LocalDate t3 = LocalDate.now();
LocalDate t4 = LocalDate.now().minusMonths(3);
long dateDiff = ChronoUnit.MONTHS.between(t4, t3);
System.out.println("diff date : " + dateDiff); // diff date : 3
}
}
My 2%
This example checks to see if the second date is the end of that month. If it is the end of that month and if the first date of month is greater than the second month date it will know it will need to add 1
LocalDate date1 = LocalDate.parse("2016-08-31");
LocalDate date2 = LocalDate.parse("2016-11-30");
long monthsBetween = ChronoUnit.MONTHS.between(
date1,
date2);
if (date1.isBefore(date2)
&& date2.getDayOfMonth() == date2.lengthOfMonth()
&& date1.getDayOfMonth() > date2.getDayOfMonth()) {
monthsBetween += 1;
}
After the short investigation, still not totally fix my question, But I used a dirty solution to avoid return the incorrect duration. At least, we can get the reasonable duration months.
private static long durationMonths(LocalDate dateBefore, LocalDate dateAfter) {
System.out.println(dateBefore+" "+dateAfter);
if (dateBefore.getDayOfMonth() > 28) {
dateBefore = dateBefore.minusDays(5);
} else if (dateAfter.getDayOfMonth() > 28) {
dateAfter = dateAfter.minusDays(5);
}
return ChronoUnit.MONTHS.between(dateBefore, dateAfter);
}
The Java API response is mathematically accurate according to the calendar. But you need a similar mechanism, such as rounding decimals, to get the number of months between dates that matches the human perception of the approximate number of months between two dates.
Period period = Period.between(LocalDate.parse("2016-08-31"), LocalDate.parse("2016-11-30"));
long months = period.toTotalMonths();
if (period.getDays() >= 15) {
months++;
}

Unexpected date calculation result

I have a method to view a calendar in Java that calculates the date by year, day of the week and week-number.
Now when I calculates the dates from 2017 everything works. But when I calculates the dates from January 2018 it takes the dates of year 2017.
My code looks like
import java.time.temporal.IsoFields;
import java.time.temporal.ChronoField;
import java.time.LocalDate;
// .....
LocalDate desiredDate = LocalDate.now()
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 1)
.with(ChronoField.DAY_OF_WEEK, 1)
.withYear(2018);
Which results in 2018-01-02 and it should be 2018-01-01. How is this possible?
The order of invoked methods seems matter.
It you invoke them by descending time-granularity (year, week of week and day of week), you get the correct result :
long weekNumber = 1;
long dayOfWeek = 1;
int year = 2018;
LocalDate desiredDate = LocalDate.now()
.withYear(year)
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
.with(ChronoField.DAY_OF_WEEK, dayOfWeek );
System.out.println(desiredDate);
2018-01-01
Note that the problem origin comes from :
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
that sets the week number (1 to 53) according to the current year.
The Java LocalDate API cannot adapt this value if then you change the year with .withYear(year) as the week number information is not kept in the LocalDate instance.
You can indeed see in LocalDate implementation that LocalDate instances are defined by only 3 field : year, month and day.
public final class LocalDate
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
...
private final int year;
/**
* The month-of-year.
*/
private final short month;
/**
* The day-of-month.
*/
private final short day;
...
}
So to be precise, the important thing is that :
.withYear(year) be invoked before
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);
I want to mention, that there is another Problem(?) with LocalDate.
This Code does also create a wrong result:
int jahr = Integer.parseInt(str[0]);
int woche = Integer.parseInt(str[1]);
LocalDate year = LocalDate.of(jahr, 1, 1);
LocalDate week = year.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, woche);
LocalDate day = week.with(wochentag);
return day;
If you change the creation of the year variable to
LocalDate year = LocalDate.now().withYear(jahr);
the code returns the expected result. It seems as the way you construct a LocalDate matters. I guess the timezone is omitted in the ".of()" version.

Java get the date of the nearest incoming certain day of week [duplicate]

This question already has answers here:
Get first Monday after certain date?
(5 answers)
Closed 6 years ago.
Hello at first i would like to note that i have found several posts with the same question here, but NONE of them worked for me. i am creating alarm clock application for android and the last thing i need is: get the date of the nearest certain day in week.
I have found several algorithms here and i will also copy one here :
import java.util.Calendar;
public class NextWednesday {
public static Calendar nextDayOfWeek(int dow) {
Calendar date = Calendar.getInstance();
int diff = dow - date.get(Calendar.DAY_OF_WEEK);
if (!(diff > 0)) {
diff += 7;
}
date.add(Calendar.DAY_OF_MONTH, diff);
return date;
}
public static void main(String[] args) {
System.out.printf(
"%ta, %<tb %<te, %<tY",
nextDayOfWeek(Calendar.WEDNESDAY) // this can contain any of the 7 days in week
);
}
}
Today is tuesday in my country
If i put wednesday in the function it returns me the wednesday that is in the next week, but thats not correct.
This algorithm automatically looks at the following week no matter if its just monday and theres whole week before you, it jumps to the next week and does its job but thats not correct, i need to implement the same behaviour but it must start from today.
Example: Today is Monday, i am looking for wednesday
Correct output: Date of wednesday in this week.
Uncorrect output: Date of wednesday in the next week.
I hope its clear enough.
Okay, algorithm works correctly, i made a simple mistake, i was passing wrong day to the function, i passed the current day, not the one that was chosen by the user
If you wish to keep it simple.
public Date getNextDate(int dayOfWeek) {
Calendar c = Calendar.getInstance();
for ( int i = 0; i < 7; i++ ) {
if ( c.get(Calendar.DAY_OF_WEEK) == dayOfWeek ) {
return c.getTime();
} else {
c.add(Calendar.DAY_OF_WEEK, 1);
}
}
return c.getTime();
}

Get days between two dates?

I am trying to get the days between two values. Which is in the format of MMdd.
Ex:
First Date = 0501
Second Date = 0519
Trying to find the value of days between the two dates. In this example would be 18. Please help me with this. I tried searching around and can't find a solution. Thank you!
My Code
This is what I have so far:
Getting an error: Method days in class Project3 cannot be applied to the given type.
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
public class Project3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String name = input.next() + input.nextLine();
String car = input.next() + input.nextLine();
String key = input.next();
String firstDate = input.next(), lastDate = input.next();
double S = 1.0, C = 1.2, U = 1.4, T = 1.6, B = 2.0;
final double N = 89.22, V = (N - 11.4);
double daily, total;
String daysBetween = Project3.days();
}
public static long days(Date firstDate, Date lastDate) {
Calendar start = Calendar.getInstance();
start.setTime(firstDate);
Calendar end = Calendar.getInstance();
long daysBetween = 0;
while (start.before(end)) {
start.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
}
Using Joda Time Days:
DateTimeFormatter dtf = DateTimeFormat.forPattern("MMdd");
LocalDate day1 = dtf.parseLocalDate("0501");
LocalDate day2 = dtf.parseLocalDate("0519");
int daysBetween = Days.daysBetween(day1, day2).getDays();
Joda time is the right way to do this, but if you really have to do it with pure JDK stuff, you can calculate it yourself.
A Calendar instance has a .getTimeInMillis() method that tells you the number of milliseconds since some fixed start point. You can take two dates, put them into Calendar instances, and then calculate the difference between the two getTimeInMillis() values.
Then divide by 1000 to get seconds; by 60 to get minutes; by 60 to get hours; by 24 to get days. And cross your fingers and hope for the best with regard to daylight saving time.
You have one other issue to get round, which is that since you've only got a day and a month, but not a year, there isn't a unique answer. The difference in days between 28 Feb and 1 Mar is one day in most years, but two days in a leap year. If you want to assume Feb has only 28 days, just choose any non-leap year you like (e.g., 2014).
This is a method for calculating the number of days between two dates. It keeps rolling the day forward, while the start date is before the end date. It works regardless of differences in time due to daylight saving time.
public static long days(Date startDate, Date endDate) {
Calendar start = Calendar.getInstance();
start.setTime(startDate);
Calendar end = Calendar.getInstance();
long daysBetween = 0;
while(start.before(end)) {
start.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}

Categories

Resources