I need a Timetable class that would work like (a rough example to explain the idea):
Timetable timetable = new Timetable("Mon-Fri 8:00-17:00");
Date eta = timetable.increment(new Date(), 3, Calendar.HOURS);
eta should be the point in time, which is exactly 3 hours ahead of current time, but only the time between 8:00 and 17:00 is taken into account. This may sound like an interview question, but I need such a class for a business purpose and I suspect that some open source implementation exists already.
I think this is very close to parse the string into a date then use java.util.Calendar to either add or subtract the date.
check this
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#add(int, int)
// create a calendar
Calendar cal = Calendar.getInstance()
// print current date
System.out.println("The current date is : " + cal.getTime());
// add 20 days to the calendar
cal.add(Calendar.DATE, 20);
System.out.println("20 days later: " + cal.getTime());
// subtract 2 months from the calendar
cal.add(Calendar.MONTH, -2);
System.out.println("2 months ago: " + cal.getTime());
// subtract 5 year from the calendar
cal.add(Calendar.YEAR, -5);
System.out.println("5 years ago: " + cal.getTime());
Related
i need to add a decimal amount of month to a java date :
-> i can use this code with joda time api to add a natural amount of months to a date. But how can i add a decimal amount of month ( for example 3.5) to a date ?
Date date = new Date();
DateTime dateTime = new DateTime(date);
dateTime = dateTime.plusMonths(3);
Date newDate = dateTime.toDate();
This will give you an approximation. It’s the best you can get.
long oneMonthInNanos = ChronoUnit.MONTHS.getDuration().toNanos();
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Phnom_Penh"));
System.out.println("Now " + now);
System.out.println("In 3.5 months " + now.plusNanos(Math.round(3.5 * oneMonthInNanos)));
System.out.println("In 4.5 months " + now.plusNanos(Math.round(4.5 * oneMonthInNanos)));
System.out.println("In 12 months " + now.plusNanos(Math.round(12.0 * oneMonthInNanos)));
Output when I ran the code just now, was:
Now 2018-11-06T22:31:36.460573+07:00[Asia/Phnom_Penh]
In 3.5 months 2019-02-21T11:13:27.460573+07:00[Asia/Phnom_Penh]
In 4.5 months 2019-03-23T21:42:33.460573+07:00[Asia/Phnom_Penh]
In 12 months 2019-11-07T04:20:48.460573+07:00[Asia/Phnom_Penh]
As has been said in comments, there is no really good definition of a fractional number of months. When you compare the first and the last date-time you also clearly see that 12 months don’t add up to a year precisely, though pretty close. Please check yourself whether the results are good enough for your purpose.
I am using java.time. I din’t know whether something similar is possible in Joda-Time.
I use LocalDate (ThreeTenABP) to calculate the period between to given dates. When I use 01/01/2018 as the first and 12/31/2018 as the second date, Period.between gives the following result:
00 years
11 months
30 days
IMHO this is wrong, since a full year has 12 months.
I tried to add one day. Then I get:
00 years
11 months
31 days
I would need a reliable method to get the real amount of full months within a given period.
If you look at the Javadoc for Period.between(), it tells you that the end date is exclusive (meaning: not counted).
The start date is included, but the end date is not. The period is calculated by removing complete months, then calculating the remaining number of days, adjusting to ensure that both have the same sign.
I wrote this code, and it appears to function as I would expect...
LocalDate d1 = LocalDate.of(2018, 1, 1);
LocalDate d2 = LocalDate.of(2018, 12, 31);
Period p1 = Period.between(d1, d2);
System.out.println(p1.getYears() + " years, " + p1.getMonths() + " months, " + p1.getDays() + " days");
// Prints: 0 years, 11 months, 30 days
Adding one day, making it 2019-01-01, gives me one year:
LocalDate d3 = LocalDate.of(2019, 1, 1);
Period p2 = Period.between(d1, d3);
System.out.println(p2.getYears() + " years, " + p2.getMonths() + " months, " + p2.getDays() + " days");
// Prints: 1 years, 0 months, 0 days
Edit:
If you just add one day to the calculated Period object, you are really just adding a day, not recalculating the period as the between method would. Here's the code from Period which does plusDays():
public Period plusDays(long daysToAdd) {
if (daysToAdd == 0) {
return this;
}
return create(years, months, Math.toIntExact(Math.addExact(days, daysToAdd)));
}
If you follow the create call, it really just adds one day to the days counter, it doesn't recalculate anything. To properly add a day to a period, recalculate it with different endpoints as I have above.
The reliable method is:
LocalDate begin = LocalDate.of(2018, Month.JANUARY, 1);
LocalDate end = LocalDate.of(2018, Month.DECEMBER, 31);
Period inclusive = Period.between(begin, end.plusDays(1));
System.out.println(inclusive);
This prints
P1Y
Voilà, a period of one year. Adding 1 day to the end date makes the end date inclusive (since now it’s the day after the end date that is exclusive).
Hello guys i have a tricky question for you that i really cant find a solution out there.
What i want to do is to have 3 date/time inputs on simpledateformat
Date 1
Date 2
Date 3
and basicaly i want to get difference of months days hours and minutes from date 1 - date2 and result of those 2 dates to be added on the firth date
for example 11/3/2017 12:30 - 7/3/2017 = 4 days and ADD that to current date 13/3/2017 13:30 + 4 days and 1 hour = 17/3/2017 14:30
i know how to get the diference in days hours and minutes , i cant get the second part of adding the result to the current date
any ideas?
thank you in dvance
Use Calendar class to add days and hours
Calendar cal = Calendar.getInstance();
cal.setTime(yourDate);
cal.add(Calendar.DAY_OF_MONTH, yourDays); //adds days to your date
cal.add(Calendar.HOUR_OF_DAY, yourHours); //adds hours to your date
cal.getTime(); //to get Date instance
To decrement dates just add negative number, for example:
int yourDays = -daysVariable;
int yourHours = -hoursVariable; //
Calendar cal = Calendar.getInstance();
cal.setTime(yourDate);
cal.add(Calendar.DAY_OF_MONTH, yourDays); //decrement days
cal.add(Calendar.HOUR_OF_DAY, yourHours); //decrement hours
cal.getTime(); //to get Date instance
Get a date object using the simpledate format
Because it is an object of the same type
Comparison is possible
I think you need to use getTime and add days throught miliseconds.
For example, if you can get the difference of days you should use something like this
date1.getTime() + 24*60*60*1000*4
(where 4 is the difference you want to add)
You can use Calendar too.
Thank you all for your ultra fast replies!
I solved it by using Mij Solution
Calendar cal = Calendar.getInstance();
cal.setTime(yourDate);
cal.add(Calendar.DAY_OF_MONTH, yourDays); //adds days to your date
cal.add(Calendar.HOUR_OF_DAY, yourHours); //adds hours to your date
cal.getTime(); //to get Date instance
To add days and
tis code to decrese days
Calendar cal = Calendar.getInstance();
cal.setTime(yourDate);
cal.add(Calendar.DAY_OF_MONTH, -yourDays); //adds days to your date
cal.add(Calendar.HOUR_OF_DAY, -yourHours); //adds hours to your date
cal.getTime(); //to get Date instance
and to control if date is bigget than my current date i used this condition
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date strDate = sdf.parse(valid_until);
if (new Date().after(strDate)) {
catalog_outdated = 1;
}
it returns -1 if the date is past from current
+1 if date is bigger that current or whatever
and 0 if dates are equal
again thank you!
When calculating years between two dates, where the second date is calculated from the first one (this is a simplified example of what I'm working on), LocalDate and Period seem to calculate a year slightly differently.
For example,
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plusYears(1);
System.out.println(Period.between(date, plusYear).getYears());
while
LocalDate date = LocalDate.of(1996, 3, 29);
LocalDate plusYear = date.plusYears(1);
System.out.println(Period.between(date, plusYear).getYears());
Despite having explicitly added a year, first Period return the years as 0, while the second case returns 1.
Is there a neat way around this?
This question has a philosophical nature and spans few problems like time measurements, and date format conventions.
LocalDate is an implementation of ISO 8601 date exchange standard.
Java Doc states explicitly that this class does not represent time but provides only standard date notation.
The API provides only simple operations on the notation itself and all calculations are done by incrementing the Year, or Month, or Day of a given date.
In other words, when calling LocalDate.plusYears() you are adding conceptual years of 365 days each, rather than the exact amount of time within a year.
This makes Day the lowest unit of time which one can add to a date expressed by LocalDate.
In human understanding, date is not a moment in time, but it is a period.
It starts with 00h 00m 00s (...) and finishes with 23h 59m 59s (...).
LocalDate however avoids problems of time measurement and vagueness of human time units (hour, day, month, and a year can all have different length) and models date notation simply as a tuple of:
(years, months within a year, days within a month )
calculated since the beginning of the era.
In this interpretation, it makes sense that Day is the smallest unit affecting the date.
As an example following:
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusSecond = date.plus(1, ChronoUnit.SECONDS);
returns
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
... which shows, that using LocalDate and adding the number of seconds (or smaller units to drive the precision), you could not overcome the limitation listed in your question.
Looking at the implementation you find that LocalDate.plusYears() after adding the years, calls resolvePreviousValid(). This method then checks for leap year and modifies the day field in the following manner:
day = Math.min(day, IsoChronology.INSTANCE.isLeapYear((long)year)?29:28);
In other words it corrects it by effectively deducting 1 day.
You could use Year.length() which returns the number of days for given year and will return 366 for leap years. So you could do:
LocalDate plusYear = date.plus(Year.of(date.getYear()).length(), ChronoUnit.DAYS);
You will still run into following oddities (call to Year.length() replaced with the day counts for brevity):
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plus(365, ChronoUnit.DAYS);
System.out.println(plusYear);
Period between = Period.between(date, plusYear);
System.out.println( between.getYears() + "y " +
between.getMonths() + "m " +
between.getDays() + "d");
returns
1997-02-28
0y 11m 30d
then
LocalDate date = LocalDate.of(1996, 3, 29);
LocalDate plusYear = date.plus(365, ChronoUnit.DAYS);
System.out.println(plusYear);
Period between = Period.between(date, plusYear);
System.out.println( between.getYears() + "y " +
between.getMonths() + "m " +
between.getDays() + "d");
returns
1997-03-29
1y 0m 0d
and finally:
LocalDate date = LocalDate.of(1996, 2, 29);
LocalDate plusYear = date.plus(366, ChronoUnit.DAYS);
System.out.println(plusYear);
Period between = Period.between(date, plusYear);
System.out.println( between.getYears() + "y " +
between.getMonths() + "m " +
between.getDays() + "d");
returns:
1997-03-01
1y 0m 1d
Please note that moving the date by 366 instead of 365 days increased the period from 11 months and 30 days to 1 year and 1 day (2 days increase!).
I want to get the starting and ending dates of a week
for example
2012-05-06 to 2012-05-12
2012-05-13 to 2012-05-19
The code I have written is
currWeekCalender.add(Calendar.WEEK_OF_YEAR, 1);
String dateStart = currWeekCalender.get(Calendar.YEAR) + "-" + addZero((currWeekCalender.get(Calendar.MONTH) + 1)) + "-" + addZero(currWeekCalender.getFirstDayOfWeek());
currWeekCalender.add(Calendar.DAY_OF_MONTH,7);
String dateEnd = currWeekCalender.get(Calendar.YEAR) + "-" + addZero((currWeekCalender.get(Calendar.MONTH) + 1)) + "-" + addZero(currWeekCalender.get(Calendar.DAY_OF_MONTH));
but the results are not correct, also I want previous weeks date.
Thanks
Hello to all coders :)
I work on little app to dive some data from database. To calculate previous weeks start and end date i use this code:
// Calendar object
Calendar cal = Calendar.getInstance();
// "move" cal to monday this week (i understand it this way)
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
// calculate monday week ago (moves cal 7 days back)
cal.add(Calendar.DATE, -7);
Date firstDateOfPreviousWeek = cal.getTime();
// calculate sunday last week (moves cal 6 days fwd)
cal.add(Calendar.DATE, 6);
Date lastDateOfPreviousWeek = cal.getTime();
Hope, that helps.
Your problem is that getFirstDayOfWeek() returns the first day of the week; e.g., Sunday in US, Monday in France. It does not return a day of the month. See javadoc.
The first day in a month that is the start of the week is (in pseudo-code)
((7 + (firstDayOfWeek - dayOfWeek(firstOfMonth))) % 7) + 1
You can translate that into java.util.Calendar code if you like, but I would suggest using Joda time instead.
also I want previous weeks date.
Just subtract seven days maybe using add
currCalendar.add(Calendar.DAY_OF_MONTH, -7)
This may involve underflow, but add deals with that.
add(f, delta)
adds delta to field f. This is equivalent to calling set(f, get(f) + delta) with two adjustments:
Add rule 1. The value of field f after the call minus the value of field f before the call is delta, modulo any overflow that has occurred in field f. Overflow occurs when a field value exceeds its range and, as a result, the next larger field is incremented or decremented and the field value is adjusted back into its range.
Java 8 version
This prints previous 10 weeks
final ZonedDateTime input = ZonedDateTime.now();
for(int i = 1; i < 10; i++) {
final ZonedDateTime startOfLastWeek = input.minusWeeks(i).with(DayOfWeek.MONDAY);
System.out.print(startOfLastWeek.format(DateTimeFormatter.ISO_LOCAL_DATE));
final ZonedDateTime endOfLastWeek = startOfLastWeek.plusDays(6);
System.out.println(" - " + endOfLastWeek.format(DateTimeFormatter.ISO_LOCAL_DATE));
}