Java: How to get next time that matches pattern - java

Is there an easy/direct way to use a DateTimeFormatter pattern to get the next LocalDateTime time that matches that pattern?
I'd like to use this to easily get the next time that an event should happen (could be daily, weekly, monthly, etc.). For example, if an event happens at "Monday 12:00 AM", I would like to get a LocalDateTime for the next Monday at 12:00 AM.
/**Get next LocalDateTime that matches this input
*
* #param input a String for time matching the pattern: [dayOfWeek ][dayOfMonth ][month ][year ]<timeOfDay> <AM/PM>
* #return LocalDateTime representing the next time that matches the input*/
public LocalDateTime getNextTime(String input) {
LocalDateTime currentTime = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("[eeee ][d ][MMMM ][u ]h:m a");
TemporalAccessor accessor = format.parse(input);
// TODO somehow get the next time (that's after currentTime) that matches this pattern
// LocalDateTime time = ???
return time;
}
I can't just do LocalDateTime.from(accessor) because there might not be a year, month, or day of month specified in the input.
To clarify, here are some examples of what I would like:
// if current date is Friday, January 1st, 2021 at 12:00 PM
// this should return a LocalDateTime for Monday, January 4th, 2021 12:00 AM
getNextTime("Monday 12:00 AM");
// should return Saturday, January 2nd, 2021 12:00 AM
getNextTime("12:00 AM");
// should return Tuesday, January 5th, 2021 12:00 AM
getNextTime("5 January 12:00 AM");
// should return Friday, January 8th, 2021 12:00 PM (must be AFTER current time)
getNextTime("Friday 12:00 PM");

