Java - get differences between given fortnight and current fortnight - java

For example:
Data Given :
Year-2010,
Month-2,
Fortnight-1
Current date
How do I get the difference in terms of number of fortnights between the two given dates?
This is what I figured out and its working fine...
Calendar c= Calendar.getInstance();
int year = 2011;
int month = 6;
int fortnight = 1;
int noofmonths=(c.get(Calendar.YEAR)-year)*12;
noofmonths=(noofmonths+((12-(month-1)+(c.get(Calendar.MONTH)-12)))-1)*2;
int nooffortnights=noofmonths+((2-(fortnight-1)+((c.get(Calendar.DAY_OF_MONTH)<15?1:2)-2)))-1;
System.out.println("nooffortnights : "+nooffortnights); //outputs 5

This depends on your definition of fortnights. If we are literal minded then a fortnight is defined as 14 days, so compute the number of days and divide by 14, job done.
I suspect that in your case we are actually using a special business calendar, where fortnights are a subdivision of quarters and hence there are some special cases - a year doesn't exactly divide into fortnights and perhaps the business year does not start on Jan 1st? So somewhere there will be a definitive list of the dates of the start of each fortnight in a year.
Let's suppose that the fortnight definitions have
17th Nov - 1st Dec
2nd Dec - 15th Dec
16th Dec - 31st Dec (note this is 15 days long)
Now what's the definition on how many fortnights from 17th Nov to 16th Dec? I guess 2. From 19th Nov to 16th Dec? I have no idea what answer you would expect.
So first, get really clear what the business requirements are. I'd be surprised is you will find off-the-shelf date packages that understand fortnights, but even if you do you need to check very carefully that they give the answers you need.

Assuming you want to do this without any 3rd Party libraries
Make 2 Calendar Objects (both with the given dates).
Calendar c1 = Calendar.getInstance(),c2 = Calendar.getInstance();
c1.add(Calendar.MONTH, 2);
int fortnights = (int)((c1.getTimeInMillis() - c2.getTimeInMillis()) / (14L * 24 * 60 * 60 * 1000));
System.out.println(fortnights); //output should be 4
Note, it's a rough approximation.

Related

How can I find all week numbers of month that are the # week of month in a year with Java?

I am looking to build up a function that return an array with all week numbers of the previous months in a year that are the same week number of one particular month.
I am using as first day of week Monday and I am taking as first week of month week with the first Monday of current month.
Input: week of year and year. For example, 27 and 2019. The first week of July (7).
Output: array of week of months. For example, [2, 6, 10, 14, 19, 23, 27].
What I try:
private void getResult(int weekYear)
{
LocalDate date = LocalDate.now();
final int weekNumber = 27;
LocalDate newDate = date.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);
int month = newDate.getMonthValue();;
int weekMonth = LocalDate.from(newDate).get(WeekFields.ISO.weekOfMonth());
System.out.println(newDate);
System.out.println(month);
System.out.println(weekMonth);
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 1; i <= month; i++)
{
LocalDate tempDate = date.withYear(2019).withMonth(i).with(WeekFields.ISO.weekOfMonth(), weekMonth);
int tempYear = LocalDate.from(tempDate).get(WeekFields.ISO.weekOfWeekBasedYear());
list.add(tempYear);
}
list.forEach((e) -> System.out.print(e + " "));
}
int weekYear = 27;
getResult(weekYear);
What I get: [1 6 10 14 18 23 27].
What I am looking for: I have two question:
First one: the results obtained are different from those expected. I think the problem is due to the fact that I didn't specify how to calculate the first week of the month (first Monday of the month). Is it right? How can I solve that?
Second one: What is a better solution?
The key here is understanding a few points:
You are numbering weeks in two different ways. For the week of year you are using ISO numbering: the first week of the year is the one that includes at least 4 days of the new year. For week of month you are counting the Mondays (you may say that the first week of the month is the one that includes seven days of the month, not four).
The week number may not always exist. If your starting point is in 0th or the 5th week of the month, a preceding month may not have that week in it.
the results obtained are different from those expected. I think the
problem is due to the fact that I didn't specify how to calculate the
first week of the month (first Monday of the month). Is it right? How
can I solve that?
You are correct. To count the Mondays of the month you may use:
LocalDate tempDate = date.withYear(2019)
.withMonth(i)
.with(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
.with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekMonth);
(DayOfWeek.MONDAY.getValue() is just of wordy way of saying 1, of course, but conveys the intention better, so I prefer it.)
With this change to your code the output is the expected:
2 6 10 14 19 23 27
The key is ChronoField.ALIGNED_WEEK_OF_MONTH. The aligned weeks of a month start from the 1st of the month and are always 7 days regardless of the days of the week. The first aligned week is from the 1st through the 7th of the month, the 2nd aligned week if from 8th through 14th, etc. Since we have set the day of week to Monday, setting the aligned week to 1 gives us the 1st Monday of the month, etc.
We’re not done yet. If I set weekNumber to 40, I get:
2 6 10 14 14 23 27 27 36 41
I had expected 40 to be the last number in the list, but it is not there. Week 40 of 2019 is from Monday September 30 through October 6, so if I understand correctly you want the 5th week of those months that have a 5th week. This brings us back to the issue of not all month having a week 5 (because they don’t have 5 Mondays). What happened was that since I ran your code on a Tuesday, it took Tuesday in week 40, which is October 1, as a starting point, and therefore gave me the 1st rather than the 5th week of every month.
are there better solutions? Can you suggest one?
I can’t really. What you’ve got is fine.
Only you’re not using the int weekYear parameter. You may want to use it in place of your weekNumber local variable. In any case you should delete one of them and use the other.
And this unrelated tip: Your use of LocalDate.from(someLocalDate) is redundant since it just gives you the same LocalDate again (either the same object or an equal one, I don’t know or care). Just use someLocalDate in those situations.

