Reputation: 183
I need to write a method that takes Date as input parameter in format YYYY-MM-DD and return all the Dates from the List which are on the same day.
The Dates in the List looks e.g. like this: 2020-06-09T07:10:28.1985307Z
Do I need to parse the parameter using "-" split and takhe the MM portion of the String and compare to MM portion of the List Date? It seems to be too complicated, could you give me some advice how to solve that better?
Upvotes: 0
Views: 1082
Reputation: 86359
This is not possible without deciding on a time zone. It is never the same date everywhere on earth, so whether a point in time from your list falls on this, that or even the other date, depends on time zone. This also implies that the new month begins at different times in different time zones. If my memory serves, one country even changed its time zone in order to be the first country to enter the new millennium some 20 years ago.
I have picked a time zone at random. You just pick your preferred time zone and substitute it into my code below. I am answering both of your questions in turn:
ZoneId zone = ZoneId.of("Africa/Kinshasa");
List<Instant> theList = List.of(
Instant.ofEpochSecond(1_590_965_000),
Instant.ofEpochSecond(1_590_966_000),
Instant.ofEpochSecond(1_592_002_800),
Instant.ofEpochSecond(1_592_089_100),
Instant.ofEpochSecond(1_593_557_000),
Instant.ofEpochSecond(1_593_558_000));
System.out.println("The gross list");
theList.forEach(System.out::println);
LocalDate userInput = LocalDate.parse("2020-06-13");
List<Instant> sameDay = theList.stream()
.filter(i -> i.atZone(zone).toLocalDate().equals(userInput))
.collect(Collectors.toList());
System.out.println("Same day: " + sameDay);
Output is:
The gross list 2020-05-31T22:43:20Z 2020-05-31T23:00:00Z 2020-06-12T23:00:00Z 2020-06-13T22:58:20Z 2020-06-30T22:43:20Z 2020-06-30T23:00:00Z Same day: [2020-06-12T23:00:00Z, 2020-06-13T22:58:20Z]
If your moments are not already Instant
objects, use Instant.parse
to convert them to Instant
before doing any other work with them. Congo is at offset +01:00 from UTC (all year), so 2020-06-12T23:00:00Z equals 2020-06-13T00:00:00+01:00[Africa/Kinshasa], so does fall on 13th June.
The code is quite similar.
YearMonth userMonth = YearMonth.from(userInput);
List<Instant> sameMonth = theList.stream()
.filter(i -> YearMonth.from(i.atZone(zone)).equals(userMonth))
.collect(Collectors.toList());
System.out.println(sameMonth);
[2020-05-31T23:00:00Z, 2020-06-12T23:00:00Z, 2020-06-13T22:58:20Z, 2020-06-30T22:43:20Z]
A YearMonth
is what the class name says, a year and a month. I figured that this was the correct class for representing your concept of same month
Oracle tutorial: Date Time explaining how to use java.time.
Upvotes: 0
Reputation: 896
1- Convert the input string to LocalDate
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(str, formatter);
2- With the LocalDate in hands, you have a number of operations that can be performed, such as retrieving the current day, month, year etc. Parse all the dates and implement your logic, these are some relevant methods:
date.getDayOfYear();
date.minusMonths();
date.isBefore();
Upvotes: 0
Reputation: 376
Date class is obsolete. Use LocalDate and ZonedDateTime for your solution.
public class Test {
public static void main(String[] args){
Test t = new Test();
List<LocalDate> result = t.fetchDates(LocalDate.parse("2020-06-09"));
System.out.println(result);
}
private List<ZonedDateTime> datesList = List.of(
ZonedDateTime.parse("2020-06-09T07:10:28.1985307Z"),
ZonedDateTime.parse("2020-06-01T01:10:28.1985307Z"),
ZonedDateTime.parse("2020-06-09T01:10:28.1985307Z"),
ZonedDateTime.parse("2020-06-08T01:10:28.1985307Z"),
ZonedDateTime.parse("2020-06-09T01:10:28.1985307Z")
);
public List<LocalDate> fetchDates(LocalDate date)
{
return datesList.stream()
.filter(zdt -> zdt.toLocalDate().equals(date))
.map(zdt -> zdt.toLocalDate())
.collect(Collectors.toList());
}
}
Prints [2020-06-09, 2020-06-09, 2020-06-09]
Upvotes: 1
Reputation: 103637
You say 'in format YYYY-MM-DD', which suggests what you actually get are String objects, not Date objects. Dates, LocalDates, Instants, etc, these don't have a format. They represent the thing they are named after (except Date, which is badly misnamed, and actually represents a timezoneless instant based on epochmillis and has absolutely no relation whatsoever to the human concept of dates).
To work with dates, you want to.. have date objects. Or rather, the right type from the java.time
package. If it's just a date, you're looking for LocalDate
. These are timezoneless. They just represent the concept of, say, 'april 4th, 1985', without location being involved. The inputs you have aren't dates. They are effectively moments in time, given that it's a minutiously specified time (with 6 digits for second fractions no less), and includes a timezone, which is a timezone no humans use for normal purposes even. That suggests what you're really looking for is Instant
.
You then want to do something really bizarre to the instant: Check the DATE. You're mixing the notion of a moment in time, with the notion of a date, which is fundamentally not a moment in time. After all, if it's the 4th of april in the netherlands, it could well be the 3rd of april in new york. If it's October 25th, 1917 in Moscow, it is November 7th in Amsterdam. Trying to equate 'dates' is nonsensical without first localizing. Who are you asking? Where did they live?
There are many ways you can turn the various types in the java.time
package from instants to dates and back. Here's one approach:
public static Instant read(String in) {
return Instant.parse(in);
}
public static LocalDate localize(Instant i, ZoneId zone) {
return i.atZone(zone).toLocalDate();
}
public static void main(String[] args) throws Exception {
Instant a = Instant.parse("2020-06-09T07:10:28.1985307Z");
Instant b = Instant.parse("2020-04-09T07:10:28.1985307Z");
Instant c = Instant.parse("2020-06-09T23:10:28.1985307Z");
ZoneId ams = ZoneId.of("Europe/Amsterdam");
LocalDate aDate = localize(a, ams);
LocalDate bDate = localize(b, ams);
LocalDate cDate = localize(c, ams);
System.out.println(aDate.isEqual(cDate));
}
The above would end up printing 'false'. The instant in time described by 2020-06-09T07:10:28.1985307Z would be described as being the 9th of june in 2020 by someone in amsterdam. The instant 2020-06-09T23:10:28.1985307Z would be described as the 10th (as amsterdam would at that point by +0200). Switch the zone to new york, and the answer would be true instead.
The question 'are these 2 instants the same date' is not a sane question to ask without also including in that question which zone is asking. Note that UTC is itself a zone, you can use it: ZoneId utc = ZoneOffset.UTC;
will get you there.
Upvotes: 3