No, there is neither an easy nor a direct way to do what you are asking for. It involves quite a bit of coding. You basically have got 16 cases because each of year, month, day of month and day of week may or may not be present. And you more or less will have to handle each case separately.
Also there may not be such a next time. If the year is 2019 there isn’t. If the string is Friday 12 January 2021 2:00 AM, there isn’t because 12 January is a Tuesday, not a Friday.
private static DateTimeFormatter format = DateTimeFormatter
.ofPattern("[eeee ][uuuu ][d ][MMMM ][uuuu ]h:m a", Locale.ENGLISH);
// input = [dayOfWeek] [dayOfMonth] [month] [year] <timeOfDay> <AM/PM>
public static LocalDateTime next(String text) {
TemporalAccessor accessor;
try {
accessor = format.parse(text);
} catch (DateTimeParseException dtpe) {
return null;
}
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
LocalTime parsedTime = LocalTime.from(accessor);
LocalDate earliest = now.toLocalDate();
if (parsedTime.isBefore(now.toLocalTime())) {
earliest = earliest.plusDays(1);
}
return resolveYearMonthDomDow(earliest, accessor).atTime(parsedTime);
}
private static LocalDate resolveYearMonthDomDow(LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.YEAR)) {
Year parsedYear = Year.from(accessor);
if (parsedYear.isBefore(Year.from(earliest))) {
return null;
}
return resolveMonthDomDow(parsedYear, earliest, accessor);
} else {
Year candidateYear = Year.from(earliest);
while (true) {
LocalDate resolved = resolveMonthDomDow(candidateYear, earliest, accessor);
if (resolved != null) {
return resolved;
}
candidateYear = candidateYear.plusYears(1);
}
}
}
private static LocalDate resolveMonthDomDow(Year year, LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.MONTH_OF_YEAR)) {
YearMonth knownYm = year.atMonth(accessor.get(ChronoField.MONTH_OF_YEAR));
if (knownYm.isBefore(YearMonth.from(earliest))) {
return null;
}
return resolveDomDow(knownYm, earliest, accessor);
} else {
YearMonth candidateYearMonth = YearMonth.from(earliest);
if (candidateYearMonth.getYear() < year.getValue()) {
candidateYearMonth = year.atMonth(Month.JANUARY);
}
while (candidateYearMonth.getYear() == year.getValue()) {
LocalDate resolved = resolveDomDow(candidateYearMonth, earliest, accessor);
if (resolved != null) {
return resolved;
}
candidateYearMonth = candidateYearMonth.plusMonths(1);
}
return null;
}
}
private static LocalDate resolveDomDow(YearMonth ym, LocalDate earliest, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.DAY_OF_MONTH)) {
int dayOfMonth = accessor.get(ChronoField.DAY_OF_MONTH);
if (dayOfMonth > ym.lengthOfMonth()) {
return null;
}
LocalDate resolved = ym.atDay(dayOfMonth);
if (resolved.isBefore(earliest)) {
return null;
} else {
return resolveDow(resolved, accessor);
}
} else {
LocalDate candidateDate = earliest;
if (YearMonth.from(earliest).isBefore(ym)) {
candidateDate = ym.atDay(1);
}
while (YearMonth.from(candidateDate).equals(ym)) {
LocalDate resolved = resolveDow(candidateDate, accessor);
if (resolved != null) {
return resolved;
}
candidateDate = candidateDate.plusDays(1);
}
return null;
}
}
private static LocalDate resolveDow(LocalDate date, TemporalAccessor accessor) {
if (accessor.isSupported(ChronoField.DAY_OF_WEEK)) {
if (date.getDayOfWeek().getValue() == accessor.get(ChronoField.DAY_OF_WEEK)) {
return date;
} else {
return null;
}
} else {
return date;
}
}
Let’s try it out:
String input = "Monday 12:00 AM";
// get the next time that matches this pattern
LocalDateTime time = next(input);
System.out.println(time);
Output when I ran just now (Monday Januar 11, 2021 in the evening):
2021-01-18T00:00
So next Monday. Looks right.
For a different example, showing that leap years are respected:
String input = "Wednesday 29 February 12:00 AM";
2040-02-29T00:00
There are most probably bugs in my code, but the basic idea is working.
The time of day poses no problem. The challenge is with the date. I am using the time of day to determine whether today’s date is an earliest candidate. If the time now is already past the time in the string, the earliest possible date is tomorrow. For your example string, Monday 12:00 AM, this will practically always be the case: it is always after 12 midnight.
You had got an ambiguity in Monday 25 12:00 AM since 25 may be a year (a couple of millennia ago) or a day of month. I solved it by insisting on a four digit year. So if a number in the beginning or right after a day of week has four digits, it’s a year, otherwise it’s a day of month. The formatter I use looks funny, the year comes twice. I needed this to force the parsing to try year before trying day of month, or it would sometimes have taken a four digit number to be day of month. This in turn means that the formatter accepts a few formats too many. I figure it won’t be a problem in practice.

Provided your input is well formatted and is always in English, you could split your input at the first space and use it as follows:
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;
public class Example {
public static void main(String[] args) {
LocalDateTime desiredDay = getNextDayTime("Friday 12:00 AM");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm a");
System.out.println(dtf.format(desiredDay));
}
public static LocalDateTime getNextDayTime(String input){
String[] splited = input.split(" ", 2);
LocalTime localTime = LocalTime.parse(splited[1], DateTimeFormatter.ofPattern("hh:mm a", Locale.US));
LocalDateTime dateTime = LocalDateTime.now().with(localTime);
LocalDateTime desiredDay = dateTime.with(TemporalAdjusters.next(DayOfWeek.valueOf(splited[0].toUpperCase())));
return desiredDay;
}
}

Related

Get correct week Start date and end date when monday , tuesday falls in last year last week

