Determinining the date of a particular day of week - java

Java Q: On any given day, I want to determine the date on which (say) last Friday fell.
Example: If I run my program today (ie. Wednesday, 05th Sep 12), I should get the result as "Last Friday was on 31st Aug 12". If I run it on Saturday, 08th Sep 12, the result should be 07th Sep 12, and so on (The date formatting is not strictly an issue here though)
Is there any available api, or do I need to write a program at length going back that many days based on the current day, etc?
Thank you!

How about this:
Calendar cal = Calendar.getInstance();
int day = cal.get(Calendar.DAY_OF_WEEK);
cal.add(Calendar.DAY_OF_MONTH, -((day + 1) % 7));
Date lastFriday = cal.getTime();
We can always go back to the previous Friday by subtracting the Calendar.DAY_OF_WEEK value for the current date, plus 1. For example, if the current day is Monday (value=2) and we subtract (2 + 1) we go back 3 days to Friday. If we do the same thing on a Tuesday we go back (3 + 1) days - also to a Friday.
If the current day is either Friday or Saturday we need to be sure that we only go back 0 or 1 day respectively, so we just take mod 7 of the (day + 1) value.

int day = cal.get(Calendar.DAY_OF_WEEK);
int dayDiff = (day+1)%7;
if(dayDiff == 0)
dayDiff = 7;
cal.add(Calendar.DAY_OF_MONTH, - dayDiff);

I recently developed Lamma Date which is particularly designed for this use case:
new Date(2014, 7, 1).previous(DayOfWeek.FRIDAY); // 2014-06-27
new Date(2014, 7, 2).previous(DayOfWeek.FRIDAY); // 2014-06-27
new Date(2014, 7, 3).previous(DayOfWeek.FRIDAY); // 2014-06-27
new Date(2014, 7, 4).previous(DayOfWeek.FRIDAY); // 2014-06-27
new Date(2014, 7, 5).previous(DayOfWeek.FRIDAY); // 2014-07-04
new Date(2014, 7, 6).previous(DayOfWeek.FRIDAY); // 2014-07-04
new Date(2014, 7, 7).previous(DayOfWeek.FRIDAY); // 2014-07-04

Related

Get start date of current financial year

Here in the UK, the tax year runs from 6 April to 5 April each year. I want to get the start date of the current tax year (as a LocalDate), so for example if today is 3 April 2020, then return 6 April 2019, and if today is 8 April 2020, then return 6 April 2020.
I can calculate it using some logic like the following:
date = a new LocalDate of 6 April with today's year
if (the date is after today) {
return date minus 1 year
} else {
return date
}
But is there some method I can use that is less complex and uses a more succinct, perhaps functional style?
There are a few different approaches, but it's easy enough to implement the logic you've already specified in a pretty functional style:
private static final MonthDay FINANCIAL_START = MonthDay.of(4, 6);
private static LocalDate getStartOfFinancialYear(LocalDate date) {
// Try "the same year as the date we've been given"
LocalDate candidate = date.with(FINANCIAL_START);
// If we haven't reached that yet, subtract a year. Otherwise, use it.
return candidate.isAfter(date) ? candidate.minusYears(1) : candidate;
}
That's pretty concise and simple. Note that it doesn't use the current date - it accepts a date instead. That makes it much easier to test. It's easy enough to call this and provide the current date, of course.
using java.util.Calendar, you can get financial year's START and END date in which your given date lies.
In India financial year starts from from 1 April and ends on 31st March,
for financial year 2020-21 , dates will be 1 April 2020
public static Date getFirstDateOfFinancialYear(Date dateToCheck) {
int year = getYear(dateToCheck);
Calendar cal = Calendar.getInstance();
cal.set(year, 3, 1); // 1 April of Year
Date firstAprilOfYear = cal.getTime();
if (dateToCheck.after(firstAprilOfYear)) {
return firstAprilOfYear;
} else {
cal.set(year - 1, 3, 1);
return cal.getTime();
}
}
In your case set cal.set(year, 0, 1); // 1 Jan of Year
public static Date getLastDateOfFinancialYear(Date dateToCheck) {
int year = getYear(dateToCheck);
Calendar cal = Calendar.getInstance();
cal.set(year, 2, 31); // 31 March of Year
Date thirtyFirstOfYear = cal.getTime();
if (dateToCheck.after(thirtyFirstOfYear)) {
cal.set(year + 1, 2, 31);
return cal.getTime();
} else {
return thirtyFirstOfYear;
}
}
In your case set cal.set(year, 11, 31); // 31 Dec of Year

