I'm trying to get the first day of the next month from a LocalDate object but have run into some issues.
I have a datepicker where a user can pick any date they want, without restriction and I need to get the next month's first day, this is what I've thought about doing:
LocalDate localDate = myDatePicker.getValue();
LocalTime startTime = LocalTime.of(0, 0);
LocalDate endDate = LocalDate.of(localDate.getYear(), localDate.getMonthValue() + 1, 0);
However I see a problem that may occur when choosing the month December, if that happens then the call
LocalDate.of(localDate.getYear(), localDate.getMonthValue() + 1, 0);
Should fail because I'm passing it a month value of 13. Now I could choose to check if the month value is December and if so I could add 1 to the year and start at 0 like so:
if(localDate.getMonthValue() >= 12)
LocalDate.of(localDate.getYear() + 1, 0, 0);
However I feel like there must be a way to get around this within the class itself. Does anyone know if my presumptions about passing 13 to LocalDate.of month value will cause an error? If so is there a way to do what I want to do that doesn't look so bad and uses a build in method?
Fortunately, Java makes this really easy with the idea of adjusters and TemporalAdjusters.firstDayOfNextMonth():
import java.time.*;
import java.time.temporal.*;
public class Test {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2018, 12, 3);
LocalDate date2 = date1.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(date2); // 2019-01-01
}
}
Custom way with :
.plusMonths(1) to get the next month
.withDayOfMonth(1) to get the first day
LocalDate localDate = LocalDate.of(2018, 12, 15);
LocalDate firstNext = localDate.plusMonths(1).withDayOfMonth(1);
// or firstNext = localDate.withDayOfMonth(1).plusMonths(1);
System.out.println(firstNext); //2019-01-01
Built-in way with :
TemporalAdjusters.firstDayOfNextMonth()
firstNext = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
// does a temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS); operation
Using LocalDate you can get firstDayofNextMonth withTemporalAdjusters.firstDayOfNextMonth()
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class Test {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalDate firstDayOfNextMonth = date.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(firstDayOfNextMonth);
}
}
Related
Say I want my week to start on Tuesday, and the day should start at 5:30 am.
This means, code like this should work:
// LocalDateTimes created with the "standard" ISO time
LocalDateTime tuesday_4_30 = LocalDateTime.now()
.with(TemporalAdjusters.next(DayOfWeek.TUESDAY))
.withHour(4).withMinute(30);
LocalDateTime tuesday_6_30 = tuesday_4_30.withHour(6).withMinute(30);
LocalDateTime previous_monday = tuesday_4_30.minusDays(1);
// eventual adjustment using TemporalAdjusters here? like this?
// tuesday_4_30 = tuesday_4_30.with(new MyTemporalAdjuster(DayOfWeek.TUESDAY, 5, 30));
// <do the same for 6_30 and previous monday>
// or possibly change some global parameter like Chronology, Locale, or such..
Assert.assertEquals(tuesday_4_30.getDayOfWeek(), DayOfWeek.MONDAY);
Assert.assertEquals(tuesday_6_30.getDayOfWeek(), DayOfWeek.TUESDAY);
// there is 1 week between the previous monday and the next tuesday 6:30
Assert.assertEquals( ChronoUnit.WEEKS.between(previous_monday,tuesday_6_30), 1);
// there is 0 week between the previous monday and the next tuesday 4:30
Assert.assertEquals( ChronoUnit.WEEKS.between(previous_monday,tuesday_4_30), 0);
// 1 day between tuesday_4_30 and tuesday_6_30
Assert.assertEquals( ChronoUnit.DAYS.between(tuesday_4_30,tuesday_6_30), 1);
// 0 day between previous_monday and tuesday_4_30
Assert.assertEquals( ChronoUnit.DAYS.between(previous_monday,tuesday_4_30), 1);
I am tempted to use temporal adjusters here, and I'm quite sure I could offset the hours and minute so that the day starts at 5:30, but I can't figure out how to modify the start of the week.
Note that I looked into WeekFields but I can't make it work with ChronoUnit.XXX.between(), so I didn't go too far. It looks like I would have to code my own Chronology, which seemed too far strectched.
Can you help me?
Note: ChronoUnit.WEEKS.between counts the number of entire weeks (a period of 7 days) between two dates. In your case, there is only one days between the Monday and the Tuesday so it will return 0. You probably meant to compare the week of year fields instead.
Unless you want to write your own chronology (that's going to be a pain), you could "fake" your calendar by:
converting back and forth between UTC and UTC+5:30 to represent your cut-off time / or just subtract 5:30 from the dates
adding some simple logic for the week calculations
See below a rough example based on your code, that makes all the tests pass - you may want to extract the logic into a separate class etc. This is a bit hacky but may be enough for your use case.
#Test
public void test() {
LocalDateTime tuesday_4_30 = LocalDateTime.now()
.with(TemporalAdjusters.next(DayOfWeek.TUESDAY))
.withHour(4).withMinute(30);
LocalDateTime tuesday_6_30 = tuesday_4_30.withHour(6).withMinute(30);
LocalDateTime previous_monday = tuesday_4_30.minusDays(1);
// eventual adjustment using TemporalAdjusters here? like this?
// tuesday_4_30 = tuesday_4_30.with(new MyTemporalAdjuster(DayOfWeek.TUESDAY, 5, 30));
// <do the same for 6_30 and previous monday>
// or possibly change some global parameter like Chronology, Locale, or such..
assertEquals(dayOfWeek(tuesday_4_30), DayOfWeek.MONDAY);
assertEquals(dayOfWeek(tuesday_6_30), DayOfWeek.TUESDAY);
// there is 1 week between the previous monday and the next tuesday 6:30
assertEquals(weekBetween(previous_monday, tuesday_6_30), 1);
// there is 0 week between the previous monday and the next tuesday 4:30
assertEquals(weekBetween(previous_monday, tuesday_4_30), 0);
// 1 day between tuesday_4_30 and tuesday_6_30
assertEquals(weekBetween(tuesday_4_30, tuesday_6_30), 1);
// 0 day between previous_monday and tuesday_4_30
assertEquals(weekBetween(previous_monday, tuesday_4_30), 0);
}
private static DayOfWeek dayOfWeek(LocalDateTime date) {
return date.atOffset(ZoneOffset.ofHoursMinutes(5, 30)).withOffsetSameInstant(UTC).getDayOfWeek();
}
private static int weekBetween(LocalDateTime date1, LocalDateTime date2) {
OffsetDateTime date1UTC = date1.atOffset(ZoneOffset.ofHoursMinutes(5, 30)).withOffsetSameInstant(UTC);
OffsetDateTime date2UTC = date2.atOffset(ZoneOffset.ofHoursMinutes(5, 30)).withOffsetSameInstant(UTC);
int w1 = date1UTC.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
if (dayOfWeek(date1).getValue() >= TUESDAY.getValue()) w1++;
int w2 = date2UTC.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
if (dayOfWeek(date2).getValue() >= TUESDAY.getValue()) w2++;
return w2 - w1;
}
Alternative implementation, maybe cleaner:
private static DayOfWeek dayOfWeek(LocalDateTime date) {
return adjust(date).getDayOfWeek();
}
private static int weekBetween(LocalDateTime date1, LocalDateTime date2) {
int w1 = adjust(date1).get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
if (dayOfWeek(date1).getValue() >= TUESDAY.getValue()) w1++;
int w2 = adjust(date2).get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
if (dayOfWeek(date2).getValue() >= TUESDAY.getValue()) w2++;
return w2 - w1;
}
private static LocalDateTime adjust(LocalDateTime date) {
return date.minusHours(5).minusMinutes(30);
}
Am trying to get a LocalDate instance for each Year in a Period. For example, for this:
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(2011, Month.DECEMBER, 19);
Period period = Period.between(birthday, today);
I want 2012-12-19, 2013-12-19, 2014-12-19, 2015-12-19.
Given the methods of Period this isn't possible. Is there a way around this? Is it possible using another method?
Care must be taken when looping over dates. The "obvious" solution does not work properly. The solution of Soorapadman will work fine for the date given (the 19th December), but fail if the start date is the 29th February. This is because 1 year later is the 28th, and the date will never return to the 29th February, even when another leap year occurs.
Note that this problem is more pronounced for month addition. A start date of the 31st January will return the sequence 28th February (or 29th), then 28th March 28th April and so on. This is unlikely to be the desired output, which is probably the last date of each month.
The correct strategy is as follows:
public List<LocalDate> datesBetween(LocalDate start, LocalDate end, Period period);
List<LocalDate> list = new ArrayList<>();
int multiplier = 1;
LocalDate current = start;
while (!current.isAfter(end)) {
current = start.plus(period.multipliedBy(multiplier);
list.add(current);
multiplier++;
}
return list;
}
Note how the strategy adds an increasing period to the same start date. The start date is never altered. Using the same start date is critical to retain the correct month length of that date.
You can try like this using Java 8;
LocalDate start = LocalDate.of(2011, Month.DECEMBER, 19);
LocalDate end = LocalDate.now();
while (!start.isAfter(end)) {
System.out.println(start);
start = start.plusYears(1);
}
}
I want to take all Saturday and Sunday from given date range...
my inputs are
Start Date : 01/01/2011
End Date : 01/01/2012
now search date which is in between given start date and end date and day would be Saturday or Sunday.
Please Suggest...
Firstly, I'd recommend using Joda Time if you possibly can. It's a much better date and time API than the one built into Java.
Secondly, unless you're really worried about efficiency I would personally go for the incredibly-simple-but-somewhat-wasteful approach of simply iterating over every day in the time period, and including those which fall on the right days. Alternating between adding one day and adding six days would certainly be more efficient, but harder to change.
Sample code:
import java.util.*;
import org.joda.time.*;
public class Test
{
public static void main(String[] args)
{
List<LocalDate> dates = getWeekendDates
(new LocalDate(2011, 1, 1), new LocalDate(2011, 12, 1));
for (LocalDate date : dates)
{
System.out.println(date);
}
}
private static List<LocalDate> getWeekendDates
(LocalDate start, LocalDate end)
{
List<LocalDate> result = new ArrayList<LocalDate>();
for (LocalDate date = start;
date.isBefore(end);
date = date.plusDays(1))
{
int day = date.getDayOfWeek();
// These could be passed in...
if (day == DateTimeConstants.SATURDAY ||
day == DateTimeConstants.SUNDAY)
{
result.add(date);
}
}
return result;
}
}
I recommend to take a look at this RFC-2445 Java open-source library. You can create a weekly recurrence rule with repeating on Sat and Sun, then iterate over the specified period to get all dates.
I think, you can use following way - it's really simple and you don't need to use other libraries.
Take weekday number (for Monday = 1, Sunday = 7). Then - choose new start date, which is first Sunday occurence -> it is startDate + (7 - weekdayNum). By the same algorithm, you can take last Sunday from interval (by substracting EndDate - weekdayNum - 1, I think). And now you can go in for loop through all occurences (use incremental step 7). Or if you want specific occurence, e.g. 3rd sunday, you can simply do newStartDate + 3 * 7.
I hope, this is clear. I'm not sure, if numbers are correct. Hope this helps for understanding the problem.
Here is the complete example.
Please do suggest if we can make it better.
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
*
* #author varun.vishwakarma
*/
public class FindWeekendsInDateRange {
static HashMap<Integer, String> daysOfWeek=null;
static {
daysOfWeek = new HashMap<Integer, String>();
daysOfWeek.put(new Integer(1), "Sun");
daysOfWeek.put(new Integer(2), "Mon");
daysOfWeek.put(new Integer(3), "Tue");
daysOfWeek.put(new Integer(4), "Wed");
daysOfWeek.put(new Integer(5), "Thu");
daysOfWeek.put(new Integer(6), "Fri");
daysOfWeek.put(new Integer(7), "Sat");
}
/**
*
* #param from_date
* #param to_date
* #return
*/
public static List<Date> calculateWeekendsInDateReange(Date fromDate, Date toDate) {
List<Date> listOfWeekends = new ArrayList<Date>();
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
from.setTime(fromDate);
to.setTime(toDate);
while (from.getTimeInMillis() < to.getTimeInMillis()) {
if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sat") {
Date sat = from.getTime();
listOfWeekends.add(sat);
} else if (daysOfWeek.get(from.get(Calendar.DAY_OF_WEEK)) == "Sun") {
Date sun = from.getTime();
listOfWeekends.add(sun);
}
from.add(Calendar.DAY_OF_MONTH, 1);
}
return listOfWeekends;
}
public static void main(String[] args) {
String fromDate = "7-Oct-2019";
String toDate = "25-Oct-2019";
System.out.println(FindWeekendsInDateRange.calculateWeekendsInDateReange(new Date(fromDate), new Date(toDate)));
}
}
I'm assuming your start and end dates are given in milliseconds. Loop through the dates and check whether days are 'Saturday' or 'Sunday'. Below I'm returning the total no. of Saturday and Sunday in given date range.
private int totalWeekendDays(long start, long end)
{
int result=0;
long dayInMS = TimeUnit.DAYS.toMillis(1);
for (long i = start; i<=end; i = i + dayInMS)
{
String dayOfTheWeek = (String) DateFormat.format("EEEE", i);
if (dayOfTheWeek.equals("Sunday")||dayOfTheWeek.equals("Saturday"))
{
result = result+1;
}
}
return result;
}
I need to calculate a java.util.Date for a beginning of a today day (00:00:00 a.m. of a today day). Does someone know something better than resetting fields of java.util.Calendar:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.AM_PM, Calendar.AM);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
If you don't bother about time zones then your solution is ok. Otherwise it's worth to look at JodaTime.
If you eventually decide to switch to JodaTime, then you can use DateMidnight class which is supposed to be used in your situation.
The following code will return the current date's calendar object with time as 00:00:00
Calendar current = Calendar.getInstance();
current.set(current.get(Calendar.YEAR),current.get(Calendar.MONTH),current.get(Calendar.DATE),0,0,0);
It will not consider the timezone values and is almost same as your code. Only difference is that it is done all resets to 0 in single line.
This solution can be better as it does not make use of java's heavy element Calender
public class DateTest {
public static void main(String[] args) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
long time = dateFormat.parse(dateFormat.format(new Date())).getTime();
System.out.println("todays start date : " + new Date(time));
}
}
I'm in the same boat, and what you have provided is how I do it. I do have it in a DateUtil.stripToMidnight(...) function...
But just remember to consider TimeZones when doing all this, as 0:00am here, will not be the same in another part of the world.
There might be a way to do this in JodaTime, but I don't know of it.
With the date4j library :
DateTime start = dt.getStartOfDay();
Another option without additional libraries:
import java.sql.Date;
public class DateTest {
public static void main(String[] args) {
long MS_PER_DAY = 24L * 60 * 60 * 1000;
long msWithoutTime = (System.currentTimeMillis() / MS_PER_DAY) * MS_PER_DAY;
Date date = new Date( msWithoutTime );
System.out.println( date.toGMTString());
}
}
As of java8, it can be done as follow assuming you don't care about timezone
LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT);
Date midnight = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
I want to work out the next payment date in my code. I have a start date and i have a payment frequency which can be DAY, WEEK, MONTH or YEAR. So if the start date was 10 FEB 2009 and had a payment frequency of MONTH and the current date is 13 NOV 2009 then the next payment date would be 10 DEC 2009
I have already written some meaty code using JDK data classes to work this out. But we have move other parts of the system to Joda and so i would like to migrate this code to.
So does any Joda guru know how to do it easily?
Here's a brute force method (ignoring working days etc). Note that you can't just repeatedly add the period, as (Jan 30th + 1 month) + 1 month != Jan 30th + 2 months.
import org.joda.time.LocalDate;
import org.joda.time.Period;
public class Test {
public static void main(String[] args) {
LocalDate start = new LocalDate(2009, 2, 10);
LocalDate now = new LocalDate(2009, 11, 13);
System.out.println(next(start, Period.months(1), now));
}
public static LocalDate next(LocalDate start, Period period, LocalDate now) {
Period current = Period.ZERO;
while (true) {
LocalDate candidate = start.plus(current);
if (candidate.isAfter(now)) {
return candidate;
}
current = current.plus(period);
}
}
}
It's possible that there are less brute-force ways of doing it - particularly if you don't have to be able to take a completely arbitrary period - but this is probably the simplest solution.
Just putting together the comments
public static void main(String[] args) {
LocalDate date = LocalDate.parse("03-10-2010",Constants.DEFAULT_DATE_FORMAT);
Months gap = Months.monthsBetween(date,LocalDate.now());
System.out.println(Months.monthsBetween(date,LocalDate.now()));
System.out.println("Cycle Start " + date.plusMonths(gap.getMonths()));
System.out.println("Cycle End " + date.plusMonths(gap.getMonths()+1));
}