I am getting week number and year from DB(using function DATE_PART('week',alarm_date - (interval '1 days') * 0) AS week, DATE_PART('year',alarm_date) AS yearNo , ISO compliant) and on the basis of week number and year i want to calculate weekStartDate and weekEndDate between user provided startdate and end date with week start date for example {"startDate":"2021-12-28","endDate":"2022-01-06","weekStartDay":"Sunday"}
private String getWeek(LocalDate startTime, LocalDate endTime, int yearNo, int weekNumber, int weekStartDay){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
// make it ISO compliant since postgres is using ISO time to calculate week number
cal.setMinimalDaysInFirstWeek(4);
cal.set(Calendar.YEAR, yearNo);
cal.set(Calendar.WEEK_OF_YEAR, weekNumber);
//ISO week starts on Monday and ends on Sunday
cal.set(Calendar.DAY_OF_WEEK, weekStartDay);// weekStartDay configurabale, as per
//user input Calendar.SUNDAY or Calendar.MONDAY or Calendar.TUEDAY; etc
String weekStartDate = sdf.format(cal.getTime());
cal.add(Calendar.DATE, 6);
String weekEndDate = sdf.format(cal.getTime());
LocalDate weekStart = LocalDate.of(Integer.valueOf(weekStartDate.substring(0, 4)),
Integer.valueOf(weekStartDate.substring(5, 7)), Integer.valueOf(weekStartDate.substring(8)));
if(weekStart.isBefore(startTime)) {
weekStart = startTime;
}
LocalDate weekEnd = LocalDate.of(Integer.valueOf(weekEndDate.substring(0, 4)),
Integer.valueOf(weekEndDate.substring(5, 7)), Integer.valueOf(weekEndDate.substring(8)));
if(weekEnd.isAfter(endTime)) {
weekEnd = endTime;
}
String weekStr = weekStart.toString()+"_"+weekEnd.toString();
return weekStr;
}
But when weekStartDay falls in lastweek of previous year then it gives the wrong vale of weekStartDate and weekStartEnd so please suggest me how to set yearnumber in java
Avinash, not the full answer but in-line with what Tom mentioned. A lot of convinient date time API's can be used since Java-8. Please feel free to customize this approach for the exact logic you may need
import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import static java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.TemporalAdjusters;
public class SO75013931 {
public static void main(String[] args) {
System.out.println(getWeekStart(LocalDate.parse("2021-12-28"),DayOfWeek.SUNDAY));
System.out.println(getWeekEnd(LocalDate.parse("2021-12-28"),DayOfWeek.SUNDAY));
}
//28-12-2021 TO 01-01-2022 && 02-01-2022 to 06-01-2022
private static String getWeekStart(LocalDate localDate, DayOfWeek weekStartDay) {
LocalDate weekStart = localDate.with(TemporalAdjusters.previous(weekStartDay));
return weekStart.isBefore(localDate) ? localDate.toString(): weekStart.toString();
}
private static String getWeekEnd(LocalDate localDate, DayOfWeek weekStartDay) {
LocalDate weekEnd = localDate.with(TemporalAdjusters.next(weekStartDay.minus(1)));
return weekEnd.isBefore(localDate) ? localDate.toString(): weekEnd.toString();
}
}
This would give
2021-12-28
2022-01-01
Again, the idea was to recommend usage of these API's as opposed to older util API's

Java LocalDate How to utilize

