4

I am given timestamps formatted like this:

Mon Jul 28 11:39:29 GMT-05:00 2014
Mon Jul 28 13:39:29 GMT+02:00 2014
Thu Jul 17 00:02:02 UTC 2014
Fri Jul 18 14:47:01 UTC 2014

I need to add X minutes to that and return true/false if the result is in the future. The trick is the timestamps can be in any timezone, and timezone might be expressed as UTC or GMT (see above examples).

Here is the code I wrote so far, but I do not know how to continue:

function isFuture($dateTimeStr, $minToAdd) {    
  $date1 = DateTime::createFromFormat("D M d H:i:s P Y", $dateTimeStr);

  // Something like $date1->date_interval_create_from_date_string('30 minutes);
  $date1->add(date_interval_create_from_date_string($minToAdd . ' minutes'));

  $now = new DateTime("now");
  return $date1 > $now;
}

echo isFuture("Mon Jul 28 14:39:29 GMT-05:00 2014", 30) ? "Future" : "Past";
echo isFuture("Fri Jul 18 14:47:01 UTC 2014", 30) ? "Future" : "Past";

Answering my own question:

function isFuture($dateTimeStr, $minToAdd) {    
  $t = strtotime($dateTimeStr) + ($minToAdd*60);
  return $t > time();
}
Pepster K.
  • 339
  • 2
  • 5
  • 17

2 Answers2

2

Just use DateTime::getTimezone() to get the working timezone of $date1 and use it for your $now DateTime object:

function isFuture($dateTimeStr, $minToAdd) {    
  $date1 = DateTime::createFromFormat("D M d H:i:s P Y", $dateTimeStr);

  // Something like $date1->date_interval_create_from_date_string('30 minutes);
  $date1->add(date_interval_create_from_date_string($minToAdd . ' minutes'));

  $now = new DateTime("now", new DateTimeZone($date1->getTimezone()));
  return $date1 > $now;
}

This will then work with any time zone. But if the time zone will always be GMT/UTC you can just hard code it into your function:

