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 :)
Related
I recently answered some questions using LocalDate.atStartOfDay() and LocalDate.atTime(LocalTime.MIN).
I was wondering why there is no LocalDate.atEndOfDay() or similar, so one has to use LocalDate.atTime(LocalTime.MAX) in order to get the very last moment (in nanos, I think) of that specific day.
I had a look at the source of LocalDate and LocalTime and got slightly confused by this:
/**
* Combines this date with the time of midnight to create a {#code LocalDateTime}
* at the start of this date.
* <p>
* This returns a {#code LocalDateTime} formed from this date at the time of
* midnight, 00:00, at the start of this date.
*
* #return the local date-time of midnight at the start of this date, not null
*/
public LocalDateTime atStartOfDay() {
return LocalDateTime.of(this, LocalTime.MIDNIGHT);
}
Contrary to my expectation, this method returns a LocalDateTime using LocalTime.MIDNIGHT instead of LocalTime.MIN.
Of course, I opened the OpenJDK source of LocalTime and was sure to find out the difference myself, but I found out there is no difference apart from the name of the constant:
/**
* Constants for the local time of each hour.
*/
private static final LocalTime[] HOURS = new LocalTime[24];
static {
for (int i = 0; i < HOURS.length; i++) {
HOURS[i] = new LocalTime(i, 0, 0, 0);
}
MIDNIGHT = HOURS[0]; // <--- == MIN
NOON = HOURS[12];
MIN = HOURS[0]; // <--- == MIDNIGHT
MAX = new LocalTime(23, 59, 59, 999_999_999);
}
While I totally understand the presence of NOON and MAX, I don't really get why there are MIN and MIDNIGHT when obviously one of them would be enough since they have the very same value.
Can anyone tell me the reason why...
... there are two constants having the very same value and
... why the code uses MIDNIGHT for the start of a day?
Is it just for having something more readable in some situations?
But why isn't MIN used in LocalTime.atStartOfDay() but rather LocalTime.MIDNIGHT?
MIN exists to provide the minimum value, which is consistent with other java.time.* classes.
MIDNIGHT exists to provide semantic meaning to developers, and as a place to indicate to Javadoc readers that midnight is considered to be at the start of the day (not the end).
Summary, the semantic benefits in code reading outweigh the cost of the extra constant.
(Source: I'm the main java.time.* author)
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.
The scenario is as follows.
You have to check if the current time is between a given start day + time and end day + time. A specific date range is not given, and the range can be in two different days.
Example:
String startDayAndTime = "SATURDAY 17:00";
String endDayAndTime = "SUNDAY 17:00";
SimpleDateFormat simpleDateFormatForTime = new SimpleDateFormat("HH:mm");
SimpleDateFormat simpleDateFormatForDay = new SimpleDateFormat("EEEE");
simpleDateFormatForTime.setTimeZone(timeZone);
simpleDateFormatForDay.setTimeZone(timeZone);
String deviceTimeString = simpleDateFormatForTime.format(date);
String deviceDayString = simpleDateFormatForDay.format(date).toUpperCase();
// TODO boolean isValidDayRange =
boolean withInRange = deviceTimeString.compareTo(startDayAndTime.split(" ")[1]) >= 0 && deviceTimeString.compareTo(endDayAndTime.split(" ")[1]) <= 0;
if (isValidDayRange && withInRange) {
//do something
}
This above code I'm working on can check for the time but not the date.
How to achieve this? TIA.
PS: Real world example: A shop offers discount for a product on every weekend from 5PM Saturday to 5PM Sunday. Trying to check the current time is eligible for that.
Requirement Update: Has to be in Java 1.7 or lesser
There is nothing in java.time to represent a day and a time (à la MonthDay) but we can quite easily define our own. I have chosen a DayOfWeek and a Duration. Make sure you validate that the time is non-negative and is less than 24 hours.
Note that DayOfWeek has a natural ordering of Monday (lowest) to Sunday (highest).
class DayTime implements Comparable<DayTime>
{
private final DayOfWeek dayOfWeek;
private final Duration time;
//...
public int compareTo(final DayTime o) { /* ... */ }
}
We can then define an event which specifies a start and end time. Make sure to validate that the start is not after the end.
class Event
{
private final DayTime start;
private final DayTime end;
//...
boolean isTimeDuringEvent(final DayTime dayTime) { /* ... */ }
}
I have left the implementation details up to you. It's your assignment.
We can use these classes like so:
final DayTime start = new DayTime(DayOfWeek.SATURDAY, Duration.ofHours(17));
final DayTime end = new DayTime(DayOfWeek.SUNDAY, Duration.ofHours(17));
final Event event = new Event(start, end);
final LocalDateTime now = LocalDateTime.now();
final DayTime test = new DayTime(
now.getDayOfWeek(),
Duration.ofNanos(now.toLocalTime().toNanoOfDay())
);
System.out.println(event.isTimeDuringEvent(test));
If you need to take user input as a string then I would advise you to work on getting the logic correct first (as above, with hardcoded values such as DayOfWeek.SATURDAY) and then when you're sure that that works, work on parsing the input. (you'll probably want DateTimeFormatter for this)
Using TemporalAccessor
You can use TemporalAccessors and a DateTimeFormatter to read the values and then build simple comparators to check your work.
String startDayAndTime = "SATURDAY 17:00";
String endDayAndTime = "SUNDAY 17:00";
DateTimeFormatter format = DateTimeFormatter.ofPattern("EEEE HH:mm");
TemporalAccessor tempNow = LocalDateTime.now();
TemporalAccessor tempStart = format.parse(startDayAndTime.toLowerCase());
TemporalAccessor tempEnd = format.parse(endDayAndTime.toLowerCase());
Comparator<TemporalAccessor> dayCompare = (a, b) -> a.get(ChronoField.DAY_OF_WEEK) - b.get(ChronoField.DAY_OF_WEEK);
Comparator<TemporalAccessor> timeCompare = (a, b) -> LocalTime.from(a).compareTo(LocalTime.from(b));
Comparator<TemporalAccessor> dateCompare = dayCompare.thenComparing(timeCompare);
if (dateCompare.compare(tempStart, tempNow) >= 0 && dateCompare.compare(tempNow, tempEnd) >= 0) {
//do something
}
You can access the date as below
LocalDateTime today = LocalDateTime.now();
LocalDate ld = LocalDate.now();
ld = ld.with(TemporalAdjusters.previous(DayOfWeek.SATURDAY));
LocalDateTime previousMonday = ld.atTime(17, 00);
LocalDate ld2 = LocalDate.now();
ld2 = ld2.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
LocalDateTime nextSunday = ld2.atTime(17, 00);
You can write your logic after that.
As above you can find previousMonday and nextSunday.
if previousMonday and nextSunday time gap less than a week, you are in the gap. Otherwise you are in out.
You can use calendar here
Calendar startDateTime=Calendar.getInstance();
startDateTime.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY);
startDateTime.set(Calendar.HOUR_OF_DAY,1);
startDateTime.set(Calendar.MINUTE,0);
startDateTime.set(Calendar.SECOND,0);
System.out.println("start Date : "+startDateTime.getTime());
Calendar endDateTime=Calendar.getInstance();
endDateTime.set(Calendar.DAY_OF_WEEK,Calendar.FRIDAY);
endDateTime.set(Calendar.HOUR_OF_DAY,17);
endDateTime.set(Calendar.MINUTE,0);
endDateTime.set(Calendar.SECOND,0);
System.out.println("end Date : "+endDateTime.getTime());
Calendar today = Calendar.getInstance();
if(today.after(startDateTime) && today.before(endDateTime))
{
System.out.println("Yes");
}
But here you have need to maintain order of day because calendar WEEKS start with SUNDAY and ends with SATURDAY. So you have to follow this Order. Smaller is startdate and bigger is end date.
Order is like this
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Sunday.
*/
public final static int SUNDAY = 1;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Monday.
*/
public final static int MONDAY = 2;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Tuesday.
*/
public final static int TUESDAY = 3;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Wednesday.
*/
public final static int WEDNESDAY = 4;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Thursday.
*/
public final static int THURSDAY = 5;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Friday.
*/
public final static int FRIDAY = 6;
/**
* Value of the {#link #DAY_OF_WEEK} field indicating
* Saturday.
*/
public final static int SATURDAY = 7;
But I think it is enough to serve your requirements.
thanks for the answers and the conversations. I managed to solve the issue from both TemporalAccessor and Calendar options given. Later a new requirement was given as to the util class I was working on has to be written in Java 1.7 or lesser since it was to be a library for an android app which didn't support Java 1.8. Hence the answer by #flopcoder was accepted, on the grounds where Sunday was taken as the beginning of the week and the logic was only to be applied on ranges within one week only.
You have written the code to check only day and time, not written the code to check date use simpleDateFormat and send the system current date to check and compare, you are passing "HH: mm" Which will give you system current time and "EEEE" Will give you day, .... So u need to pass "dd" to get current system date only and then compare as per you requirement
public class Dating
{
// Note: this class has no instance variables!
/**
* Creates an empty Dating object so that you can call the methods
*/
public Dating()
{
// Empty constructor
}
/**
* Computes and returns the next year in which New Year's Day will
* fall on the same day of the week as in a given year
* #param theYear the given year
* #return the next year in which New Year's day is the same day
* of the week as in parameter theYear
*/
public int newYears(int theYear)
{
// TO DO: write body of this method here
}
/**
* Computes and returns the Date on which Election Day will fall
* in the USA for a given year.
*
* NOTE: By law, Thanksgiving Day is the first Tuesday after the first
* Monday in November.
*
* #param year the year for which to compute the date of Election Day
* #return the Date of Election Day for the specified year
*/
public Date electionTime(int year)
{
INSERT CODE HERE
}
I feel like I got the electionTime part correct but I am confused as in to where to begin for newYears. Any suggestions? I'm uncertain how to put together a code that would calculate not only when the date is but when it will happen again. I was not given a specific year to start with either.
/*
* Computes and returns the next year in which New Year's Day will
* fall on the same day of the week as in a given year.
*/
public int newYears(int year)
{
// First, find out what day of the week it falls on in year X
Calendar calendar = new GregorianCalendar(); // create a calendar object
calendar.set(year, 0, 1); // calendar.set([year], January, 1st)
int day = calendar.get(Calendar.DAY_OF_WEEK); // store this value for later
// The code between the curly braces below will be executed 30 times,
// the first time i = 1, the second i = 2, third i = 3, etc...
for(int i = 1; true; i++)
{
calendar.set(year + i, 0, 1); // set the calendar to the next year
if(calendar.get(Calendar.DAY_OF_WEEK) == day) // compare to the value we stored earlier, and if it's the same day...
{
return year + i; // we have the correct year!
}
}
}
EDIT
Okay I'm going overboard here but I must follow the calling of my inner geek.
I took a for loop and looped through and ran a bunch of sequential years through the function, subtracted to find the difference, and got this table:
in | out | difference
2004 2009 5
2005 2011 6
2006 2012 6
2007 2018 11
2008 2013 5
2009 2015 6
2010 2016 6
2011 2022 11
2012 2017 5
2013 2019 6
2014 2020 6
2015 2026 11
There's a very clear pattern that repeats every four years (because of leap year I suppose). Using this, we can write a sneaky/condensed version of this function:
public int sneakyNewYears(int year)
{
int diff = year % 4;
int add = -1;
if(diff == 0) add = 5;
if(diff == 1) add = 6;
if(diff == 2) add = 6;
if(diff == 3) add = 11;
return year + add;
}
This works fine for 98.6% percent of years, but testing this 'sneaky' function against the working function shows that there are a few years that this doesn't work for, for some odd reason... These years: 1575, 1577, 1578, 1579, 1580, 1581, 1582, 1691, 1695, 1696, 1697, 1698, 1699, 1700, 1791, 1795, 1796, 1797, 1798, 1799, 1800, 1891, 1895, 1896, 1897, 1898, 1899 and 1900.
Anyway.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How can I increment a date by one day in Java?
I have an existing date object that I'd like to increment by one day while keeping every other field the same. Every example I've come across sheds hours/minutes/seconds or you have to create a new date object and transfers the fields over. Is there a way you can just advance the day field by 1?
Thanks
EDIT: Sorry i didn't mean increment the value of the day by one, i meant advance the day forward by 1
Calendar c = Calendar.getInstance();
c.setTime(yourdate);
c.add(Calendar.DATE, 1);
Date newDate = c.getTime();
The Date object itself (assuming you mean java.util.Date) has no Day field, only a "milliseconds since Unix Epoch" value. (The toString() method prints this depending on the current locale.)
Depending of what you want to do, there are in principle two ways:
If you want simply "precisely 24 hours after the given date", you could simply add 1000 * 60 * 60 * 24 milliseconds to the time value, and then set this. If there is a daylight saving time shift between, it could then be that your old date was on 11:07 and the new is on 10:07 or 12:07 (depending of the direction of shift), but it still is exactly 24 hours difference.
private final static long MILLISECONDS_PER_DAY = 1000L * 60 * 60 * 24;
/**
* shift the given Date by exactly 24 hours.
*/
public static void shiftDate(Date d) {
long time = d.getTime();
time += MILLISECONDS_PER_DAY;
d.setTime(time);
}
If you want to have "the same time on the next calendar day", you better use a Calendar, like MeBigFatGuy showed. (Maybe you want to give this getInstance() method the TimeZone, too, if you don't want your local time zone to be used.)
/**
* Shifts the given Date to the same time at the next day.
* This uses the current time zone.
*/
public static void shiftDate(Date d) {
Calendar c = Calendar.getInstance();
c.setTime(d);
c.add(Calendar.DATE, 1);
d.setTime(c.getTimeInMillis());
}
If you are doing multiple such date manipulations, better use directly a Calendar object instead of converting from and to Date again and again.
org.apache.commons.lang.time.DateUtils.addDays(date, 1);