Java, How to subtract Date objects whilst considering DST

I have a piece of code that is used to calculate the number of days between two Date objects, and in most instances, it works fine.
However, if the date range between the two objects includes the end of March, the result is always 1 less than it should be. e.g March 31 2014 - March 29 2014 = 1, whereas it should be 2.
I understand that this is due to the fact that March has 30 days of 24 hours and 1 day of 23 hours due to DST, which is the cause of the value being 1 less.
However, I am not sure the best way to account for the missing hour.
// This was what I have initially
int numDays = (int) ((dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
// I have tried rounding, since it should have 23 hours left over, but it didn't actually work.
int numDays = (Math.round(dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
Any help/pointers would be greatly appreciated.
I am and have to use Java 7 and I am not able to use Jodatime unfortunately.
Your second example is very close. Your parentheses for Math.round() only surround the subtraction, though, so since that's already an integer (well, a long really), nothing happens, and then you divide. The other problem with your second bit of code is that you are doing integer division which always truncates the part after the decimal point. Try this:
long numDays2 = Math.round((dateTo.getTime() - dateFrom.getTime()) / (1000.0 * 60 * 60 * 24));
(As indicated, I changed the Math.round() parens, and made it floating point division by making the divisor a double.)
As indicated by the comments, though, this is a hack. In particular, it will tell you that there are two days between 6AM March 5 and 8PM March 6. It's probably not really what you want. Try this on for size instead:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.setTime(fmt.parse("2014-03-29"));
long start = cal.getTimeInMillis();
start += cal.getTimeZone().getOffset(start);
cal.setTime(fmt.parse("2014-03-31"));
long end = cal.getTimeInMillis();
end += cal.getTimeZone().getOffset(end);
System.out.println((end - start)/86400000.0);
Is it ugly? Yes. Is it weird? Yes. Does it work? Yes (I think so). Note that I'm providing a double as a result; you can apply any rounding you want to this result.

How to check the number of fixed time segments between two dates?

Two Dates are given:
Let's say,
Date dt1 = 22 June 2013 8:00 PM
Date dt2 = 24 June 2013 6:00 AM
Given the two dates, I want to determine that how many segments from 1 am to 5 am are between these two dates.
For above, there are two segments:
23 June 1 am to 5am
24 June 1am to 5am
So the answer should be 2.
I can get the difference between the two times,
var time1 = new Date(dt1).getTime();
var time2 = new Date(dt2).getTime();
var diff = new Date(time1 - time2);
And the number of hours, min and seconds,
var hours = diff.getHours();
var minutes = diff.getMinutes();
var seconds = diff.getMinutes();
But this only gives difference as expected.
What approach is needed to do so ?
Like everything else in computer science: break the problem down into a series of smaller problems that you're able to solve.
For example, in this problem you might simply determine if there's at least one of your "segments" in the time span. If there is, you might remove the first 24 hours from the full time span, then repeat the process for as long as there exists 24 hours to remove. Remember to count along the way.
Another approach might be to check
if time1.getHours() before or equal to 1am then result=1
if time2.getHours() after 5am then resutl++
result+= diff.getDays() - 1

Calendar add() vs roll() when do we use it?

I know add() adds the specified (signed) amount of time to the given time field, based on the calendar's rules.
And roll() adds the specified (signed) single unit of time on the given time field without changing larger fields.
I can't think of an everyday usage of roll() I would do everything by add().
Can you help me out with examples when do we use roll() and when add()?
EDIT 1
Joda answers are not accepted!
add() - almost always, as you said
roll() - for example you want to "dispense" events in one month. The algorithm may be to proceed a number of days and place the event, then proceed further. When the end of the month is reached, it should start over from the beginning. Hence roll().
Found in jGuru
Calendar.roll()
Changes a specific unit
and leaves 'larger' (in terms of time-month
is 'larger' than day) units unchanged. The API example is that
given a date of August 31, 1999,
rolling by (Calendar.MONTH, 8) yields
April 30, 1999. That is, the DAY was
changed to meet April's maximum, but
the 'larger' unit, YEAR, was
unchanged.
roll(): Rolls up 8 months here i.e., adding 8 months to Aug will result in Apr but year remains unchanged(untouched).
Calendar.add()
Will cause the
next 'larger' unit to change, if
necessary. That is, given a date of
August 31, 1999, add(Calendar.MONTH,
8) yields April 30, 2000. add() also
forces a recalculation of milliseconds
and all fields.
add(): Adds months to the current date i.e., adding 8 months to Aug will give Apr of Next Year, hence forces the Year change.
I was just asking the same question (which is how I found this page) and someone at my work place (well done, DCK) came up with a suggestion:
The date selectors on many smart phones (and other similar interfaces) will "roll" the day from the 31st to the 1st without altering the month, similarly for the month field.
I can't think of another use ATM and this one could be implemented in other ways, but at least it's an example!
Tim
Here is an example that will not work. The condition in the loop will never be satisfied, because the roll, once reaching January 31, 2014, will go back to January 1, 2014.
Calendar start=new GregorianCalendar();
start.set(Calendar.YEAR, 2014);
start.set(Calendar.MONTH, 0);
start.set(Calendar.DAY_OF_MONTH, 1);
//January 2, 2014
Calendar end=new GregorianCalendar();
end.set(Calendar.YEAR, 2014);
end.set(Calendar.MONTH, 1);
end.set(Calendar.DAY_OF_MONTH, 2);
//February 2, 2014
while (start.getTime().before(end.getTime())){
start.roll(Calendar.DATE, 1);
}

calculate frequency on certain range

I have maths problem ... (at the moment i solved it using manual iteration which is pretty slow) ...
For example if an employee got paid weekly (it can be fortnightly / every 2 weeks and monthly) with certain date (let's call the employee got paid every tuesday and for monthly the employee paid on certain date).
I have date range between 10th August 2009- 31 December 2009, now how to get frequency the employee got paid ?
is it possible to calculate this using jodatime ?
Example to make this question clear:
I have date range between Friday 14 August - Monday 14 Sept 2009 (31 days)
the employee got paid on every Tuesday
so he got paid on 18 & 25 August, 1 & 8 August we got 4 times payment
(frequency)
another example:
with the same date range Friday 14 August - Monday 14 Sept 2009 (31 days)
but different pay date .. for example on Sunday
so he got paid on : 15, 22 & 29 August , 5 & 12 September ... we got 5 times payment.
same date range but different pay day .. will result different.
So my question is, are there any formula to solve this case ?
at the moment I calculate using manual iterator .. which is very slow (because the range could be some years or months)
thank you
ps: I am using groovy .. any solutions using java or groovy or just algorithm are welcome :)
Oftentimes pay periods are on the 15th and the end of every month, so in that case you'd count the number of months and multiply by 2, checking the end conditions (if start is before the 15th, subtract one pay period; if end is after end of the month subtract one pay period).
It's possible to get counts of days, weeks, and months, but you'll have to add in the logic to handle the dodgy end conditions. It's probably not a simple formula, as the case I described demonstrates.
abosolutely, using the Weeks class is very simple:
DateTime start = new LocalDate(2009, 8, 10).toDateTimeAtStartOfDay();
DateTime end = new LocalDate(2009, 12, 31).toDateTimeAtStartOfDay();
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();
this code give 20 as result. It is right?
EDIT
maybe this is better:
DateMidnight start = new DateMidnight(2009, 8, 10);
DateMidnight end = new DateMidnight(2009, 12, 31);
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();
System.out.println(numberOfWeeks);
Subtracting one date from the other to get the "number of days" (or weeks) is generally the wrong way to go for these kinds of calculations. For example, if someone is 365 days old, they are exactly one year old, unless there was a February 29 during that time. In any (modern) 7-day period, there is always exactly one Tuesday; but for 8 days, it's either one or two. The calendar often figures into the calculations.
If they're paid once or twice a month, you do the easy calculation on the whole months -- starting on the first and ending on the last day of the month, which varies -- and then you have to consider partial months at the beginning and/or end. (Don't forget what happens if the 15th or last day of the month falls on a weekend.) If they're paid every one or two weeks, you can sync on a known payday, and then do the simpler math to figure the whole weeks before and/or since. (Don't forget holidays that fall on the payday.)
There are two tricks here: One is that the rules are different depending on the time frame. I mean, if a person is paid once a week, then in 7 days he gets paid once, in 14 days he gets paid twice, etc. But if a person is paid on the 1st and 16th of every month, I can't tell you how many times he was paid in 60 days without knowing what months were included: where they short months or long months?
The second is that you have to worry about the start and end of the time period. If a person is paid every Monday, then the number of times he gets paid in 8 days depends on whether the first day of the 8 is Monday.
Thus, I think you need to have different logic for schedules that are a fixed number of days and those that are tied to months or something else where the intervals can vary.
For the fixed number of days, the problem is fairly simple. The only complexity is if the time frame is not an exact multiple of the interval. So I'd say, find the first date in the interval on which a payday occurs. Then find the number of days between there and the end of the time period, divide by the interval and drop any fractions.
For example: A person is paid every Monday. How many pay days between March 1 and April 12? Find the first Monday in that range. Say it falls on March 4. Then calculate the number of days from March 4 to April 12. That would be 39. 39/7=5 and a fraction. Therefore he gets paid 5 more paychecks, for a total of 6.
For monthly pay, I think you'd have to separate out the first and last month. You could then count the number of months in the middle and multiply by the number of pays per month. Then for the first and last count how many are in them the hard way.
Just got solutions please check if I did something wrong
import org.joda.time.* ;
def start = new Date().parse("dd/MM/yy","14/08/2009");
def end = new Date().parse("dd/MM/yy","14/09/2009");
println("date range ${start} - ${end}");
def diff = end - start ;
println("diff : ${diff} days ");
println("how many weeks : ${diff/7}");
def payDay = 2 ; // Monday = 1 Sunday = 0
def startDay = new DateTime(start).dayOfWeek ; // 5 = Thursday
def startDayDiff = payDay - startDay ;
if(startDay > payDay){
startDayDiff = 7 + payDay - startDay ;
}
// for example if end on Friday (5) while Pay day is day 1 (Monday) then
// make sure end date is on Monday (same week )
// end date = end - ( endDay - payDay)
def endDay = new DateTime(end).dayOfWeek;
println("original end day: ${endDay}");
def endDayDiff = endDay - payDay ;
// otherwise ... if endDay < payDay (for example PayDay = Friday but End day is on Monday)
// end date = end - 7 + payDay
if(endDay < payDay){
endDayDiff = 7 - endDay - payDay ;
}
println("endDayDiff : ${endDayDiff}");
println("startDayDiff: ${startDayDiff}");
def startedOn = new DateTime(start).plusDays(startDayDiff);
println("started on : ${startedOn.toDate()}");
def endOn = new DateTime(end).minusDays(endDayDiff);
println("End on : ${endOn.toDate()}");
println("occurences : ${Weeks.weeksBetween(startedOn,endOn).getWeeks()+1}");
Tested using groovyConsole with Joda Time help .. :)

Categories

Resources