Calendar returns wrong Week of the year

I want to get this current week on the day of 9/10/2018 as the 42 week of the year after setting the First Day of the week to Sunday. Still I get the output as 41 from the below snippet
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.SUNDAY);
System.out.println( c.get(Calendar.WEEK_OF_YEAR) );
Am I missing something here?
Background: Our week start can be variable. Our configuration has the ability to let users decide the first day of the week.
Sorry if I’m too persistent. I still think you should leave the calculation to a custom WeekFields object. If I understood your comment correctly, you want:
final int daysPerWeek = DayOfWeek.values().length; // A wordy way of writing 7 :-)
WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());
To test whether this agrees with what you are already doing I wrote the following method:
static void printWeekNumber(DayOfWeek firstDayOfWeek, LocalDate date) {
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("EEE uuuu-MM-dd", Locale.ENGLISH);
final int daysPerWeek = DayOfWeek.values().length;
// Week number according to your comment: “using the Temporal adjusters
// I am getting the date on the last day of the week.
// After that dividing the Day of the Year from the API by 7”
DayOfWeek lastDayOfWeek = firstDayOfWeek.minus(1);
int askersCommentWeekNumber = date
.with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
.getDayOfYear()
/ daysPerWeek;
// My suggested way of calculating the same week number
WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());
System.out.format(Locale.ENGLISH, "Week begins on %-8s Date is %s. Week %2d or %2d, agree? %s%n",
firstDayOfWeek, date.format(dateFormatter),
askersCommentWeekNumber, customWeekNumber,
askersCommentWeekNumber == customWeekNumber);
}
To make it easier to check the calculations by hand, I have picked a date in January in different years:
printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2017, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2017, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.THURSDAY, LocalDate.of(2017, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2018, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2019, Month.JANUARY, 9));
printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2019, Month.JANUARY, 9));
Output:
Week begins on SUNDAY Date is Mon 2017-01-09. Week 2 or 2, agree? true
Week begins on MONDAY Date is Mon 2017-01-09. Week 2 or 2, agree? true
Week begins on THURSDAY Date is Mon 2017-01-09. Week 1 or 1, agree? true
Week begins on SUNDAY Date is Tue 2018-01-09. Week 1 or 1, agree? true
Week begins on MONDAY Date is Tue 2018-01-09. Week 2 or 2, agree? true
Week begins on SUNDAY Date is Wed 2019-01-09. Week 1 or 1, agree? true
Week begins on MONDAY Date is Wed 2019-01-09. Week 1 or 1, agree? true
Please check whether the results are as you want them, though. For the example in your question, the result is neither 41 nor 42:
printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.OCTOBER, 9));
Week begins on SUNDAY Date is Tue 2018-10-09. Week 40 or 40, agree? true
Edit: If you want ISO 8601 week numbers, use date.get(WeekFields.ISO.dayOfWeek()). If you want your custom first day of week and 4 days in the first week as in ISO 8601, use:
WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, 4);

Java, easiest way to identify if one week away or one month etc using dates

