Subtract fiscal year quarters from current date using Java LocalDate - java

By using Java LocalDate how can I subtract eight quarters from the current quarter?
For example:
2019 Q3 - (8 x quarter) = 2017 Q4
I've tried using
LocalDate.now(ZoneId.of("Europe/London"));
now.minus(1, IsoFields.QUARTER_OF_YEAR);
but I am getting a negative value and I don't know how to handle this.

You are using QUARTER_OF_YEAR which is of type TimeField. You should use IsoFields.QUARTER_YEARS which is of type TemporalUnit:
Unit that represents the concept of a quarter-year. For the ISO calendar system, it is equal to 3 months.
LocalDate now = LocalDate.now(ZoneId.of("Europe/London"));
LocalDate ago = now.minus(3, IsoFields.QUARTER_YEARS);
System.out.println(ago);

Related

Compare date Range by Month (Integer) and Year (Integer)

I'm having a problem comparing the date range. I have to validate dates that are within a certain month and year. The month and year are integer values.
NOTE: I´m using OUTSYSTEMS aggregates using Oracle DataBase
Example for two results of a query:
Start Date End Date
1 2020-08-16 2020-10-14
2 2019-11-01 2020-08-15
Case 1
Input:
Month = 9
Year = 2020
Expected Result:
Start Date End Date
1 2020-08-16 2020-10-14
Case 2
Input:
Month = 8
Year = 2020
Expected Result:
Start Date End Date
1 2020-08-16 2020-10-14
2 2019-11-01 2020-08-15
Case 3
Input:
Month = 3
Year = 2020
Expected Result:
Start Date End Date
2 2019-11-01 2020-08-15
Case 4
Input:
Month = 10
Year = 2019
Expected Result: No Row
The selection is in Java Way. I´m using a system function like Month() and Year() to convert the rows to the integers.
Like this
((Month(StartDate) <= Month and Month(EndDate) = Month)
and
(Year(StartDate) <= Year and Year(EndDate) = Year))
or
((Month(StartDate) <= Month and Month(EndDate) = Month)
and
(Year(StartDate) <= Year and Year(EndDate) = Year))
The code above won't work. I try many combinations without success. I have no special comparison functions. For my analysis, I have four scenarios to create to bring the dates that are included in the month and year that I am researching. But I'm not getting the code to work. Someone can light the way for me
A simple approach uses arithmetics:
where year * 100 + month
between year(startdate) * 100 + month(startdate)
and year(enddate) * 100 + month(enddate)
However this probably isn't the most efficient method. In general, you want to avoid applying functions on the column you filter on. A better alternative woul be to convert the year/month parameter to a date - unfortunately you did not tag your database, and date functions are highly vendor-specific, so it is not really possible to suggest.
If you don't want between:
where year * 100 + month >= year(startdate) * 100 + month(startdate)
and year * 100 + month <= year(enddate) * 100 + month(enddate)
Does this work? Considering your inputs m for month and y for year:
StartDate <= AddDays(AddMonths(NewDate(Year(y), Month(m), 1),1)-1)
and
EndDate >= NewDate(Year(y), Month(m), 1))
The thinking is like: filter by all start dates that are lower than the last day of input month and all the end dates that are greater than the first day of input month.
Regarding performance, with this approach you don't have to do any logic/filter on the columns you're filtering on.
The vendor-independent solution
The answer by GMB is nice, I might go with it if it were me. As GMB says, it is vendor specific because the date functions are. If you want a solution that works across database vendors, do the date math in Java so you only need simple date comparisons in the database.
int month = 8;
int year = 2020;
YearMonth ym = YearMonth.of(year, month);
LocalDate monthStart = ym.atDay(1);
LocalDate monthEnd = ym.atEndOfMonth();
When you pass these dates to your query, your search condition may be put simply:
where startDate <= monthEnd and endDate >= monthStart

Generate random dates within past 12 months

I'm using this Java code to generate random dates:
LocalDate localDate = LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Is there a way to limit the random dates within last 12 months?
You probably don't want to deal with timezones, leap years, leap seconds etc. yourself, so I recommend using the java.time library (java 8 and up).
If you only want LocalDate-precision, you could get any day within a specified range like this:
LocalDate now = LocalDate.now();
LocalDate then = now.minusYears(1);
long difference = now.toEpochDay() - then.toEpochDay();
int randomDifference = random.nextInt((int) difference);
LocalDate randomDate = then.plusDays(randomDifference);

