I have a list of DateTime objects and my task is to compare them and find the latest timestamp. The DateTime class is used from Joda API. I have been stuck on this part for a little while now. I would appreciate the help.
Collections.max()
DateTimeZone dtz = DateTimeZone.forID("Indian/Comoro");
List<DateTime> dateTimeObjects = Arrays.asList(
new DateTime(2021, 2, 13, 21, 0, dtz),
new DateTime(2021, 2, 13, 22, 0, dtz),
new DateTime(2021, 2, 13, 23, 0, dtz));
DateTime latestDateTime = Collections.max(dateTimeObjects);
System.out.println(latestDateTime);
Output:
2021-02-13T23:00:00.000+03:00
Collections.max() throws a NoSuchElementException if the list is empty. It throws a NullPointerException if the list contains a null (except perhaps if the null is the sole element, then it may get returned).
When comparing DateTime objects from different time zones Joda-Time first compares the instants, the points in time, so also in this case you are getting the latest. For example:
List<DateTime> dateTimeObjects = Arrays.asList(
new DateTime(2021, 2, 13, 21, 0, DateTimeZone.forID("Asia/Istanbul")),
new DateTime(2021, 2, 13, 22, 0, DateTimeZone.forID("Atlantic/Madeira")),
new DateTime(2021, 2, 13, 23, 0, DateTimeZone.forID("Antarctica/Macquarie")));
DateTime latestDateTime = Collections.max(dateTimeObjects);
System.out.println(latestDateTime);
Output:
2021-02-13T22:00:00.000Z
We got the time 22:00 for Madeira. You may wonder that the time 23:00 for Macquarie would seem later, but Macquarie is at UTC offset +11:00, so that time is in fact 10 hours earlier. DateTime objects are Comparable and compare by instant, not by clock hour. So we have got the latest point in time. We always will, also when several time zones are mixed.
Documentation link: Collections.max()
Related
How can I check if specific time will occur between two dates, for example:
time -> 11:34
dates 1.12 17:00 <-> 2.12 17:01
LocalDateTime startDateTime = LocalDateTime.of(2017, Month.DECEMBER, 1, 17, 0);
LocalDateTime endDateTime = LocalDateTime.of(2017, Month.DECEMBER, 2, 17, 1);
LocalTime timeToTest = LocalTime.of(11, 34);
// Does the timeToTest occur some time between startDateTime and endDateTime?
LocalDateTime candidateDateTime = startDateTime.with(timeToTest);
if (candidateDateTime.isBefore(startDateTime)) {
// too early; try next day
candidateDateTime = candidateDateTime.plusDays(1);
}
if (candidateDateTime.isAfter(endDateTime)) {
System.out.println("No, " + timeToTest + " does not occur between " + startDateTime + " and " + endDateTime);
} else {
System.out.println("Yes, the time occurs at " + candidateDateTime);
}
This prints
Yes, the time occurs at 2017-12-02T11:34
It’s a little bit tricky. I am exploiting the fact that LocalTime implements the TemporalAdjuster interface, which allows me to adjust one into another date-time class, in this case startDateTime. I don’t know at first whether this will adjust the time forward or backward, so I need to test that in a subsequent if statement.
Please consider whether you wanted your date-time interval to be inclusive/closed, exclusive/open or half-open. The standard recommendation is the last: include the start time, exclude the end time; but only you know your own requirements.
Also be aware that using LocalDateTime prevents taking summer time (DST) and other transitions into account. For example, if moving the clock forward in spring, some times of day will not exist that day, but the above code will be happy to tell you they do exist.
The idea would be calculating the dates between start and end date. Then pair it with your specific time and check if any date time matches the following constraint: start <= date + time <= end.
public boolean isTimeInBetween(LocalDateTime start, LocalDateTime end, LocalTime time) {
return start.toLocalDate().datesUntil(end.plusDays(1).toLocalDate())
.anyMatch(d -> !(d.atTime(time).isBefore(start) || d.atTime(time).isAfter(end)));
}
You can define 3 variables, start, end and a test time. Using Java 8's LocaleDateTime makes this simple enough. See example below with 3 test cases:
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2017, 12, 1, 17, 0);
LocalDateTime end = LocalDateTime.of(2017, 12, 2, 17, 1);
System.out.println("Test with time before range");
System.out.println(isInRange(start, end, LocalDateTime.of(2017, 12, 1, 12, 0)));
System.out.println("Test with time in range");
System.out.println(isInRange(start, end, LocalDateTime.of(2017, 12, 2, 11, 34)));
System.out.println("Test with time after range");
System.out.println(isInRange(start, end, LocalDateTime.of(2017, 12, 2, 20, 0)));
}
private static boolean isInRange(LocalDateTime start, LocalDateTime end, LocalDateTime test) {
return !(test.isBefore(start) || test.isAfter(end));
}
Output:
Test with time before range
false
Test with time in range
true
Test with time after range
false
I want to find the number of dates from 1st week, 2nd week, 3 rd week and 4th week from the given dates list
[2017-11-22 21:41:39.0, 2017-11-27 23:15:26.0, 2017-11-27 23:26:23.0,
2017-11-28 19:50:18.0, 2017-11-29 16:14:33.0] are dates
//By Using map
Map<Integer, List<Date>> map;
map = inboxOutboxentityList.stream()
.collect(Collectors.groupingBy(element ->
element.getDate().get(weekFields.weekOfWeekBasedYear())
)
);
If you can, just forget about the long outdated Date class and solve your problem in pure java.time. Your code is not far from working.
List<LocalDateTime> entities = Arrays.asList(
LocalDateTime.of(2017, Month.NOVEMBER, 22, 21, 41, 39),
LocalDateTime.of(2017, Month.NOVEMBER, 27, 23, 15, 26),
LocalDateTime.of(2017, Month.NOVEMBER, 27, 23, 26, 23),
LocalDateTime.of(2017, Month.NOVEMBER, 28, 19, 50, 18),
LocalDateTime.of(2017, Month.NOVEMBER, 29, 16, 14, 33));
Map<Integer, Long> countPerWeek = entities.stream()
.collect(Collectors.groupingBy(
ldt -> ldt.get(WeekFields.ISO.weekOfWeekBasedYear()),
Collectors.counting()));
System.out.println(countPerWeek);
This prints:
{48=4, 47=1}
So the count is 1 for week 47 and 4 for week 48. I believe this was what you intended. Please substitute a different WeekFields object if required.
If you are getting a list of Date objects, you will need to convert them into some modern class first. There are plenty of questions and answers about how to do that, happy searcing. As you have probably already realized, you can do it in the same series of stream operations.
I am using Joda Time library for parsing the string into dateTime using parseDateTime funtion in this library and noticed that date range supported for this library is -292,269,054 to 292,277,023.
Can anyone know on how to limit date range using this library.Especially with year (YYYY) to 9999?
Thanks.
Interval Class
You can limit date ranges in Joda-Time with Interval.
You can then query whether a DateTime is within that interval/range.
As MadProgrammer commented, limiting a date range is your job as the app developer. Joda-Time cannot know what you consider to be reasonable limits.
Bean Validation
To help with that chore of validating data, you might find the Bean Validation spec useful. Defined by JSR 303 (spec 1.0) and JSR 349 (spec 1.1).
With Bean Validation, you can conveniently use annotations to define rules such as a minimum and maximum value for a particular member variable in a class.
Joda-Time surprisingly offers what you want (really?). The apparent solution is using LimitChronology. An example:
DateTime min = new DateTime(2014, 1, 1, 0, 0);
DateTime max = new DateTime(2015, 1, 1, 0, 0).minusMillis(1);
Chronology chronology =
LimitChronology.getInstance(ISOChronology.getInstance(), min, max);
DateTime now = DateTime.now(chronology);
System.out.println(now.toString(DateTimeFormat.fullDateTime()));
// output: Donnerstag, 6. November 2014 19:08 Uhr MEZ
DateTime test = new DateTime(1970, 1, 1, 0, 0).withChronology(chronology);
System.out.println(test.toString(DateTimeFormat.fullDateTime()));
// no exception! => output: �, �. � ���� ��:�� Uhr MEZ
test = now.withYear(1970);
// IllegalArgumentException:
// The resulting instant is below the supported minimum of
// 2014-01-01T00:00:00.000+01:00 (ISOChronology[Europe/Berlin])
My advise is however not to use this feature.
First reason is the inconvenience to apply the LimitChronology on every DateTime-object in your program. Probably you would be forced to change your application architecture to install a central factory for producing such exotic DateTime-objects in order to be sure that you really don't forget any object.
Another reason is the partial unreliability of the chronology in question. It can not prevent instantiating DateTime-objects outside of the supported limited range but produces strange formatted output (see example above).
Therefore I suggest you to follow the advise of #MadProgrammer or #CharlieS using Interval for range checks.
I am not sure, but you can test with this code
DateTime startRange = new DateTime(2010, 1, 1, 12, 0, 0, 0);
DateTime endRange = new DateTime(9999, 12, 31, 21, 59, 59, 59);
Interval interval = new Interval(startRange, endRange);
DateTime testRange = new DateTime(2014, 10, 30, 11, 0, 0, 0);
System.out.println(interval.contains(testRange)); // returns true
endRange = new DateTime(2014, 12, 31, 21, 59, 59, 59);
testRange = new DateTime(9999, 10, 30, 11, 0, 0, 0);
System.out.println(interval.contains(testRange)); // returns false
I need to populate JComboBox with days as follows:
April 1, 2014
April 2, 2014
...
April 10,2014
I am using JodaTime to define dates. However, I don't know how to create an iterater over days in JodaTime.
JComboBox<String> days = new JComboBox<String>();
DateTime startD = new DateTime(2014, 4, 1, 0, 0, 0);
for (int i=0; i<10; i++)
{
// DateTime nextD = ...
days.addItem(startD.toString(DateTimeFormat.forPattern("yyyyMMdd")));
}
DateTime currentDate = startD.plusDays(i);
You should have found that easily by reading the javadoc.
Note that unless you really want the items to represent a precise instant (i.e. the first april at midnight in your timezone), you should probably use a LocalDate instead of a DateTime.
Given a DateTime object at 31-March-2011 and this code:
DateTime temp1 = new DateTime(2011, 3, 31, 12, 0, 0, 0);
DateTime temp2 = temp1.plusMonths(1);
DateTime temp3 = temp2.plusMonths(1);
after the execution
temp1 = 2011-03-31T12:00:00.000+02:00
temp2 = 2011-04-30T12:00:00.000+02:00
temp3 = 2011-05-30T12:00:00.000+02:00
temp3 is wrong here.
Is that above correct. Am I doing a mistake?
No, there's no mistake here. You're adding one month twice, which means the second time you'll get the result of adding a month to the possibly truncated result of adding the first month.
April only has 30 days, which is why you're getting April 30th for temp2 - and adding one month to April 30th gets you to May 30th.
If you want May 31st, use:
DateTime temp3 = temp1.plusMonths(2);
Basically, date and time arithmetic gives "odd" results if you try to think of it in terms of associativity etc.