0

Have a string object with a specific format of date. Need to check if that dateStr is after the current time on local machine. Having trouble with conversions and LocalDateTime

String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
public static final String DATE_FORMAT = "MMM dd yyyy HH:mm:ss zzzZ";

I know something is fishy in the below code with the usage of LocalDateTime

public static boolean isFutureDate(String dateStr){
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
      LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
      return(dateTime.isAfter(LocalDateTime.now()));
}

Trouble is with timezones and date conversions. Please help find the right way of checking if a dateStr is after the current local date this in Java 8?

Ashok Goli
  • 5,043
  • 8
  • 38
  • 68

2 Answers2

4

Local… types have no time zone

You are using the wrong type for your data.

The Local… types including LocalDateTime purposely have no concept of time zone or offset-from UTC. As such they not represent a moment on the time line, only rough idea of a range of possible moments. Use LocalDateTime only when the time zone is unknown or irrelevant; never use it for an actual moment in history.

Use OffsetDateDate for values with an offset-from-UTC, a number of hours and minutes.

Use ZonedDateTime for values with an assigned time zone. A time zone such as Asia/Kolkata or America/Montreal is a particular region’s history of past, present, and future changes to its offset-from-UTC. Anomalies such as Daylight Saving Time (DST) mean a change to the offset.

If you know all your inputs are in GMT/UTC, use OffsetDateTime. If the inputs may use time zones, parse as ZonedDateTime objects.

This input data format is terrible. If you have any control, use standard ISO 8601 formats instead when exchanging date-time values as text.

All this has been covered many times already on Stack Exchange. Please search more thoroughly before posting. And search Stack Overflow to learn more. I kept my Answer here brief, as this is a duplicate.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
3

When parsing to a LocalDateTime, you're ignoring the offset (+0000), and I'm not sure if that's what you really want.

In this case, the +0000 offset means the date/time is October 27th 2017 at 02:29 AM in UTC. When you parse to a LocalDateTime, you're ignoring the offset (so it represents only "October 27th 2017 at 02:29 AM", not attached to any timezone) and comparing to your local date/time (or the current date/time in the JVM's default timezone).

If you want to make a comparison that also considers the offset, you can parse it to OffsetDateTime and convert to Instant to compare it with the actual UTC instant, regardless of the timezone.

Also, the month name is in English (I'm assuming it's English, but you can change this accordingly), so you must a java.util.Locale in the formatter (if you don't set a locale, it'll use the JVM default, and it's not guaranteed to always be English):

// parse to OffsetDateTime (use the same formatter)
String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss zzzZ", Locale.US);
OffsetDateTime odt = OffsetDateTime.parse(dateStr, fmt);
// compare Instant's
System.out.println(odt.toInstant().isAfter(Instant.now()));

Although it works for you now, keep in mind that the default locale can be changed without notice, even at runtime. If your input has locale-sensitive date (such as month names), it's better to specify it as above.

  • 1
    On the note of parsing the date, the format is [parsed appropriately](https://ideone.com/vlu0Og). – Naman Oct 27 '17 at 15:01
  • The first code block does not give me expected with the current GMT time and my local time. I'm trying your second method. But the parser works as expected :) – Ashok Goli Oct 27 '17 at 15:01
  • @AshokFelix The first code block just gets the date and time and ignores the offset - it doesn't make any conversions –  Oct 27 '17 at 15:06
  • 2
    @nullpointer Indeed, the format `zzzZ` works, I've made a typo when testing and thought it didn't. I've removed that note from the answer, thanks! –  Oct 27 '17 at 15:09
  • 2
    @AshokFelix The parser works because your JVM's default locale is probably English (or any other that recognizes "Oct" as month name), but it's not guaranteed to work in all configurations (my JVM is set to Portuguese and it fails if I don't set a specific locale) - I've added a note in the answer about it –  Oct 27 '17 at 15:13
  • @Hugo I tested it with a sample time of current gmt - 5 mins and gmt + 5 mins and both return false with both the samples above :( – Ashok Goli Oct 27 '17 at 15:34
  • @AshokFelix Could you please edit your question and add examples of inputs and outputs that fail? –  Oct 27 '17 at 15:35
  • @Hugo - Some more trials worked. I'm just testing with the current GMT time +/- a few minutes as input. Thank you. – Ashok Goli Oct 27 '17 at 15:45
  • @AshokFelix The input corresponds to `2017-10-27T02:29Z` (2:29 AM in UTC), which corresponds to an instant that happened more than 13 hours ago. So adding a few minutes will still be in the past. Anyway, I'm glad it worked! –  Oct 27 '17 at 15:46
  • @hugo Considered that. I changed the constant string dateStr to before current UTC and after current UTC. Got it – Ashok Goli Oct 27 '17 at 15:50