input list
from date ex) 2020-10-01
to date ex) 2020-10-30
List [day of week] ex) [sun,mon....]
List [week] ex) [1,4,5]
I would like to know how to get a specific day of the week between the two dates.
Thank.
from date ex) 2020-10-01 to date ex) 2020-10-30
Your input string is already in the ISO8601 format for date and therefore it can be parsed without providing a DateTimeFormatter explicitly. In order to get the output string in a custom format (e.g. yyyy-MM-dd), you need to format the date object using DateTimeFormatter.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String inputStrDate = "2020-10-01";
LocalDate date = LocalDate.parse(inputStrDate);
String outputStrDate = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
System.out.println(outputStrDate);
}
}
Output:
2020-10-01
However, if your input is some other format, you will need to use DateTimeFormatter in order to parse it to a date object.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Formatter for input string
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy");
String inputStrDate = "10-01-2020";
LocalDate date = LocalDate.parse(inputStrDate, inputFormat);
// Formatter for output string
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String outputStrDate = date.format(outputFormat);
System.out.println(outputStrDate);
}
}
Output:
2020-10-01
Learn more about date-time API from Trail: Date Time.
for(LocalDate d = fromDate; !d.isAfter(toDate); d = d.plusDays(1)) { // 일정 시작 ~ 끝 loop
for (Integer wf : weekOfMonth) {
for (Integer df : dayOfWeek) {
offDay = d.with(fieldWeek, wf)
.with(fieldDay, df);
if (d.getMonth() == offDay.getMonth() && !offDays.contains(offDay)) {
offDays.add(offDay);
}
}
}
}
Sorry for asking the wrong question.
And thank you very much.
I've already made it, but I've studied your code.
java.time
I too recommend that you use java.time, the modern Java date and time API, for your date work. My shot is:
LocalDate fromDate = LocalDate.of(2020, Month.OCTOBER, 1);
LocalDate toDate = LocalDate.of(2020, Month.OCTOBER, 30);
List<DayOfWeek> daysOfWeek = List.of(DayOfWeek.SUNDAY, DayOfWeek.MONDAY);
List<Integer> weeks = List.of(1, 4, 5);
if (! YearMonth.from(fromDate).equals(YearMonth.from(toDate))) {
throw new IllegalStateException("Covering more than one month is not yet supported");
}
WeekFields wf = WeekFields.SUNDAY_START;
for (int week : weeks) {
for (DayOfWeek dow : daysOfWeek) {
LocalDate date = fromDate.with(wf.weekOfMonth(), week)
.with(wf.dayOfWeek(), dow.get(wf.dayOfWeek()));
// Is date inside interval?
if (! (date.isBefore(fromDate) || date.isAfter(toDate))) {
System.out.println(date);
}
}
}
Output:
2020-10-18
2020-10-19
2020-10-25
2020-10-26
The dates printed are Sunday and Monday of weeks 4 and 5 of October defining weeks in the American way where the week begins on Sunday (since you mentioned Sunday first in your example list) and week 1 is the week of October 1. Sunday and Monday of week 1 are not printed because they fall before October 1, that is, in September.
Consider which week scheme you require. You may use for example WeekFields.ISO or WeekFields.of(Locale.getDefault()).
I am finding the week first, then the day of week, because to me this is the natural way. I need to use the WeekFields object for both adjustments to make sure that the chosen week scheme is respected.
If you need to cover more than one calendar month, iterate over the months and do the same for each. Also check that the result date falls within the month so duplicates near month borders are ignored.

How to traverse between a given time (i.e.11:00 am) and another time (i.e. 1:00 pm) in java?

I am making an Online Reservation System for a Restaurant in java. I want to know if a table is reserved. I have come up with this code.
I am not sure how to implement this logic.
public class Services {
public void reserveTable(String tableSize ,int time_limit){
String starting_time = "11:00 am";
String ending_time = "1:00 pm";
String current_time = "12:00 pm"; //time at which new order arrived
boolean reserved = false
for (String start = "11:00 am"; start <= ending_time; start ++){
if (current_time == start){
reserved = true;
}
}
}
}
You can use a DateTimeFormatter to parse your time strings into LocalTimes, and then check if the current is between the start and end:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("h:mm a")
.toFormatter(Locale.ENGLISH);
LocalTime start = LocalTime.parse("11:00 am", formatter);
LocalTime end = LocalTime.parse("1:00 pm", formatter);
LocalTime current = LocalTime.parse("12:00 pm", formatter);
boolean reserved = false;
if (current.isAfter(start) && current.isBefore(end)) {
reserved = true;
}
Note that this won't work if the start and end span across midnight. e.g. start is 11pm and end is 2am. A current of 1am won't cause reserved to be set to true. For this case to work you need a date.

Format credit card date MM/yy to MM/dd/yyyy