Joda Time - difference in "complete" months between two dates

How to calculate the number of "full" months between two dates with joda time, dropping incomplete months?
For example, I have 2 dates
LocalDate from = new LocalDate (2018, 9, 10);
LocalDate to = new LocalDate (2018, 11, 15);
Between these dates there is one "full" month - October from 1 to 31.
So I want to get is the number "1" by dropping the "incomplete" months - September and November
I need something like this
System.out.println(Months.monthsBetween(from, to).getMonths()); // returns 2
System.out.println(Months.**completed**MonthsBetween(from, to).getMonths()); // returns 1
UPD 1.
I could achieve what I want as follows:
LocalDate from = new LocalDate (2018, 9, 10);
LocalDate to = new LocalDate (2018, 11, 15);
if (to.getDayOfMonth() != 1)
from = from.plusMonths(1).withDayOfMonth(1);
if (to.getDayOfMonth() != 1)
to = to.withDayOfMonth(1);
System.out.println(Months.monthsBetween(from, to).getMonths());
but maybe there is an out of the box method?
Wouldn't this means that you simply want to remove one month from each interval and do a difference between them?
LocalDate fromMinusOne = from.minus(Months.ONE);
LocalDate toMinusOne = to.minus(Months.ONE);
System.out.println(Months.monthsBetween(fromMinusOne, toMinusOne).getMonths());
Joda Time provides methods to extract days, months and years between two dates. Create two instances of you date.
DateTime startDate = DateTime.parse("1970-01-01", DateTimeFormat.forPattern("yyyy-MM-dd"))
DateTime endDate = DateTime.parse("2015-02-25", DateTimeFormat.forPattern("yyyy-MM-dd"))
You can create your date instances in LocalDate as well instead of DateTime.
Now, complete months between above two dates can be found easily with,
int months = Months.monthsBetween(startDate.withDayOfMonth(1), endDate.withDayOfMonth(1)).getMonths()
For days,
int days = Days.daysBetween(startDate, endDate).getDays()
Difference between two dates in months
For years,
int years = Years.yearsBetween(startDate, endDate).getYears();

How to get the number of days between two java dates, comparing both the date and also time

I am trying to calculate the number of days between two java date objects using the following code:
public static int daysBetweenDates(Date startDate, Date endDate)
{
return Days.daysBetween( new LocalDate(startDate.getTime()), new LocalDate(endDate.getTime())).getDays();
}
I am using the Joda time here. But my problem is that when I compare two dates, example : Mon Apr 11 09:04:00 IST 2016 and Wed Apr 13 11:04:00 IST 2016, the result I get is 2. In fact the result I am expecting is 3 since there is more than 2 days between the given dates. Is there any way to do that.
The JavaDoc for Days.daysBetween() says (emphasis mine):
Creates a Days representing the number of whole days between the two
specified partial datetimes.
So just check whether there are any "left-overs", and increase if that's the case:
LocalDateTime now = new LocalDateTime();
LocalDateTime then = now.minusDays(2).minusMinutes(5);
int numberOfDaysBetween = Days.daysBetween(then, now).getDays();
LocalDateTime fullDayTime = then.plusDays(numberOfDaysBetween);
if (fullDayTime.isBefore(now)) {
numberOfDaysBetween++;
}
This should end up with numberOfDaysBetween being 3, since then is 2 days and 5 minutes before now.
No absolute need to use Joda time, or java.time, here. A day is (86400 * 1000) milliseconds. Java Dates give you the current time as UTC milliseconds in the Posix epoch. So ...
long diffMillis = endDate.getTime() - startDate.getTime();
int deltaDays = (int) Math.ceil(diffMillis / (86400.0 * 1000.0));

Inconsistent `w` symbol formatting from joda time to java.time

