Add 30 minutes to the current time - java

I have written the code below but if the current date-time is 2022-07-03 09:48:05.448 and I add 30 minutes, my response returns 2022-07-03 09:79:05.448.
But minutes can never be 79, it is supposed to move to the hours instead...
public static String getExpiryDate(int additionalMinutesToCurrentMinute) {
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int month = now.getMonthValue();
int day = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute() + additionalMinutesToCurrentMinute;
int second = now.getSecond();
int millis = now.get(ChronoField.MILLI_OF_SECOND); // Note: no direct getter available.
String expiryDateAndTime = String.format("%d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, millis);
return expiryDateAndTime;
}

Explanation
The reason your code does not work as expected is because you are not involving javas Date/Time API at all in your "math".
Your adding the minutes with plain int-arithmetic
int minute = now.getMinute() + additionalMinutesToCurrentMinute;
and then you use plain string formatting
String.format("%d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, millis);
Nothing in this chain is "clever" and knows about date/time specifics.
Solution
You have to involve the Date/Time API for your math, then it will be clever and correctly adjust the hours as well. Fortunately, there is a method in LocalDateTime already that does what you want:
LocalDateTime expirationTime = LocalDateTime.now().plusMinutes(30);
and that is pretty much all you need.
For the formatting part, either roll with the default representation:
return expirationTime.toString();
or use a DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd HH:mm:ss.AAA");
and then
return expirationTime.format(formatter);
Notes
Instant
You are actually using the incorrect type for an expiration time. Using LocalDateTime will result in your application failing under certain situations. For example if your computer moves across countries, or your government decides to change its timezone. Or when DST hits (summer vs winter time) or leap seconds are added and more...
The correct type would be Instant, which represents a single moment on the timeline, without interpretation of clock-time or calendar-dates.
The API is the same, so you can just use it the same way.
That said, your method should also return Instant and not a String. Keep the clever date/time type as long as possible, dont go to something as low level and raw as a string.
public static Instant getExpiryDate(int additionalMinutes) {
return Instant.now()
.plus(additionalMinutes, ChronoUnit.MINUTES);
}
Design
Design-wise it would be better if the method would not even take int additionalMinutes but also the unit. Otherwise the call-site is hard to read for users:
getExpiryDate(30) // 30 what? minutes? seconds? days?
with the unit, it would be easier to read and harder to misunderstand
getExpiryDate(30, ChronoUnit.MINUTES)
At which point one could argue that the method is kinda obsolete now.

Instead of editing the amount of minutes manually, try using the plusMinutes method on your LocalDateTime like so:
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusMinutes(30);
This way, the class should increase the hour for you once it passes 60 minutes.

Related

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds

i like to get the duration between to datetime values in minutes.
public long datetimeDiffInMinutes(String dateStop, String dateStart) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDate firstDate = LocalDate.parse(dateStart, formatter);
LocalDate secondDate = LocalDate.parse(dateStop, formatter);
Duration d1 = Duration.between(firstDate, secondDate);
long min = d1.toMinutes();
return min;
}
There will be thrown an exception: java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
But i dont use "Seconds" in this function. This line throws the exception: Duration d1 = Duration.between(firstDate, secondDate);
The documentation for the method you're calling (Duration.between(Temporal, Temporal)) states:
The specified temporal objects must support the SECONDS unit. For full accuracy, either the NANOS unit or the NANO_OF_SECOND field should be supported.
But LocalDate.isSupported is documented with:
If the unit is a ChronoUnit then the query is implemented here. The supported units are: DAYS, WEEKS, MONTHS, YEARS, DECADES, CENTURIES, MILLENNIA, ERAS
All other ChronoUnit instances will return false.
So no, LocalDate doesn't support seconds, which is required for the method you're calling.
It may be worth considering that a Duration is intended to be an elapsed time - a fixed number of seconds etc. The elapsed time between two dates may depend on the time zone involved - because a day doesn't always have 24 hours when there are time zones involved.
If you're happy assuming a 24-hour day, you could use Duration.ofDays(DAYS.between(firstDate, secondDate)).
You specify your dates with time information. That makes LocalDate a suboptimal choice. LocalDateTime is a better option. That already lets you create a duration.
Results may be off because of DST. Adding the right time zone should solve that:
ZoneId zone = ZoneId.systemDefault(); // or an explicit one
ZonedDateTime firstDateTime = LocalDateTime.parse(dateStart, formatter).atZone(zone);
ZonedDateTime secondDateTime = LocalDateTime.parse(dateStop, formatter).atZone(zone);
Duration d1 = Duration.between(firstDateTime, secondDateTime);
long min = d1.toMinutes();
For differences between dates, Period is a better representation.
Because your format string contains time, however, it looks like you want to be parsing to LocalDateTime instead of LocalDate. This way, the minutes (and seconds) you care about are not discarded:
private static final DateTimeFormatter parser =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public long datetimeDiffInMinutes(String dateStop, String dateStart) {
LocalDateTime firstDate = parser.parse(dateStart, LocalDateTime::from);
LocalDateTime secondDate = parser.parse(dateStop, LocalDateTime::from);
return firstDate.until(secondDate, ChronoUnit.MINUTES);
}
Note that because you don't have information about the time zone and any daylight-saving transitions that may occur, the results might not match what people expect in every case. You should clarify the use case, and get more information about the zone if necessary.

How to get duration by subtracting Arrival time by departing time in Java using Gregorian calendar?

Lets say I have to subtract Arrival time by departing time of specific days. How would I do this in Java using Gregorian calendar?
public Duration getDuration(){
SimpleDateFormat date = new SimpleDateFormat("YYYYMMDD");
SimpleDateFormat time = new SimpleDateFormat("HHMM");
String ArivalTime = "1720"
String DepartingTime = "1100"
String ArivalDate = "20200220"
String DepartingDate = "20200211"
Calendar departureDateCalc = new GregorianCalendar();
//return duration;
}
the code is barely anything. But I need to subtract an Arrival date by Departing date
java.time
Don’t use GregorianCalendar for this. Use java.time, the modern Java date and time API.
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmm");
String arrivalTime = "1720";
String departingTime = "1100";
String arrivalDate = "20200220";
String departingDate = "20200211";
String arrivalTimeZone = "Africa/Niamey";
String departingTimeZone = "America/Mendoza";
ZonedDateTime departure = LocalDate.parse(departingDate, DateTimeFormatter.BASIC_ISO_DATE)
.atTime(LocalTime.parse(departingTime, timeFormatter))
.atZone(ZoneId.of(departingTimeZone));
ZonedDateTime arrival = LocalDate.parse(arrivalDate, DateTimeFormatter.BASIC_ISO_DATE)
.atTime(LocalTime.parse(arrivalTime, timeFormatter))
.atZone(ZoneId.of(arrivalTimeZone));
Duration difference = Duration.between(departure, arrival);
System.out.println(difference);
This outputs:
PT218H20M
So a period of time of 218 hours 20 minutes. If you want it more readable:
String diffString = String.format(
"%d days %d hours %d minutes", difference.toDays(),
difference.toHoursPart(), difference.toMinutesPart());
System.out.println(diffString);
9 days 2 hours 20 minutes
The conversion to days assumes that a day is always 24 hours, which may not be the case in either of the departure or the arrival time zone, for example when they go from standard to summer time (DST) or vice versa.
Don’t use GregorianCalendar
The GregorianCalendar class is poorly designed and long outdated. Don’t use it. For anything. If you had wanted to use it for finding a duration, the way would have been to add one day at a time to the departure time until you reach the arrival time. If you’re past it, subtract one day again and start counting hours, again by adding one at a time. Same with minutes. It’s way more complicated and also more error-prone than using the Duration class directly.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Duration.ofDays generates UnsupportedTemporalTypeException

I am trying to learn the new Date & Time API. My code is working except for the last line:
LocalDate current=LocalDate.now();
System.out.println(current);
LocalDate personaldate=LocalDate.of(2011,Month.AUGUST, 15);
System.out.println(personaldate);
LocalDate afterten=current.plus(Period.ofDays(10));
System.out.println(afterten);
// error occurs here
System.out.println(afterten.plus(Duration.ofDays(3)));
When I try and add a Duration in days, it generates an error. Can anyone help me understand why?
Error:
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
at java.time.LocalDate.plus(LocalDate.java:1241)
at java.time.LocalDate.plus(LocalDate.java:137)
at java.time.Duration.addTo(Duration.java:1070)
at java.time.LocalDate.plus(LocalDate.java:1143)
at TestClass.main(TestClass.java:15)
Whilst the accepted answer is completely correct, when I arrived at this question, I was looking for a simple solution to my problem.
I found using Period would not allow me to count the number of days between my two LocalDate objects. (Tell me how many years, months and days between the two, yes, but not just then number of days.)
However, to get the result I was after was as simple as adding the LocalDate method "atStartOfDay" to each of my objects.
So my erronious code:
long daysUntilExpiry = Duration.between(LocalDate.now(), training.getExpiryDate()).toDays();
was simply adjusted to:
long daysUntilExpiry = Duration.between(LocalDate.now().atStartOfDay(), training.getExpiryDate().atStartOfDay()).toDays();
Doing this make the objects into LocalDateTime objects which can be used with Duration. Because both object have start of day as the "time" part, there is no difference.
Hope this helps someone else.
A Duration measures an amount of time using time-based values (seconds, nanoseconds). A Period uses date-based values (years, months, days).
here is the link
https://docs.oracle.com/javase/tutorial/datetime/iso/period.html
the same as in JodaTime
//(year,month,day)
LocalDate beginDate = LocalDate.of(1899,12,31);
LocalDate today = LocalDate.now();
ChronoUnit.DAYS.between(beginDate, today)
As hinted before, Duration is always seconds-based whereas Period honours the day as concept.
The code throws an exception when it tries to add seconds on a LocalDate - which is also day-based.
Changing your code like this shows the difference: use LocalDateTime when getting down to instants within days:
LocalDateTime current = LocalDateTime.now();
System.out.println(current);
LocalDateTime afterten = current.plus(Period.ofDays(10));
System.out.println(afterten);
// error occurred here - but with LocalDateTime is resolved!
System.out.println(afterten.plus(Duration.ofDays(3)));
Try to run following code in a Unit test and see for yourself that the accepted answer to your problem should be ChronoUnit.DAYS.between() as stated by Ravi.
LocalDate date1 = LocalDate.of(2020,6,2);
LocalDate date2 = LocalDate.of(2020,7,4);
System.out.printf("ChronoUnit.DAYS = %d%n", ChronoUnit.DAYS.between(date1, date2));
System.out.printf("Period.between = %d%n",Period.between(date1, date2).getDays());
Because the output will look as follows:
ChronoUnit.DAYS = 32
Period.between = 2
Period will incorrectly return only the days portion of the difference (ignoring higher order differences like months and years).
System.out.printf("Duration.between = %d%n",Duration.between(date1, date2).getSeconds());
This will throw an exception as LocalDate does not provide enough information for seconds calculations (undefined hour, minutes and seconds).
Therefore you would have to convert it to LocalDateTime for example by calling date1.atStartOfDay().
System.out.printf("Duration.between = %d%n",Duration.between(date1.atStartOfDay(), date2.atStartOfDay()).get(ChronoUnit.DAYS));
This call will simply throw java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Days because of how the get method on Duration class is implemented in Java:
#Override
public long get(TemporalUnit unit) {
if (unit == SECONDS) {
return seconds;
} else if (unit == NANOS) {
return nanos;
} else {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
}

Test a date within a day intervall range

I have a date and a number and want to check if this date and this number occurs in a list of other dates within:
+-20 date intervall with the same number
so for example 1, 1.1.2013 and 1,3.1.2013 should reuturn false.
I tried to implement the method something like that:
private List<EventDate> dayIntervall(List<EventDate> eventList) throws Exception {
List<EventDate> resultList = new ArrayList<EventDate>();
for (int i = 0; i < eventList.size(); i++) {
String string = eventList.get(i).getDate();
Date equalDate = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN).parse(string);
for (int j = 0; j < eventList.size(); j++) {
String string1 = eventList.get(i).getDate();
Date otherDate = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN).parse(string1);
if (check number of i with number of j && check Date) {
//do magic
}
}
}
return resultList;
}
The construction of the iteration method is not that hard. What is hard for me is the date intervall checking part. I tried it like that:
boolean isWithinRange(Date testDate, Date days) {
return !(testDate.before(days) || testDate.after(days));
}
However that does not work because days are not takes as days. Any suggestions on how to fix that?
I really appreciate your answer!
You question is difficult to follow. But given its title, perhaps this will help…
Span Of Time In Joda-Time
The Joda-Time library provides a trio of classes to represent a span of time: Interval, Period, and Duration.
Interval
An Interval object has specific endpoints that lie on the timeline of the Universe. A handy contains method tells if a DateTime object occurs within those endpoints. The beginning endpoint in inclusive while the last endpoint is exclusive.
Time Zones
Note that time zones are important, for handling Daylight Saving Time and other anomalies, and for handling start-of-day. Keep in mind that while a java.util.Date seems like it has a time zone but does not, a DateTime truly does know its own time zone.
Sample Code
Some code off the top of my head (untested)…
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Berlin" );
DateTime dateTime = new DateTime( yourDateGoesHere, timeZone );
Interval interval = new Interval( dateTime.minusDays( 20 ), dateTime.plusDays( 20 ) );
boolean didEventOccurDuringInterval = interval.contains( someOtherDateTime );
Whole Days
If you want whole days, call the withTimeAtStartOfDay method to get first moment of the day. In this case, you probably need to add 21 rather than 20 days for the ending point. As I said above, the end point is exclusive. So if you want whole days, you need the first moment after the time period you care about. You need the moment after the stroke of midnight. If this does not make sense, see my answers to other questions here and here.
Note that Joda-Time includes some "midnight"-related methods and classes. Those are no longer recommended by the Joda team. The "withTimeAtStartOfDay" method takes their place.
DateTime start = dateTime.minusDays( 20 ).withTimeAtStartOfDay();
DateTime stop = dateTime.plusDays( 21 ).withTimeAtStartOfDay(); // 21, not 20, for whole days.
Interval interval = new Interval( start, stop );
You should avoid java.util.Date if at all possible. Using the backport of ThreeTen (the long awaited replacement date/time API coming in JDK8), you can get the number of days between two dates like so:
int daysBetween(LocalDate start, LocalDate end) {
return Math.abs(start.periodUntil(end).getDays());
}
Does that help?
You can get the number of dates in between the 2 dates and compare with your days parameter. Using Joda-Time API it is relatively an easy task: How do I calculate the difference between two dates?.
Code:
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN);
Date startDate = format.parse("1.1.2013");
Date endDate = format.parse("3.1.2013");
Days d = Days.daysBetween(new DateTime(startDate), new DateTime(endDate));
System.out.println(d.getDays());
Gives,
2
This is possible using Calendar class as well:
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
System.out.println(cal.fieldDifference(endDate, Calendar.DAY_OF_YEAR));
Gives,
2
This 2 can now be compared to your actual value (20).

