Let's say I have the current day, the next day, and the previous day. And I want to write a method that finds the first business day of the month by doing logical operations on them. For example, the first working day of November 2021 starts on the 4th, because the 3rd of the month has no working days due to holidays. In short, we need to write a program that takes into account non-working days and finds the first working day of each month.
Well, there is no standard Java library to get the dates of the holidays. That would be too localized, because holidays heavily depend on your country and region (except for widely known holidays, such as Christmas or Easter).
You must rely on some external source, for instance a holiday API. Once you have the holidays, you could easily get the first business day of a month.
In the code below, I've hardcoded the holidays as a Set of LocalDates. I also assumed that business days are from Monday to Friday.
public static Optional<LocalDate> firstBusinessDayOfMonth(YearMonth month) {
// I've hardcoded the holidays as LocalDates
// and put them in a Set
final Set<LocalDate> holidays = Set.of(
LocalDate.of(2021, 11, 1),
LocalDate.of(2021, 11, 2),
LocalDate.of(2021, 11, 3)
);
// For the sake of efficiency, I also put the business days into a Set.
// In general, a Set has a better lookup speed than a List.
final Set<DayOfWeek> businessDays = EnumSet.of(
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
);
return
// All dates of the month
month.atDay(1).datesUntil(month.plusMonths(1).atDay(1))
// Retain all business days. Use static imports from
// java.time.DayOfWeek.*
.filter(date -> businessDays.contains(date.getDayOfWeek()))
// Retain only dates not present in our holidays list
.filter(date -> !holidays.contains(date))
// Get the first
.findFirst();
}
To get the first business day of the current month, use firstBusinessDayOfMonth(YearMonth.now()).
Note that this method returns an Optional, because it could theoretically be the case that there is no business day within the whole month.
Thanks for all the answers and help, but this is what I wanted.
Here, in my isOperateDay variable, they say that the data they have already sent me from the other server is 1 business day, not 0 business day. What I just wanted to do was to check if the values between yesterday and today are the first working day.
As you can see, I'm taking yesterday's month and comparing it to today's month, if yesterday's month is different, it means it was the previous month and my current day's month is counted as the first working day.
#Data
class ST_XF_DWH {
private LocalDateTime previousDate;
private LocalDateTime currentDate;
private int isOperateDate;
}
public void isFirstWorkDay(ST_XF_DWH st_xf_dwh) {
LocalDateTime previousDate = st_xf_dwh.getPreviousDate();
LocalDateTime currentDate = st_xf_dwh.getCurrentDate();
if (previousDate.getMonth() != currentDate.getMonth() && st_xf_dwh.getIsOperateDate() == 1) {
System.out.println("Is First Work Day" + st_xf_dwh.getCurrentDate());
} else {
System.out.println(st_xf_dwh.getCurrentDate() + "is not First Work Day");
}
}
Related
I am trying to figure out find out list of calendar dates from two specific dates. But I am getting only within a same year not fix two dates.
What I have done:
private ArrayList<Calendar> weekendList = null;
public void findWeekendsList(long startDate, long endDate)
{
weekendList = new ArrayList();
Calendar calendarStart = null;
Calendar calendarEnd=null;
calendarStart= Calendar.getInstance();
calendarStart.setTimeInMillis(startDate);
/*calendarEnd= Calendar.getInstance();
calendarEnd.setTimeInMillis(endDate);
*/
// The while loop ensures that you are only checking dates in the current year
while(calendar.get(Calendar.YEAR) == Calendar.getInstance().get(Calendar.YEAR)){
// The switch checks the day of the week for Saturdays and Sundays
switch(calendar.get(Calendar.DAY_OF_WEEK)){
case Calendar.SATURDAY:
case Calendar.SUNDAY:
weekendList.add(calendar);
break;
}
// Increment the day of the year for the next iteration of the while loop
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
}
I am getting 102 weekends and it was like jan 9 to dec 31 but i want to today date(jan 9, 2018) to up to next year( like jan 9 2019), all the weekends in arrayList.
If anyone have any idea, that would great help for me.
So, immediately, you have a number of issues which stand out...
Using an out of date API. Calendar should be avoided at all costs, it's troublesome, clumsy and all way to easy to screw up
The while loop is looping only so long as the year is the same, so it's ignoring the endDate altogether
Because Calendar is mutable, all you are producing is a List with the same date/time value contained within it
You algorithm considers a weekend to be both "Saturday" or "Sunday", where normally, I'd consider a weekend to be the time between "Friday" and "Monday" - Don't know if this is deliberate on your part, but it stands out to me.
Since Java 8 included a newer Date/Time API, you should start using it. If you're not using Java 8+ (and I'd be asking some serious questions as to why not), you should be using a more reliable API - JodaTime comes to mind, but there is also a compatible back port of the Java 8 Date/Time for earlier JDK/JVMs
Now, having said all that, I'd do something more like...
public List<LocalDate> findWeekendsBetween(long startTime, long endTime) {
LocalDate startDate = LocalDate.ofEpochDay(startTime);
LocalDate endDate = LocalDate.ofEpochDay(endTime);
System.out.println("Starting from " + startDate);
System.out.println("Ending at " + endDate);
List<LocalDate> weekends = new ArrayList<>(25);
while (startDate.isBefore(endDate) || startDate.equals(endDate)) {
switch (startDate.getDayOfWeek()) {
case SATURDAY:
weekends.add(startDate);
startDate = startDate.plusDays(2);
break;
default:
startDate = startDate.plusDays(1);
}
}
return weekends;
}
In fact, I'd even change it so that callers were required to pass you LocalDate values...
public List<LocalDate> findWeekendsBetween(LocalDate startDate, LocalDate endDate) {
as long is ambiguous.
The above algorithm is inclusive of the startTime and endTime and considers a "weekend" to be the time between "Friday" and "Monday", so it will only return "Saturday" values
Then you could call it using something like...
LocalDate startDate = LocalDate.now();
LocalDate endDate = startDate.plusMonths(1);
List<LocalDate> weekends = findWeekendsBetween(startDate.toEpochDay(), endDate.toEpochDay());
System.out.println("Found " + weekends.size() + " Saturday/Sundays");
for (LocalDate date : weekends) {
System.out.println(date);
}
(as you can see, I'm to lazy to calculate a fixed point in time and just use LocalDate and convert it to a long value)
Which in my testing printed out something like...
Starting from 2018-01-09
Ending at 2018-02-09
Found 4 Weekends
2018-01-13
2018-01-20
2018-01-27
2018-02-03
but you have only added Saturday, it has to be Sundays also.
Yes, as I said, I made it accept only Saturday, as for me, a weekend is inclusive of Saturday AND Sunday.
It would be easily fixed by simply including SUNDAY into the switch statement...
switch (startDate.getDayOfWeek()) {
case SATURDAY:
case SUNDAY:
weekends.add(startDate);
break;
default:
startDate = startDate.plusDays(1);
}
I think, it might be 52*2=104 list size.
I've not tested a full year, I've only checked a month's worth. You could just change the end date, something like...
LocalDate endDate = startDate.plusYears(1);
I need the number of days in a year and I wanted to use Java8's new time api.
However, I can't do Duration.ofDays(365) because it doesn't account for leap years. And Duration.of(1, ChronoUnit.YEARS) doesn't fly because of java.time.temporal.UnsupportedTemporalTypeException: Unit must not have an estimated duration
I looked into Period, but it doesn't appear useful for going from years to days.
I feel like I'm missing something here? I could write something to add a day if the year is a leap year, but it seems like I should be able to handle this out of the box.
As per the response in Getting Duration using the new dateTime API you should be using
Period p = Period.ofYears(1);
It's important to understand the difference between Duration (exact number of nanoseconds < 1 day) and Period (variable > 1 day).
Duration won't account for leap days, daylight savings time or leap seconds, for example, and is intended for durations of less than a day, at most a few days.
So you should use Period instead.
Because different years have different number of days, if you want to find the number of days in a year, you need to specify which year you're talking about.
If you want the number of days in a specific year, you can use
Year.of(year).length()
If you want the date one year from now, you can use
LocalDate.now().plusYears(1)
or
LocalDate.now().plus(Period.ofYears(1))
If you need the number of days between two dates, you can use
ChronoUnit.DAYS.between(start, end)
So to find the number of days to the date a year from now, you can use
LocalDate today = LocalDate.now();
long days = ChronoUnit.DAYS.between(today, today.plusYears(1));
If you want to see whether a membership of one year is still valid, you can use
Period membershipLength = Period.ofYears(1);
LocalDate membershipStart = ...;
LocalDate membershipEnd = membershipStart.plus(membershipLength);
LocalDate today = LocalDate.now();
boolean memberShipEnded = today.isAfter(membershipEnd);
boolean membershipValid = !membershipEnded;
It seems clear you do not want a duration (= between two dates), but the year length of a specific date.
LocalDate dateLeap = LocalDate.of(2004, Month.MARCH, 1);
System.out.println("leap year of " + dateLeap
+ " has days: " + dateLeap.lengthOfYear());
leap year of 2004-03-01 has days: 366
Java 8 Date & Time is astonishing complete.
If you mean, in January 5th 2004 to January 5th 2005 = 366 and March 2nd 2004 to March 2rd 2005 = 365:
int lengthOfYear(LocalDate date) {
return date.getMonthValue() <= 2
? date.lengthOfYear() // Count Feb in this year
: date.plusYears(1).lengthOfYear(); // Count Feb in next year
}
Explanation: basically the length is 365. But if date is >= March, the February in the next year is counted, otherwise this year's February.
Mind that plusYears(1) will not change DAY or MONTH.
Also neither leap second nor hour/minuts on February, 29th are considered.
In Java, how would I go about constructing a utility that would take a range of dates (start and end date) and then would see how many times a given partial date ( the month and day-of-month) appears in that range, and will add an entry to a list for each match.
In my instance, I want to give it a range of say 5 years - starting Jan 1st 2014 and going to Dec 31st 2019. My check date is the 2nd August. I want the method to return the full information about each match of any August 2 of any year in the range. So for 2014 is will return Saturday 2nd August 2014, then Sunday 2nd August 2015 etc and so on.
I've been trying to get something working so far with Joda Time and the default date/calendar classes in Java and I'm just getting myself in a mess.
Thanks,
S
Edit: How silly of me, apologies for not adding my code :(
public static List<Date> getDaysInRange(Date startdate,
Date enddate,
Date checkDate) {
SimpleDateFormat sdf = new SimpleDateFormat("MMdd");
List<Date> dates = new ArrayList<>();
Calendar cal = new GregorianCalendar();
cal.setTime(startdate);
while (cal.getTime().before(enddate)) {
if (sdf.format(cal.getTime()).equals(sdf.format(checkDate))) {
Date result = cal.getTime();
dates.add(result);
}
cal.add(Calendar.DATE, 1);
}
return dates;
}
Date-Only
Since you want only a date without time-of-day and without time zone, use a date-only class. The old java.util.Date/.Calendar classes lack such a class. And those old classes are notoriously troublesome and flawed.
Instead use either:
Joda-Time
java.time, built into Java 8, inspired by Joda-Time.
Joda-Time
Here is some untested code using Joda-Time 2.6.
The main idea is to focus on the small set of possible year numbers rather than test every day of year. In the example below, that means six date-time values to compare rather than thousands. Besides efficiency, the purpose of the code becomes more apparent.
The arguments to your routine should be a month number and a day-of-month number, a pair of ints or Integers, rather than a Date. As seen in this examples two int variables, month and day.
LocalDate start = new LocalDate( 2011, 2, 3 );
LocalDate stop = new LocalDate( 2016, 4, 5 );
int yearStart = start.getYear();
int yearStop = stop.getYear();
int month = 11;
int day = 22;
for ( i = yearStart, i <= yearStop, i++ )
{
LocalDate x = new LocalDate( i, month, day );
boolean matchStart = ( x.isEqual( start ) || x.isAfter( start ) );
boolean matchStop = x.isBefore( stop ); // Half-Open approach where beginning of range is inclusive while ending is exclusive.
if ( matchStart && matchStop )
{
// Add to collection of LocalDate objects.
// Later you can ask each LocalDate object for its day-of-week.
{
}
java.time
The java.time package also offers a LocalDate class. The code would be similar to the above Joda-Time example.
I think using SimpleDateFormat is a bad idea. Use Calendar for comparison directly, like this
cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) && cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH)
I am new to java programming and I am stuck at the following problem.
I have a database (SQLite3) table in which one of the columns is text which stores DATE in the string(text) format. It has to be Text for some reasons and not of type Date (I even don't know whether Sqlite3 supports date data-type).
Now based on this Text date, I want to filer the data in the table into :
Week : how much data has been entered in the table in this week.
Week starts from monday and ends on sunday.
So when I filter on week , I want the all the entries that have been
entered from Monday to this day of the week.
Similar results are expected when I want to filter data into month and year.
Need some pointers on how this could be done. ?
Thanks.
I will give an example for the week. You can use similar technique for month and year. Please refer to http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
SELECT * FROM yourtable WHERE yourTimestamp >= CURDATE() - LEAST(6, DAYOFWEEK(CURDATE())-2)
DAYOFWEEK() numbers Sunday as 1, Saturday as 7. What happens if the command is run on a Sunday? To cater for this, LEAST(6,...) is used.
What you can do here is to use the java.Util.Calendar library to create your query from the db layer of your code.
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month = now.get(Calendar.MONTH); // Note: zero based!
int dayofMonth = now.get(Calendar.DAY_OF_MONTH);
But the trickiest part in forming this query from java layer is to get the number of days elapsed since the first day of the week,
For this you need to use
int dayofWeek = calendar.get(Calendar.DAY_OF_WEEK);
// If current day is Sunday, day=1. Saturday, day=7.
The following function can return a String array of the elapsed days in week -
String[] elapsedDaysOfWeek(String dayOfWeek,String dayofMonth)
{
int dayOfWeek=Int.ParseInt(dayOfWeek);
int dayOfMonth=IntParseInt(dayOfMonth);
String[] days=new String(dayOfWeek);
days[0]=dayOfMonth;
for (int i=1;i<dayOfWeek;i++)
days[i]=(dayOfMonth-i).ToString();
return days;
}
So if you call elapsedDaysOfWeek(5,25) - you will get an arry of {25,24,23,22,21} - this array you can use in your query using an ÍN' keyword -
e.g. substr(datetext,1,2) in {25,24,23,22,21}
I have homework that involves the user entering 2 integers (The month & The year) and I was wondering how to do that, I have searched a little in the calendar class documentation but I didn't find what I was searching for.
The main thing I'm tring to do is to print a calendar like the one in Windows where the only input I get from the user is the number of the month and year, I need to find a way to find weather the month is 31, 30, 29 or 28 days and the day in which that month started.
http://lifehacker.com/assets/2006/06/vista-windows-calendar.jpg this is what I want to do but as text without printing the days from other months .
You could use java.util.Date for this:
int month = 3 ; // Input
int year = 2012 ; // Input
Date date = new Date() ;
date.setMonth(month) ;
date.setYear(year) ;
But since Date is deprecated, you would have to use java.util.Calendar instead. The equivalent functions are:
Calendar.set(Calendar.MONTH, month) ;
Calendar.set(Calendar.YEAR, year) ;
Have a look at DateFormatSymbols. This has methods to retrieve the months. You can then use the index postion in the array (the month number) to get the month
String[] months = new DateFormatSymbols(Locale.getDefault()).getMonths();
System.out.println(months[0]);
System.out.println(months[11]);
As it's homework I'll let you work out why [0] gives Januaray and [11] gives December
Since this is homework, I'm not spilling out all the beans. You have to figure out the rest.
Without knowing what have you tried or what do you mean by finding a month, I think you want to obtain a Date object based in a year and a month.
The Calendar class was a right start. First of all, you should obtain an instance with the getInstance() method, considering the set(int field, int value) method in particular to set both the year and the month of that calendar.
If you're wondering how do you know which field you're setting, try the different constant values defined by Calendar itself (by convention, those are named in uppercase, just for you to find them).
In the end you just need to obtain that Date, through the getTime() method.
EDIT
Following the Calendar class approach and by using set, you can come up with the month you're searching.
Use methods such as getActualMaximum(int field) with Calendar.DAY_OF_MONTH. That's practically one of the answers. The other one is similar and I'm leaving it up to you.
Hint: Create a calendar and play with the fields, try setting the day of the month to 1 (the first day) and the current month to the one you need to get information from.
import java.util.Calendar;
import java.text.SimpleDateFormat;
class PrintCalendar {
public static void main(String args[]) {
Calendar c = Calendar.getInstance();
int month = 3;
int year = 2011;
c.set(year, month, 1); // Set c's time to first day of specified month/year
// Day of week (by numerical index) can also be obtained programmatically with c.get(Calendar.DAY_OF_WEEK)
System.out.println("First day of month falls on a " + new SimpleDateFormat("EEEE").format(c.getTime()));
// "Actual maximum" means the maximum in the current timeframe; that is, it will return 29 for a February in a leap year
System.out.println("Month has " + c.getActualMaximum(Calendar.DAY_OF_MONTH) + " days");
}
}