I am currently using the DatePicker in Android to let the user select a date. Is there a possibility to only allow the user to select Mondays and disable all other days for selection? I did not find anything in the Documentation.
Currently I am using this to show the DatePicker:
DatePickerDialog datePickerDialog = new DatePickerDialog(AddAppointment.this,
new DatePickerDialog.OnDateSetListener() {
#Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
// Do stuff with the info
}
}, setYear, setMonth, setDay);
datePickerDialog.show();
You can use this library Material Date Time Picker, here you can set an option to show specific dates, For Example:
datePicker.setSelectableDays(Calendar[] days)
And pass the array of Calendar as a parameter which contains all the selectable date.
for finding monday array you can use this logic:- Get all Fridays in a date Range in Java
You can calculate the calendar week of the chosen date or calculate the most recent Monday using one of the methods below. They are commented, so I keep the text short.
public class ExampleDateCalculation {
public static void main(String[] args) {
int dayOfMonth = 4;
int monthOfYear = 3;
int year = 2018;
// create a java.time.LocalDate of the given integers
LocalDate localDate = LocalDate.of(year, monthOfYear, dayOfMonth);
// calculate the calendar week of it
int calendarWeekTheLocalDateIsIn = getCalendarWeek(localDate);
// calculate the last Monday before this date
LocalDate lastMonday = getLastFrom(DayOfWeek.MONDAY, localDate);
// create a formatter for your locale
DateTimeFormatter germanDateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(localDate.format(germanDateFormatter)
+ " is in calendar week "
+ calendarWeekTheLocalDateIsIn
+ " of the system locale and the last Monday before was at "
+ lastMonday.format(germanDateFormatter));
}
/**
* <p>
* Gets the calendar week number of the given {#link LocalDate} based on the
* {#link Locale} of the operating system.
* </p>
*
* #param localDate the date of the day
* #return the calendar week number the day is in
*/
public static int getCalendarWeek(LocalDate localDate) {
WeekFields weekFields = WeekFields.of(Locale.getDefault());
return localDate.get(weekFields.weekOfWeekBasedYear());
}
/**
* <p>
* Gets the date of the last given weekday or day of week starting from the
* weekday of the given date. The method calculates the date of the nearest
* weekday chronologically backwards.
* </p>
* <p>
* <strong>For example:</strong><br>
* If the weekday of the given date is a Monday and the given day of week is a
* Tuesday, then this method will return the date of the Tuesday before today,
* which is 6 days back in the past.
* </p>
*
* #param weekday the day of week whose date is to be determined
* #param from the date to start from calculating backwards
* #return the date of the last given day of week starting from the given date
*/
public static LocalDate getLastFrom(DayOfWeek weekday, LocalDate from) {
DayOfWeek fromWeekday = from.getDayOfWeek();
int fromWeekdayValue = fromWeekday.getValue();
int weekdaysValue = weekday.getValue();
int daysToSubtract = 0;
/*
* Calculate the days to go back and be beware of negative values by means of
* case differentiation. Get the positive difference by subtracting the smaller
* value from the larger one and subtract a week if the result would be 0.
*/
if (fromWeekdayValue < weekdaysValue) {
daysToSubtract = 7 - (weekdaysValue - fromWeekdayValue);
} else if (fromWeekdayValue > weekdaysValue) {
daysToSubtract = fromWeekdayValue - weekdaysValue;
} else {
daysToSubtract = 7;
}
return from.minusDays(daysToSubtract);
}
}
If you want the user to only see calendar weeks or Mondays, follow the suggestions given in Uday Nayak's answer.
If anyone finds errors in or knows disadvantages of this code, please let me know.
You can try to do it little bit differently. First, change font color of days user don't want to pick (all except Mondays) and than filter active day selected and disable functionality until Monday is selected.
I need to get the 4-5-4 Calendar Week from a Date. Is there any utility like Georgian Calendar in Java for 4-5-4 Retail Calendar?
If not, how can I create one? What all logic is needed? What is 53rd Week in case of Leap Year?
For example, if I pass a date (DD-MM-YYY) 04-03-2018 as input I should get March Week 1 as output.
Or, if I give 01-04-2018 as input I should get March Week 5 as output.
Please help me by providing a way to build this utility.
The following class should do it:
public class NrfMonthWeek {
public static NrfMonthWeek getWeek(LocalDate date) {
// Determine NRF calendar year.
// The year begins on the Sunday in the interval Jan 29 through Feb 4.
LocalDate firstDayOfNrfYear = date.with(MonthDay.of(Month.JANUARY, 29))
.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
if (date.isBefore(firstDayOfNrfYear)) { // previous NRF year
firstDayOfNrfYear = date.minusYears(1)
.with(MonthDay.of(Month.JANUARY, 29))
.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
}
// 1-based week of NRF year
int weekOfNrfYear = (int) ChronoUnit.WEEKS.between(firstDayOfNrfYear, date) + 1;
assert 1 <= weekOfNrfYear && weekOfNrfYear <= 53 : weekOfNrfYear;
YearMonth firstMonthOfNrfYear = YearMonth.from(firstDayOfNrfYear)
.with(Month.FEBRUARY);
if (weekOfNrfYear == 53) {
// Special case: the last week of a 53 weeks year belongs to
// the last month, January; this makes it a 5 weeks month.
return new NrfMonthWeek(firstMonthOfNrfYear.plusMonths(11), 5);
} else {
// 1-based month of NRF year (1 = February through 12 = January).
// A little math trickery to make the 4-5-4 pattern real.
int monthOfNrfYear = (weekOfNrfYear * 3 + 11) / 13;
// Number of weeks before the NRF month: 0 for February, 4 for March, 9 for April, etc.
int weeksBeforeMonth = (monthOfNrfYear * 13 - 12) / 3;
int weekOfMonth = weekOfNrfYear - weeksBeforeMonth;
return new NrfMonthWeek(
firstMonthOfNrfYear.plusMonths(monthOfNrfYear - 1), weekOfMonth);
}
}
private YearMonth month;
/** 1 through 5 */
private int weekOfMonth;
public NrfMonthWeek(YearMonth month, int weekOfMonth) {
this.month = Objects.requireNonNull(month);
if (weekOfMonth < 1 || weekOfMonth > 5) {
throw new IllegalArgumentException("Incorrect week number " + weekOfMonth);
}
this.weekOfMonth = weekOfMonth;
}
#Override
public String toString() {
return month.getMonth().getDisplayName(TextStyle.FULL, Locale.US)
+ " Week " + weekOfMonth;
}
}
Let’s try it. Here I pass the two dates from your question to the getWeek method:
System.out.println(NrfMonthWeek.getWeek(LocalDate.of(2018, Month.MARCH, 4)));
System.out.println(NrfMonthWeek.getWeek(LocalDate.of(2018, Month.APRIL, 1)));
This prints the desired:
March Week 1
March Week 5
Though only month and week are printed, also the year is contained in the object returned from getWeek.
The formulas for calculating the month and week-of-month are cryptic. I have no really good argument why they work, though such an argument could probably be constructed. I have tested them with all relevant values, and you are free to do the same. Other than that, using java.time, the modern Java date and time API, it wasn’t too bad.
If that were me, I would have finer validation in the NrfMonthWeek constructor, only allowing week 5 in the months that may have 5 weeks. I am leaving that to you. And I would have a pretty thorough unit test.
Please check whether my understanding agrees with yours: If I have understood correctly from the example calendars that Basil Bourque linked to in his answer, the NRF 4-5-4 year starts with February. Its weeks begin on Sunday, and the first week of the year is the first week that contains at least 4 days of February. In other words, the week that contains February 4. In yet other words, the week that begins on a Sunday in the interval January 29 through February 4. Months March, June, September and December always have 5 weeks. In case of a 53 weeks year also January has 5 weeks.
No support built-in
Neither the modern java.time classes nor the legacy date-time classes (Date/Calendar) directly support the National Retail Federation 4-5-4 Calendar.
Implement Chronology
I suspect the best way to solve this problem is to implement a Chronology for the java.time framework.
Java 8 and later bundle five implementations (HijrahChronology, IsoChronology, JapaneseChronology, MinguoChronology, ThaiBuddhistChronology). Their source is available in the OpenJDK project.
The ThreeTen-Extra project provides ten more chronologies (AccountingChronology, BritishCutoverChronology, CopticChronology, DiscordianChronology, EthiopicChronology, InternationalFixedChronology, JulianChronology, PaxChronology, Symmetry010Chronology, Symmetry454Chronology) whose source code might help.
Here is my try to do date minus for GWT:
Date from = new Date();
Date to = new Date();
if(filter.equals(DATE_FILTER.PAST_HOUR)){
minusHoursToDate(to, 1);
} else if(filter.equals(DATE_FILTER.PAST_24_HOURS)){
minusHoursToDate(to, 1 * 24);
} else if(filter.equals(DATE_FILTER.PAST_WEEK)){
minusHoursToDate(to, 1 * 24 * 7);
} else if(filter.equals(DATE_FILTER.PAST_MONTH)){
minusHoursToDate(to, 1 * 24 * 7 * 4);
} else if(filter.equals(DATE_FILTER.PAST_YEAR)){
minusHoursToDate(to, 1 * 24 * 7 * 4 * 12);
}
public static void minusHoursToDate(Date date, int hours){
date.setTime(date.getTime() - (hours * 3600000));
}
The problem I see here is with the calculation in terms of month and year. As months is not always 4-week aligned and a year is also affected.
What could be the best calculation for subtracting month & year?
Since java.util.Calendar is unsupported in GWT because of the complexity needed for its implementation, the final JS size, etc, I would go with a simple and lightweight solution based on JS.
Apart from the java Date implementation, in GWT we have the JsDate wrapper which includes all the methods available in the native JS date, so subtracting a month or a year should be as simpler as:
int months = -2;
int years = -3;
JsDate j = JsDate.create(new Date().getTime());
j.setMonth(j.getMonth() + months);
j.setFullYear(j.getFullYear() + years);
Date d = new Date((long)j.getTime());
You can do the same to manipulate other units:
getDate() Returns the day of the month (from 1-31)
getDay() Returns the day of the week (from 0-6)
getFullYear() Returns the year (four digits)
getHours() Returns the hour (from 0-23)
getMilliseconds() Returns the milliseconds (from 0-999)
getMinutes() Returns the minutes (from 0-59)
getMonth() Returns the month (from 0-11)
getSeconds() Returns the seconds (from 0-59)
I've been all up night trying to figure this out, but nothing I try seems to work. Let say the Fiscal year starts on 10/01 of every year, for example the fiscal year started on 10/01/2012 making this week number 30. I can't seem to find the code that returns the appropriate week number.
The closest I've gotten is this code below which returns week number 16 starting from Jan.
public String getCurrentWeek() {
GregorianCalendar current = new GregorianCalendar(getCalendar().get(Calendar.YEAR),
getCalendar().get(Calendar.MONTH), getCalendar().get(Calendar.DATE));
return Integer.toString(current.get(Calendar.WEEK_OF_YEAR));
}
I believe:
private static final int LENGTH_OF_WEEK = 7 * 24 * 60 * 60 * 1000;
public static int weekOf(Calendar yearStart, Calendar date) {
long millisElapsed = date.getTimeInMillis() - yearStart.getTimeInMillis();
int weeksElapsed = (int) (millisElapsed / LENGTH_OF_WEEK);
return weeksElapsed + 1;
}
Should do it.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 8 years ago.
Improve this question
Does anyone knows a good business calendar library in java?
It should handle easy :) date calculations, taking holidays into account.
Ideally, besides configuring holidays and company off days, we should also be able to configure 'working hours' on a day basis so we can calculate SLA's and KPI's on working hours.
I know something like this is part of jboss jBpm, but I was wondering if their was any other project doing this.
Off course, open source is a big plus point!
Check out this library, it has functionality for holidays and such, it's built around joda.
http://objectlabkit.sourceforge.net/
Below is a very longwinded answer. It's something that I put together for exactly this purpose. It's not super user friendly, but it should give you want you are looking for.
It relies on the Apache commons project which can be acquired here: http://commons.apache.org/lang/
package com.yourPackageName;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class BusinessDayUtil {
private static Log log = LogFactory.getLog(BusinessDayUtil.class);
private static transient Map<Integer, List<Date>> computedDates = new HashMap<Integer, List<Date>>();
/*
* This method will calculate the next business day
* after the one input. This means that if the next
* day falls on a weekend or one of the following
* holidays then it will try the next day.
*
* Holidays Accounted For:
* New Year's Day
* Martin Luther King Jr. Day
* President's Day
* Memorial Day
* Independence Day
* Labor Day
* Columbus Day
* Veterans Day
* Thanksgiving Day
* Christmas Day
*
*/
public static boolean isBusinessDay(Date dateToCheck)
{
//Setup the calendar to have the start date truncated
Calendar baseCal = Calendar.getInstance();
baseCal.setTime(DateUtils.truncate(dateToCheck, Calendar.DATE));
List<Date> offlimitDates;
//Grab the list of dates for the year. These SHOULD NOT be modified.
synchronized (computedDates)
{
int year = baseCal.get(Calendar.YEAR);
//If the map doesn't already have the dates computed, create them.
if (!computedDates.containsKey(year))
computedDates.put(year, getOfflimitDates(year));
offlimitDates = computedDates.get(year);
}
//Determine if the date is on a weekend.
int dayOfWeek = baseCal.get(Calendar.DAY_OF_WEEK);
boolean onWeekend = dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY;
//If it's on a holiday, increment and test again
//If it's on a weekend, increment necessary amount and test again
if (offlimitDates.contains(baseCal.getTime()) || onWeekend)
return false;
else
return true;
}
/**
*
* This method will calculate the next business day
* after the one input. This leverages the isBusinessDay
* heavily, so look at that documentation for further information.
*
* #param startDate the Date of which you need the next business day.
* #return The next business day. I.E. it doesn't fall on a weekend,
* a holiday or the official observance of that holiday if it fell
* on a weekend.
*
*/
public static Date getNextBusinessDay(Date startDate)
{
//Increment the Date object by a Day and clear out hour/min/sec information
Date nextDay = DateUtils.truncate(addDays(startDate, 1), Calendar.DATE);
//If tomorrow is a valid business day, return it
if (isBusinessDay(nextDay))
return nextDay;
//Else we recursively call our function until we find one.
else
return getNextBusinessDay(nextDay);
}
/*
* Based on a year, this will compute the actual dates of
*
* Holidays Accounted For:
* New Year's Day
* Martin Luther King Jr. Day
* President's Day
* Memorial Day
* Independence Day
* Labor Day
* Columbus Day
* Veterans Day
* Thanksgiving Day
* Christmas Day
*
*/
private static List<Date> getOfflimitDates(int year)
{
List<Date> offlimitDates = new ArrayList<Date>();
Calendar baseCalendar = GregorianCalendar.getInstance();
baseCalendar.clear();
//Add in the static dates for the year.
//New years day
baseCalendar.set(year, Calendar.JANUARY, 1);
offlimitDates.add(offsetForWeekend(baseCalendar));
//Independence Day
baseCalendar.set(year, Calendar.JULY, 4);
offlimitDates.add(offsetForWeekend(baseCalendar));
//Vetrans Day
baseCalendar.set(year, Calendar.NOVEMBER, 11);
offlimitDates.add(offsetForWeekend(baseCalendar));
//Christmas
baseCalendar.set(year, Calendar.DECEMBER, 25);
offlimitDates.add(offsetForWeekend(baseCalendar));
//Now deal with floating holidays.
//Martin Luther King Day
offlimitDates.add(calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.JANUARY));
//Presidents Day
offlimitDates.add(calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.FEBRUARY));
//Memorial Day
offlimitDates.add(calculateFloatingHoliday(0, Calendar.MONDAY, year, Calendar.MAY));
//Labor Day
offlimitDates.add(calculateFloatingHoliday(1, Calendar.MONDAY, year, Calendar.SEPTEMBER));
//Columbus Day
offlimitDates.add(calculateFloatingHoliday(2, Calendar.MONDAY, year, Calendar.OCTOBER));
//Thanksgiving Day and Thanksgiving Friday
Date thanksgiving = calculateFloatingHoliday(4, Calendar.THURSDAY, year, Calendar.NOVEMBER);
offlimitDates.add(thanksgiving);
offlimitDates.add(addDays(thanksgiving, 1));
return offlimitDates;
}
/**
* This method will take in the various parameters and return a Date objet
* that represents that value.
*
* Ex. To get Martin Luther Kings BDay, which is the 3rd Monday of January,
* the method call woudl be:
*
* calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.JANUARY);
*
* Reference material can be found at:
* http://michaelthompson.org/technikos/holidays.php#MemorialDay
*
* #param nth 0 for Last, 1 for 1st, 2 for 2nd, etc.
* #param dayOfWeek Use Calendar.MODAY, Calendar.TUESDAY, etc.
* #param year
* #param month Use Calendar.JANUARY, etc.
* #return
*/
private static Date calculateFloatingHoliday(int nth, int dayOfWeek, int year, int month)
{
Calendar baseCal = Calendar.getInstance();
baseCal.clear();
//Determine what the very earliest day this could occur.
//If the value was 0 for the nth parameter, incriment to the following
//month so that it can be subtracted alter.
baseCal.set(year, month + ((nth <= 0) ? 1 : 0), 1);
Date baseDate = baseCal.getTime();
//Figure out which day of the week that this "earliest" could occur on
//and then determine what the offset is for our day that we actually need.
int baseDayOfWeek = baseCal.get(Calendar.DAY_OF_WEEK);
int fwd = dayOfWeek - baseDayOfWeek;
//Based on the offset and the nth parameter, we are able to determine the offset of days and then
//adjust our base date.
return addDays(baseDate, (fwd + (nth - (fwd >= 0 ? 1 : 0)) * 7));
}
/*
* If the given date falls on a weekend, the
* method will adjust to the closest weekday.
* I.E. If the date is on a Saturday, then the Friday
* will be returned, if it's a Sunday, then Monday
* is returned.
*/
private static Date offsetForWeekend(Calendar baseCal)
{
Date returnDate = baseCal.getTime();
if (baseCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
{
if (log.isDebugEnabled())
log.debug("Offsetting the Saturday by -1: " + returnDate);
return addDays(returnDate, -1);
}
else if (baseCal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
{
if (log.isDebugEnabled())
log.debug("Offsetting the Sunday by +1: " + returnDate);
return addDays(returnDate, 1);
}
else
return returnDate;
}
/**
* Private method simply adds
* #param dateToAdd
* #param numberOfDay
* #return
*/
private static Date addDays(Date dateToAdd, int numberOfDay)
{
if (dateToAdd == null)
throw new IllegalArgumentException("Date can't be null!");
Calendar tempCal = Calendar.getInstance();
tempCal.setTime(dateToAdd);
tempCal.add(Calendar.DATE, numberOfDay);
return tempCal.getTime();
}
}
jBPM (v3 at least) has a good business calendar implementation.
If you don't want the whole dependency on JBPM, I think you can take out just the calendar package
for date calculations try joda-time.sourceforge.net
but i have no idea about what you mean by configuring holidays. because each country has different holidays. but try that one first, it is good for date and time calculation.
I would suggest creating your own domestic holiday class that you can manage each of the holidays in. All of the holidays have rules on which day they will be. It is easy enough to program for these dates each year.
Martin Luther King day for example:
private static Date holidayHumanRights(int parmYear)
{
Date tempDate = new Date(parmYear, 0, 1); //January 1st...
try
{
tempDate = getNextDayofWeek(tempDate, "Monday");
//now point towards the 3rd Monday, which would be 2 weeks from
//current Monday date...
tempDate.advanceDays(2*7);
}
catch (Exception ex)
{
//throw or suppress the error, your choice
System.err.println(ex.toString());
}
return tempDate;
}
While thinking of the same problem I found out a Quartz Calendar. It has several problems like:
It is an implementation part of a scheduling library - using it apart from all quartz just as a holiday calendar is a bit hackish.
It has getNextIncludeTime method but no getPrevIncludeTime.
It has ugly and inconsistent API - AnnualCalendar has getter and setter that takes ArrayList, MonthlyCalendar has getter and setter that takes boolean[], both of them just expose class internals.
It has some poorly documented issues - you can chain calendars, but order of chaining is important - DailyCalendar created on AnnualCalendar is OK, AnnualCalendar created on DailyCalendar will break (hang, I think).
Still it is the best thing I could find. So maybe just take the source code, fix what's wrong and add what's missing?
I recently developed this open source project http://lamma.io which is designed for date generation.
For example:
Date(2015, 10, 5) to Date(2015, 10, 15) by 2 except Weekends
will yield
List(2015-10-05, 2015-10-07, 2015-10-09, 2015-10-13, 2015-10-15)
The project is licensed under DO WHAT YOU WANT TO PUBLIC LICENSE, so feel free to use / redistribute :)