How to create a joda time duration from java.sql.Time?

Hello I have this excerpt of code:
end = new DateTime(mergeToDateTime(this.endDate, this.empEndTime));
Duration extraTime = new Duration(this.preTime.getTime()); //add the first 30 mins
extraTime = extraTime.plus(new Duration(this.postTime.getTime())); //add the second 30 mins
end = end.plus(extraTime); // extraTime = -3600?
When I look in the debugger my durations are always coming up negative. I have no idea why this is, even though according to the API, it is possible to create a duration out of the a long type, hence the getTime(). (preTime and postTime are java.sql.Time types)
I guess your instances of java.sql.Time were created in such a way that their millisecond values include timezone offset.
For example, deprecated java.sql.Time(int hour, int minute, int second) constructor takes offset of the current timezone into account:
System.out.println(new Time(1, 0, 0).getTime()); // Prints -7200000 in UTC+3 timezone
It looks like timezone offset is introduced by JDBC driver, and it can be easily compensated by converting java.sql.Time to LocalTime (and vice versa):
LocalTime lt = new LocalTime(time);
Then you can convert LocalTime to duration:
Duration d = new Duration(lt.getMillisOfDay());
Aren't you starting out wrong when you use an instant in time as duration? The constructor signature you are using is Duration(long duration), not Duration(long startInstant) -- there is no such constructor, in fact.

Categories