$now = new DateTime("now", new DateTimeZone('GMT'));
John Conde
  • 217,595
  • 99
  • 455
  • 496
  • That doesn't provide correct results, even after correcting the one error you had:`function isFuture($dateTimeStr, $minToAdd) { $date1 = DateTime::createFromFormat("D M d H:i:s P Y", $dateTimeStr); // Something like $date1->date_interval_create_from_date_string('30 minutes); $date1->add(date_interval_create_from_date_string($minToAdd . ' minutes')); $now = new DateTime("now", $date1->getTimezone()); return $date1 > $now; } echo isFuture("Mon Jul 28 14:39:29 GMT-12:00 2014", 30) ? "Future" : "Past";` – Pepster K. Jul 28 '14 at 20:02
  • Can you elaborate? Kinda hard to improve the answer without knowing how it doesn't work. – John Conde Jul 28 '14 at 20:03
  • I apologize for the formatting problem. I'm still learning stackoverflow syntax; looks like marking something as code in a comment is different than marking it as code in an original post. When I mean it doesn't provide correct results: some timestamps which are in the past are reported as being in the future. The one I gave at the end is an example: Mon Jul 28 14:39:29 GMT-12:00 2014 – Pepster K. Jul 28 '14 at 20:11
  • No worries. At a glance I see you're missing the `new DateTimeZone()` part when setting today's date. See if correcting that fixes your issue. – John Conde Jul 28 '14 at 20:18
  • Well, that's the error I mentioned. The original code you posted `$now = new DateTime("now", new DateTimeZone($date1->getTimezone()))` gives this error: `DateTimeZone::__construct() expects parameter 1 to be string, object given`. That's why I changed it to `$now = new DateTime("now", $date1->getTimezone())` – Pepster K. Jul 28 '14 at 20:23
  • That date you provide is actually not in the past. That's why you get that result. – John Conde Jul 29 '14 at 00:40
0

java.time

Both the troublesome old date-time classes from the earliest versions of Java and the Joda-Time library are now legacy, supplanted by the java.time classes.

Formatting pattern

The formatting pattern codes of DateTimeFormatter are similar to the legacy SimpleDateFormat class, but not identical. Study the JavaDoc.

OffsetDateTime

The GMT-05:00 type of items is an offset-from-UTC so we process as an OffsetDateTime. You could parse as a ZonedDateTime for the simplicity of mixing these objects with those resulting from the other inputs, but it would be misleading to people reading your code.

ZonedDateTime

The UTC is actually the name of a time zone, so we process as a ZonedDateTime.

To be clear, GMT and UTC are practically the same thing in terms of conventional business apps. But the usage here is different. The plus or minus numbers indicate an offset-from-UTC but not a full time zone. The UTC text alone is a zone name, a particular zone that happens to be an offset of zero, but kind of string could just as well have a zone name of America/Montreal or Europe/Paris.

Classes for different ways to view a moment:

  • The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
  • An OffsetDateTime is like an Instant, but assigned an offset-from-UTC (a number of hours, minutes, and seconds adjusted in its wall-clock time).
  • A ZonedDateTime is like an Instant but assigned a time zone. A time zone is a collection of a region’s past, present, and future offsets.

Example code

List<CharSequence> inputs = new ArrayList<> ( 4 );

inputs.add ( "Mon Jul 28 11:39:29 GMT-05:00 2014" );
inputs.add ( "Mon Jul 28 13:39:29 GMT+02:00 2014" );
inputs.add ( "Thu Jul 17 00:02:02 UTC 2014" );
inputs.add ( "Fri Jul 18 14:47:01 UTC 2014" );
inputs.add ( "garbage-in garbaage-out" );
inputs.add ( "Fri Jan 23 12:34:56 UTC 2099" );  // Future.

Instant now = Instant.now ();  // Capture the current moment in UTC.

DateTimeFormatter fGMT = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss OOOO uuuu" );
DateTimeFormatter fUTC = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu" );

for ( CharSequence input : inputs ) {
    if ( input.length () == "Mon Jul 28 11:39:29 GMT-05:00 2014".length () ) {
        OffsetDateTime odt = OffsetDateTime.parse ( input , fGMT );
        if ( odt.toInstant ().isAfter ( now ) ) {
            System.out.println ( "input: " + input + " is future." );
        } else {
            System.out.println ( "input: " + input + " is past or present." );
        }
    } else if ( input.length () == "Thu Jul 17 00:02:02 UTC 2014".length () ) {
        ZonedDateTime zdt = ZonedDateTime.parse ( input , fUTC );
        if ( zdt.toInstant ().isAfter ( now ) ) {
            System.out.println ( "input: " + input + " is future." );
        } else {
            System.out.println ( "input: " + input + " is past or present." );
        }
    } else {
        System.err.println ( "ERROR - Unexpected input: " + input );
    }
}

input: Mon Jul 28 11:39:29 GMT-05:00 2014 is past or present.

input: Mon Jul 28 13:39:29 GMT+02:00 2014 is past or present.

input: Thu Jul 17 00:02:02 UTC 2014 is past or present.

input: Fri Jul 18 14:47:01 UTC 2014 is past or present.

input: Fri Jan 23 12:34:56 UTC 2099 is future.

See this code run live at IdeOne.com.

Date-time math

Adding time seems like a distraction from the core issues of your Question. So I ignored that topic in example above.

But simple enough to do. The classes above have plus… and minus… methods for adding or subtracting an number of hours, minutes, etc.

OffsetDateTime odtLater = odt.plusHours( 1 );
ZonedDateTime zdtLater = zdt.plusMinutes( 90 );

You can define a chunk of time as a Duration.

Duration d = Duration.ofMinutes( 90 ) ;
ZonedDateTime zdtLater = zdt.plus( d );

The java.time classes use immutable objects. So the result of a manipulation is a fresh object with values based on the original.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

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