I have method that can take 2 different types of date formats:
MM/YY (credit card expiration date)
yyyyMMdd (funding expiration date)
Credit card expiration date is considered expired on the last day of that month. So, if cc date is May, 2017 (05/17), this cc is considered expired on 31th of May.
Funding expiration date will expire on the day it says it expires. So, if I am looking at it on the same day, it should return TRUE as funding has expired.
This is my code:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public static boolean dateHasExpired(String dateInput)
{
LocalDate d = LocalDate.now();
LocalDate dateParsed = null;
if (dateInput.contains("/"))
{
int iYear = Integer.parseInt(dateInput.substring(dateInput.indexOf("/") + 1));
int iMonth = Integer.parseInt(dateInput.substring(0, dateInput.indexOf("/")));
int daysInMonth = LocalDate.of(iYear, iMonth, 1).getMonth().maxLength();
dateInput = iMonth+"/"+daysInMonth+"/"+iYear;
}
else
{
dateInput = ConvertDate(dateInput, "yyyyMMdd", "MM/dd/yyyy");
}
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
dateParsed = LocalDate.parse(dateInput, dateTimeFormatter);
return d.compareTo(dateParsed) <= 0;
}
public static String ConvertDate(String dateValue, String currentFormat, String requiredFormat)
{
SimpleDateFormat inFormatter = new SimpleDateFormat(currentFormat);
SimpleDateFormat outFormatter = new SimpleDateFormat(requiredFormat);
String outDate = "";
try
{
java.util.Date date = inFormatter.parse(dateValue);
outDate = outFormatter.format(date);
}
catch (ParseException e) {
ErrorLogger.logError ( e );
}
return outDate;
}
Does anyone know of better way of doing this?
I also noticed LocalDate doesn't account for Leap Year, so Feb 2015 has 29 days, just like Feb 2016, so my daysInMonth will not be a good number.
Looks like Date is more tollerant than LocalDate when it comes to year being yy and month 5 for month of May.
You can use java.time.YearMonth class, which contains a method that returns the last day of the respective month (and also takes care of leap years):
public static boolean dateHasExpired(String dateInput) {
LocalDate today = LocalDate.now();
LocalDate dateParsed = null;
if (dateInput.contains("/")) {
// parse credit card expiration date
YearMonth ym = YearMonth.parse(dateInput, DateTimeFormatter.ofPattern("MM/yy"));
// get last day of month (taking care of leap years)
dateParsed = ym.atEndOfMonth();
} else {
// parse funding expiration date
dateParsed = LocalDate.parse(dateInput, DateTimeFormatter.ofPattern("yyyyMMdd"));
}
// expired if today is equals or after dateParsed
return ! today.isBefore(dateParsed);
}
With this code (considering that today is May 02, 2017):
System.out.println(dateHasExpired("04/17")); // true
System.out.println(dateHasExpired("05/17")); // false
System.out.println(dateHasExpired("06/17")); // false
System.out.println(dateHasExpired("20170501")); //true
System.out.println(dateHasExpired("20170502")); // true
System.out.println(dateHasExpired("20170503")); // false
Note that atEndOfMonth() method takes care of leap years, so these will also work:
System.out.println(dateHasExpired("02/15"));
System.out.println(dateHasExpired("02/16"));
I've added a System.out.println(dateParsed); in dateHasExpired method, just to check if the date is being parsed correctly. And the output for the dates above are (respectively):
2015-02-28
2016-02-29
And dateHasExpired returns true for both, as expected.

Get the first Monday of a month