After 20 minutes of coding my attempt which was,
if given dd/mm/year and I have my current dd/mm/year, if
the difference in years = 0, the difference in months = 0 and the difference in days = 7, then you're 1 week away.
Then I realized, this doesn't take into account date wrapping. For instance, if I'm given the date of 07/01/2017 and my current date is 06/29/2017. My algorithm would return false, but you're in fact less than 1 week away. (Depending on month as well, i.e. 30 or 31 days).
Therefore my question is, what is the easiest way to check if you're either:
1 month, two weeks or 1 week away from a date when
Given the date and
I am using the time given from LocalDateTime.now()
Here is an example for a 7 days
LocalDate old = LocalDate.of(2017, 6, 29);
LocalDate current = LocalDate.of(2017, 7, 1);
System.out.println(old.plusDays(7).isBefore(current));
old = LocalDate.of(2017, 6, 23);
System.out.println(old.plusDays(7).isBefore(current));
The output will be
false
true
You can use ChronoUnit to measure days/months/years/weeks between two dates
LocalDate date1 = LocalDate.of( 2017, 10, 10 );
LocalDate date2 = LocalDate.of( 2017, 11, 10 );
long years = ChronoUnit.YEARS.between( date1, date2 );
long months = ChronoUnit.MONTHS.between( date1, date2 );
long days = ChronoUnit.DAYS.between( date1, date2 );
long weeks = ChronoUnit.WEEKS.between( date1, date2 );

GregorianCalendar returns wrong DAY_OF_WEEK in Java

This code:
Calendar calendar;
calendar = GregorianCalendar.getInstance();
calendar.set(year, month, day);
week_day = calendar.get(Calendar.DAY_OF_WEEK);
returns wrong value.
For example
year=2013, month=3, day=31
returns the same value of
year=2013, month=4, day=1.
How I can do this correctly ?
In Java, months start from 0.
Month 3 day 31 is April 31, that does not exist, then it will be shifted to May 1,
Month 4 day 1 is May 1, the same day as above.

Y returns 2012 while y returns 2011 in SimpleDateFormat