My team is looking to switch from Joda time to java.time, but we're seeing different behavior in formatting using the same pattern. The issue arises when we're using the week-of-week-year w symbol:
final String dateString = "2016-01-04 00:00:00";
final String inputPattern = "yyyy-MM-dd HH:mm:ss";
// parse the input string using Joda
final org.joda.time.format.DateTimeFormatter jodaInputFormatter = org.joda.time.format.DateTimeFormat.forPattern(inputPattern);
final org.joda.time.DateTime jodaDateTime = jodaInputFormatter.parseDateTime(dateString);
// parse the input string using two different java.time classes
final java.time.format.DateTimeFormatter javaTimeInputFormatter = java.time.format.DateTimeFormatter.ofPattern(inputPattern).withZone(java.time.ZoneOffset.UTC);
final java.time.LocalDateTime localDateTime = java.time.LocalDateTime.parse(dateString, javaTimeInputFormatter);
final java.time.ZonedDateTime zonedDateTime = java.time.ZonedDateTime.parse(dateString, javaTimeInputFormatter);
final String outputPattern = "'week' w - dd/MM/yyyy HH:mm:ss";
final org.joda.time.format.DateTimeFormatter jodaOutputFormatter = org.joda.time.format.DateTimeFormat.forPattern(outputPattern);
final java.time.format.DateTimeFormatter javaTimeOutputFormatter = java.time.format.DateTimeFormatter.ofPattern(outputPattern);
// output: week 1 - 04/01/2016 00:00:00
System.out.println("With joda: " + jodaOutputFormatter.print(jodaDateTime));
// output: week 2 - 04/01/2016 00:00:00
System.out.println("With LocalDateTime: " + javaTimeOutputFormatter.format(localDateTime));
// output: week 2 - 04/01/2016 00:00:00
System.out.println("With ZonedDateTime: " + javaTimeOutputFormatter.format(zonedDateTime));
For some reason, the output from the w symbol is off-by-one across the two implementations.
What is causing this inconsistency? Is the w symbol inconsistently implemented across Joda time and java.time?
Well, it is a little bit speculative, but since you told me that your system timezone is EST (-05:00) I assume that you are sitting in US (New York?). And US does not apply ISO-8601-week rules. Weeks start on Sunday, and the first week of the year does not need to contain at least 4 days (even one day is enough to be counted as first week of year).
So let's look at your example date of 4th of January. It is a Monday. The first US-week is from 2016-01-01 until 2016-01-02 (2 days - enough for US). And the second US-week starts on Sunday the 3rd of January, so the fourth of January is in the second week, too.
And now the critical point: java.time (JSR-310) uses a localized week of week-based-year for the pattern symbol w, see also its backport which should have the same code. Code excerpt:
} else if (cur == 'w') {
if (count > 2) {
throw new IllegalArgumentException("Too many pattern letters: " + cur);
}
appendInternal(new WeekFieldsPrinterParser('w', count));
...
static final class WeekFieldsPrinterParser implements DateTimePrinterParser {
private final char letter;
private final int count;
public WeekFieldsPrinterParser(char letter, int count) {
this.letter = letter;
this.count = count;
}
#Override
public boolean print(DateTimePrintContext context, StringBuilder buf) {
WeekFields weekFields = WeekFields.of(context.getLocale());
DateTimePrinterParser pp = evaluate(weekFields);
return pp.print(context, buf);
}
The use of WeekFields.of(context.getLocale()) for the pattern symbol "w" is evident.
In contrast, Joda-Time only uses ISO-8601-week-definition which let weeks start on Monday and count that week as first week of year which contains at least four days in current calendar year. So the Monday 4th of January is the start of the first week-of-year because the three days before are not enough for ISO-8601 to be counted as week. Those preceding days are instead considered as last week of previous year.
Consequently, Joda-Time displays week 1 for 4th of January while java.time uses the US-week 2.
Solution of your problem is to specify the locale such that the formatter will use ISO-weeks so you get the same result as in Joda-Time. For example, you could choose Locale.UK which also uses English but other week rules. Don't rely on your default locale. This can fool you.
Edit: As Richard points out, I'm wrong—Java SE actually does say that the first week of a week-based year is the first Monday-based week containing at least four days, just like Joda-Time.
From the documentation of Java SE's IsoFields.WEEK_OF_WEEK_BASED_YEAR:
The week-of-week-based-year has values from 1 to 52, or 53 if the week-based-year has 53 weeks.
No mention is made of excluding any weeks, so it makes sense to assume that all weeks are counted.
From the Joda-Time Fields overview:
Weeks run from 1 to 52-53 in a week based year. The first day of the week is defined as Monday and given the value 1. The first week of a year is defined as the first week that has at least four days in the year.
January 1 and 2 comprise the first partial week of 2016, and since that's fewer than four days, Joda-Time does not count it as a week at all. January 4 is in the first week which contains four or more days.

Categories

Resources