I want to get the day on which the first Monday of a specific month/year will be.
What I have:
I basically have two int variables, one representing the year and one representing the month.
What I want to have:
I want to know the first Monday in this month, preferably as an int or Integer value.
For example:
I have 2014 and 1 (January), the first Monday in this month was the 6th, so I want to return 6.
Problems:
I thought I could do that with the Calendar but I am already having trouble setting up the calendar with only Year and Month available. Furthermore, I'm not sure how to actually return the first Monday of the month/year with Calendar.
I already tried this:
Calendar cal = Calendar.getInstance();
cal.set(this.getYear(),getMonth(), 1);
int montag = cal.getFirstDayOfWeek();
for( int j = 0; j < 7; j++ ) {
int calc = j - montag;
if( calc < 0 ) {
calc += 6;
}
weekDays[calc].setText(getDayString(calc));
}
Java.time
Use java.time library built into Java 8 and TemporalAdjuster. See Tutorial.
import java.time.DayOfWeek;
import java.time.LocalDate;
import static java.time.temporal.TemporalAdjusters.firstInMonth;
LocalDate now = LocalDate.now(); //2015-11-23
LocalDate firstMonday = now.with(firstInMonth(DayOfWeek.MONDAY)); //2015-11-02 (Monday)
If you need to add time information, you may use any available LocalDate to LocalDateTime conversion like
firstMonday.atStartOfDay() # 2015-11-02T00:00
getFirstDayOfWeek() returns which day is used as the start for the current locale. Some people consider the first day Monday, others Sunday, etc.
This looks like you'll have to just set it for DAY_OF_WEEK = MONDAY and DAY_OF_WEEK_IN_MONTH = 1 as that'll give you the first Monday of the month. To do the same for the year, first set the MONTH value to JANUARY then repeat the above.
Example:
private static Calendar cacheCalendar;
public static int getFirstMonday(int year, int month) {
cacheCalendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
cacheCalendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, 1);
cacheCalendar.set(Calendar.MONTH, month);
cacheCalendar.set(Calendar.YEAR, year);
return cacheCalendar.get(Calendar.DATE);
}
public static int getFirstMonday(int year) {
return getFirstMonday(year, Calendar.JANUARY);
}
Here's a simple JUnit that tests it: http://pastebin.com/YpFUkjQG
First of all you should know the latest version of java i.e. JAVA8
Get familiar with LocalDate in JAVA8
Then only go through below code
public class Test {
public static void main(String[] args) {
LocalDate date=LocalDate.of(2014,1, 1);
for(int i=0;i<date.lengthOfMonth();i++){
if("Monday".equalsIgnoreCase(date.getDayOfWeek().toString())){
break;
}else{
date=date.plusDays(1);
}
}
System.out.println(date.getDayOfMonth());
}
}
Joda-Time
The Joda-Time library offers a class, LocalDate, for when you need only a date without a time-of-day. The method getDayOfWeek returns a number you can compare to the constant MONDAY.
LocalDate localDate = new LocalDate( year, month, 1 );
while ( localDate.getDayOfWeek() != DateTimeConstants.MONDAY ) {
localDate = localDate.plusDays( 1 );
}
int firstMonday = localDate.getDayOfMonth();
Immutable Syntax
For thread-safety, Joda-Time uses immutable objects. So rather than modify field values in an existing object, we create a new instance based on the original.
java.time
As another answer by Abhishek Mishra says, the new java.time package bundled with Java 8 also offers a LocalDate class similar to Joda-Time.
The method getFirstDayOfWeek() is not helpful. Quoting its javadoc:
Gets what the first day of the week is; e.g., SUNDAY in the U.S., MONDAY in France
The following tested method uses modulus arithmetic to find the day of the month of the first Monday:
public static long getMondaysDay(int year, int month) {
try {
Date d = new SimpleDateFormat("d-M-yyyy").parse("1-" + month + "-" + year);
long epochMillis = d.getTime() + TimeZone.getDefault().getOffset(d.getTime());
return (12 - TimeUnit.MILLISECONDS.toDays(epochMillis) % 7) % 7;
} catch (ParseException ignore) { return 0; } // Never going to happen
}
Knowing that the first day of the epoch was Thursday, this works by using modulus arithmetic to calculate the day of the epoch week, then how many days until the next Monday, then modulus again in case the first falls before Thursday. The magic number 12 is 4 (the number of days from Thursday to Monday) plus 1 because days of the month start from 1 plus 7 to ensure positive results after subtraction.
The simplest way is:
LocalDate firstSundayOfNextMonth = LocalDate
.now()
.with(firstDayOfNextMonth())
.with(nextOrSame(DayOfWeek.MONDAY));
Here is a general function to get the nth DAY_OF_WEEK of a given month. You can use it to get the first Monday of any given month.
import java.util.Calendar;
public class NthDayOfWeekOfMonth {
public static void main(String[] args) {
// get first Monday of July 2019
Calendar cal = getNthDayOfWeekOfMonth(2019,Calendar.JULY,1,Calendar.MONDAY);
System.out.println(cal.getTime());
// get first Monday of August 2019
cal = getNthDayOfWeekOfMonth(2019,Calendar.AUGUST,1,Calendar.MONDAY);
System.out.println(cal.getTime());
// get third Friday of September 2019
cal = getNthDayOfWeekOfMonth(2019,Calendar.SEPTEMBER,3,Calendar.FRIDAY);
System.out.println(cal.getTime());
}
public static Calendar getNthDayOfWeekOfMonth(int year, int month, int n, int dayOfWeek) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.YEAR,year);
cal.set(Calendar.MONTH,month);
cal.set(Calendar.DAY_OF_MONTH,1);
int dayDiff = dayOfWeek-cal.get(Calendar.DAY_OF_WEEK);
if (dayDiff<0) {
dayDiff+=7;
}
dayDiff+=7*(n-1);
cal.add(Calendar.DATE, dayDiff);
return cal;
}
}
Output:
Mon Jul 01 00:00:00 EDT 2019
Mon Aug 05 00:00:00 EDT 2019
Fri Sep 20 00:00:00 EDT 2019
Lamma Date library is very good for this use case.
#Test
public void test() {
assertEquals(new Date(2014, 1, 6), firstMonday(2014, 1));
assertEquals(new Date(2014, 2, 3), firstMonday(2014, 2));
assertEquals(new Date(2014, 3, 3), firstMonday(2014, 3));
assertEquals(new Date(2014, 4, 7), firstMonday(2014, 4));
assertEquals(new Date(2014, 5, 5), firstMonday(2014, 5));
assertEquals(new Date(2014, 6, 2), firstMonday(2014, 6));
}
public Date firstMonday(int year, int month) {
Date firstDayOfMonth = new Date(year, month, 1);
return firstDayOfMonth.nextOrSame(DayOfWeek.MONDAY);
}
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("MMM/dd/YYYY");
calendar.set(Calendar.MONTH,Calendar.JUNE);
calendar.set(Calendar.DAY_OF_MONTH,1);
int day = (Calendar.TUESDAY-calendar.get(Calendar.DAY_OF_WEEK));
if(day<0){
calendar.add(Calendar.DATE,7+(day));
}else{
calendar.add(Calendar.DATE,day);
}
System.out.println("First date is "+sdf.format(calendar.getTime()));
Get the All Monday of a month
public class AllMonday {
public static void main(String[] args){
System.out.println(weeksInCalendar(YearMonth.now()));
}
public static List<LocalDate> weeksInCalendar(YearMonth month) {
List<LocalDate> firstDaysOfWeeks = new ArrayList<>();
for (LocalDate day = firstDayOfCalendar(month);
stillInCalendar(month, day); day = day.plusWeeks(1)) {
firstDaysOfWeeks.add(day);
}
return firstDaysOfWeeks;
}
private static LocalDate firstDayOfCalendar(YearMonth month) {
DayOfWeek FIRST_DAY_OF_WEEK = DayOfWeek.of(1);
System.out.println( month.atDay(1).with(FIRST_DAY_OF_WEEK));
return month.atDay(1).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
}
private static boolean stillInCalendar(YearMonth yearMonth, LocalDate day) {
System.out.println(!day.isAfter(yearMonth.atEndOfMonth()));
return !day.isAfter(yearMonth.atEndOfMonth());
}
}

Categories

Resources