I wonder why 'Y' returns 2012 while 'y' returns 2011 in SimpleDateFormat:
System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012
System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011
Can any one explain why?
week year and year. From javadoc
A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between
the first and last weeks (inclusive) have the same week year value.
Therefore, the first and last days of a week year may have different
calendar year values.
For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is
MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard
compatible setting), then week 1 of 1998 starts on December 29, 1997,
and ends on January 4, 1998. The week year is 1998 for the last three
days of calendar year 1997. If, however, getFirstDayOfWeek() is
SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on
January 10, 1998; the first three days of 1998 then are part of week
53 of 1997 and their week year is 1997.
Here's a Java 8 update with some code, as GregorianCalendar will probably be deprecated or removed from future JDK versions.
The new code is handled in the WeekFields class, and specifically for the lower case y / upper case Y with the weekBasedYear() field accessor.
Returns a field to access the year of a week-based-year based on this
WeekFields. This represents the concept of the year where weeks start
on a fixed day-of-week, such as Monday and each week belongs to
exactly one year. This field is typically used with dayOfWeek() and
weekOfWeekBasedYear().
Week one(1) is the week starting on the getFirstDayOfWeek() where
there are at least getMinimalDaysInFirstWeek() days in the year. Thus,
week one may start before the start of the year. If the first week
starts after the start of the year then the period before is in the
last week of the previous year.
This field can be used with any calendar system.
In the resolving phase of parsing, a date can be created from a
week-based-year, week-of-year and day-of-week.
In strict mode, all three fields are validated against their range of
valid values. The week-of-year field is validated to ensure that the
resulting week-based-year is the week-based-year requested.
In smart mode, all three fields are validated against their range of
valid values. The week-of-week-based-year field is validated from 1 to
53, meaning that the resulting date can be in the following
week-based-year to that specified.
In lenient mode, the year and day-of-week are validated against the
range of valid values. The resulting date is calculated equivalent to
the following three stage approach. First, create a date on the first
day of the first week in the requested week-based-year. Then take the
week-of-week-based-year, subtract one, and add the amount in weeks to
the date. Finally, adjust to the correct day-of-week within the
localized week.
The setup of this WeekFields instance depends on the locale and may have different settings depending on it, US and European countries like France may have a different day as start of the week.
For example the DateFormatterBuilder of Java 8, instantiate the parser with the locale, and use this locale for the Y symbol :
public final class DateTimeFormatterBuilder {
...
private void parsePattern(String pattern) {
...
} else if (cur == 'Y') {
// Fields defined by Locale
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
} else {
...
static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
...
/**
* Gets the printerParser to use based on the field and the locale.
*
* #param locale the locale to use, not null
* #return the formatter, not null
* #throws IllegalArgumentException if the formatter cannot be found
*/
private DateTimePrinterParser printerParser(Locale locale) {
WeekFields weekDef = WeekFields.of(locale);
TemporalField field = null;
switch (chr) {
case 'Y':
field = weekDef.weekBasedYear();
if (count == 2) {
return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0);
} else {
return new NumberPrinterParser(field, count, 19,
(count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
}
case 'e':
case 'c':
field = weekDef.dayOfWeek();
break;
case 'w':
field = weekDef.weekOfWeekBasedYear();
break;
case 'W':
field = weekDef.weekOfMonth();
break;
default:
throw new IllegalStateException("unreachable");
}
return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
}
...
}
...
}
Here's some example
System.out.format("Conundrum : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'")));
System.out.format("Solution : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmms'S'")));
System.out.format("JVM Locale first day of week : %s%n",
WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
System.out.format("US first day of week : %s%n",
WeekFields.of(Locale.US).getFirstDayOfWeek());
System.out.format("France first day of week : %s%n",
WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
System.out.format("JVM Locale min days in 1st week : %s%n",
WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek());
System.out.format("US min days in 1st week : %s%n",
WeekFields.of(Locale.US).getMinimalDaysInFirstWeek());
System.out.format("JVM Locale min days in 1st week : %s%n",
WeekFields.of(Locale.FRANCE).getMinimalDaysInFirstWeek());
System.out.format("JVM Locale week based year (big Y): %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("France week based year (big Y) : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("US week based year (big Y) : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.US).weekBasedYear()));
And in regard of the locale and the upper case Y, you can either play with the command line option -Duser.language= (fr, en, es, etc.), or force the locale at invocation time :
System.out.format("English localized : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.ENGLISH)));
System.out.format("French localized : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.FRENCH)));
Format Y to get week year if calendar support week year. (getCalendar().isWeekDateSupported())
I learned the hard way the JSTL tag library format:date with short as the requested format uses YYYY under the covers. Which can indeed roll the printed date ahead a year.
I convert a date back and forth - you would expect the same year when you do this.
Notice how it advances one!
This is bad: YYYY!
You can run it here.
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static java.lang.System.out;
class Playground {
public static Date convertYYYYMMDDStr(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date result = null;
try {
result = sdf.parse(s);
} catch(ParseException e) {
e.printStackTrace();
}
return result;
}
public static String formatDateToStrWithSDF(Date d, SimpleDateFormat s) {
return s.format(d);
}
public static void main(String[ ] args) {
// DON'T DO. Use yyyy instead of YYYY
SimpleDateFormat sdfdmy = new SimpleDateFormat("dd-MM-YYYY");
String jan1st2020sb = "2020-01-01";
Date jan1st2020d = convertYYYYMMDDStr(jan1st2020sb);
String jan1st2020sa = formatDateToStrWithSDF(jan1st2020d, sdfdmy);
out.println(jan1st2020sb);
out.println(jan1st2020d);
out.println(jan1st2020sa);
String dec31st2020sb = "2020-12-31";
Date dec31st2020d = convertYYYYMMDDStr(dec31st2020sb);
String dec31st2020sa = formatDateToStrWithSDF(dec31st2020d, sdfdmy);
out.println(dec31st2020sb);
out.println(dec31st2020d);
out.println(dec31st2020sa);
}
}
This is good: yyyy

Categories