-1

I am using Java and iterating over D.B. column which in return gives me date and time string as shown below:

String dateTime = resultSet.getSeries().get(0).getValues().get(0).get(0);

If I iterate on this resultset I am getting dateTime values in format as shown below.

2017-07-20T19:21:37.987792408Z
2017-04-24T22:04:26.808753375Z
2017-08-14T22:22:40.340772396Z
2017-06-24T22:24:32.422544491Z
2017-07-31T22:27:05.893368615Z

Out of these records, how can I compare date string with "current" date object and discard those values which are more than 10 days old?

I tried

Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);

That didn't work. Any other idea?

Edit: I am using Java7 and using InfluxDB that does not provide sysdate column while querying. So I have to come up with solution using Java.

Ammad
  • 4,031
  • 12
  • 39
  • 62
  • 4
    Possible duplicate of [How to compare dates in Java?](https://stackoverflow.com/questions/2592501/how-to-compare-dates-in-java) combined with [Java string to date conversion](https://stackoverflow.com/questions/4216745/java-string-to-date-conversion) – takendarkk Aug 18 '17 at 00:25
  • Well, start by parsing them to actual Date objects. Do have any code that attempts that? – OneCricketeer Aug 18 '17 at 00:25
  • 2
    Step 1: Parse string to date. Step 2: Calculate difference between dates. Both topic have been discussed and explained extensively on this site and elsewhere. – shmosel Aug 18 '17 at 00:26
  • 2
    Note: Ideally your database can easily provide this functionality already, so you don't need to do it in Java. (especially if you are using a "time series database", based on your previous questions) – OneCricketeer Aug 18 '17 at 00:26
  • I am using InfluxDB that does not provide sysdate column while querying – Ammad Aug 18 '17 at 00:30
  • 1
    @Ammad Post clarifications as edits to your Question rather than as comments. Your readers should not have to dredge through the comments to discern your question. Also, if you are limited to an old version of Java , note that fact in your Question or as a Tag. – Basil Bourque Aug 18 '17 at 01:11

2 Answers2

3

java.time

Retrieve date-time values as date-time objects, not strings.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.

Instant instant = myResultSet.getObject( … , Instant.class ) ;

Compare to ten days before the current moment.

Instant now = Instant.now() ;
Instant tenDaysAgo = now.minus( 10 , ChronoUnit.DAYS ) ;
Boolean prior = instant.isBefore( tenDaysAgo ) ;

You may not want to base your "ten days ago" on UTC. If not, apply a time zone to get a ZonedDateTime and LocalDate. This has been covered many times so search Stack Overflow. Think about if "days" means (a) chunks of 24-hours or (b) calendar dates to you.

FYI, those strings happen to be in standard ISO 8601 format. The T separates the date portion from time portion. The Z is short for Zulu and means UTC. This Instant class uses the same format in its toString method.

SQL

Generally, you should do such comparison work in the database as part of the SQL query rather than in your Java app. The database is highly tuned for this work; your app is not.

String sql = "SELECT * FROM tbl_ WHERE when_ < ? " ;
… make your PreparedStatement
myPreparedStatement.setObject( 1 , tenDaysAgo ) ;
… execute
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s); will work? – Ammad Aug 18 '17 at 00:35
  • 1
    @Ammad You are using a troublesome old class, now legacy, supplanted by the java.time classes. Do yourself a favor and forget you ever saw that class, likewise `Calendar`. – Basil Bourque Aug 18 '17 at 00:37
  • 2
    @Ammad You can use [Threeten backport](http://www.threeten.org/threetenbp), a backport for Java 8 classes. It has classes and methods with same names and functionality. Also check [Oracle's tutorial](https://docs.oracle.com/javase/tutorial/datetime), a good starting point for this API. `SimpleDateFormat` won't work because it has millisecond precision - only 3 digits after decimal point (and it gives wrong results when input has more than 3) –  Aug 18 '17 at 00:38
  • I upgraded to Threeten Api, Instant instant = Instant.parse((CharSequence) result1.getSeries().get(0).getValues().get(0).get(0)) ; Instant now = Instant.now() ; Instant tenDaysAgo = now.minus( 10 , ChronoUnit.DAYS ) ; Boolean prior = instant.isBefore( tenDaysAgo ) ; Fix that. – Ammad Aug 18 '17 at 01:02
  • 1
    @Ammad Your work will be easier to program, simpler to comprehend, and faster to execute if you (a) learn to use appropriate data types rather than strings, and (b) learn to leverage your database engine whenever possible. – Basil Bourque Aug 18 '17 at 01:08
3

Assuming dates is a list of strings that represent dates such as in your example, with Java 8 ZonedDateTime and DateTimeFormatter APIs you can simply do:

dates = dates.stream()
        .map(ZonedDateTime::parse)
        .filter(z -> z.isAfter(ZonedDateTime.now().minusDays(10L)))
        .map(Zon‌​edDateTime::toString‌​)
        .collect(Collectors.toList());

System.out.println(dates);  // [2017-08-14T22:22:40.340772396Z]

UPDATE
@Basil and @shmosel raised a valid point in their comments below, the check, the way it's implemented right now, checks now() against each one of the strings (this now() is different for any such comparison).

If we want to check the same specific point in time, against all the strings we should "freeze" now(), a nice way to do it (thanks @shmosel for the suggestion) would be to create a single instance of now() and using its method reference:

ZonedDateTim‌​e.now().minusDays(10‌​)::isAfter

or:

ZonedDateTime tenDaysAgo = ZonedDateTime.now().minusDays(10L);
dates = dates.stream()
        .map(ZonedDateTime::parse)
        .filter(z -> z.isAfter(tenDaysAgo))
        .map(Zon‌​edDateTime::toString)
        .collect(Collectors.toList());
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • 1
    Isn't that call to `.now` going to be repeated? If so, the results will be inconsistent. – Basil Bourque Aug 18 '17 at 00:40
  • @BasilBourque since we deal with accuracy of days I don't think it should matter, that said - it's a valid point and the question should be directed back to the OP. – Nir Alfasi Aug 18 '17 at 00:41
  • 1
    You can fix the above problem and get rid of the formatter and use method references: `dates.stream().map(ZonedDateTime::parse).filter(ZonedDateTime.now().minusDays(10)::isBefore).map(ZonedDateTime::toString)` – shmosel Aug 18 '17 at 00:42
  • @shmosel I didn't think about doing something such as `ZonedDateTim‌​e.now().minusDays(10‌​)::isBefore` - Nice! – Nir Alfasi Aug 18 '17 at 00:43
  • Though I find it a bit less readable, which is why I'm not modifying this bit. – Nir Alfasi Aug 18 '17 at 00:46
  • Agree on that point, but it's more than just an aesthetic difference in this case. – shmosel Aug 18 '17 at 00:49
  • @shmosel the diff in time between processing one string to the next one is measured in nanoseconds, the diff that the OP is looking for is in days. So unless this list is _very very_ long or the diff in nanoseconds actually matters - only in one of these cases I'd change it. That said, since it's a valid point I'll update the answer to make sure this point wouldn't escape the reader's eye. – Nir Alfasi Aug 18 '17 at 00:52
  • 1
    I understand your point, but I think precision is too important in programming. Though if we're talking precision, it should probably be `z -> !z.isBefore(tenDaysAgo)`, which is neither concise nor easily readable. – shmosel Aug 18 '17 at 01:02
  • There's also the consideration of all the extra objects being created, but that (as well as the precision issue) can be resolved with a simple variable. – shmosel Aug 18 '17 at 01:03
  • @shmosel creating short lived objects is not an issue anymore, I'd trade this kind of efficiency for readability without blinking ;) – Nir Alfasi Aug 18 '17 at 01:08
  • 1
    Agreed, but it's still worth noting IMO. Especially considering the variable solution improves performance, precision **and** readability. – shmosel Aug 18 '17 at 01:10
  • @shmosel when you're right I can't disagree... :) – Nir Alfasi Aug 18 '17 at 01:11