1
\$\begingroup\$

I despise playing with dates in PHP so no doubt the below is too convoluted for what is needed. What I am looking for is a general tidy/reduction.

Everything but the wednesday and friday arrays are in a loop. The loop is from a ROQL statement. Oracle SQL for it's RightNow product, which is a very very stripped down version of MySQL from what I understand, meaning we are limited to basic SELECT statements i.e. we can't do anything worthwhile there.

  1. $inc['order_date'] is a string representing a date in the format yyyymmdd
  2. $inc['order_dispatch_date'] is a string representing a date in the format yyyymmdd
  3. $inc['order_address'] is a string representing an address

So the basics of the code is:

  1. Loop through each row in the database
  2. Convert some dates
  3. If the order address in the database is in the wednesday array, set the collection date to the Thursday after
  4. If the order address in the database is in the friday array, set the collection date to the Saturday after
  5. Do some more date conversion/manipulation
  6. END GOAL: Get the difference in days between the order_date and the collection_date

CODE

$wednesday = array("Paris","London","New York");
$friday = array("Munich", "Cardiff", "Sydney"); 

$res = RNCPHP\ROQL::query( "SQL QUERY HERE")->next();
while($inc = $res->next()) {        

    $order_date = DateTime::createFromFormat('Ymd', $inc['order_date']);
    $order_date = $order_date->format('Ymd');

    $order_dispatch_date = DateTime::createFromFormat('Ymd', $inc['order_dispatch_date']);
    $order_dispatch_date = $order_dispatch_date->format('Ymd');

    if (in_array($inc['order_address'], $wednesday)) {
        $order_collection = date('Ymd', strtotime('next thursday', strtotime($order_dispatch_date)));
    }
    if (in_array($inc['order_address'], $friday)) {
        $order_collection = date('Ymd', strtotime('next saturday', strtotime($order_dispatch_date)));
    }

    $order_collection = new DateTime($order_collection); 
    $order_date   = new DateTime($order_date);

    $interval = $order_date->diff($order_collection);
    $interval = $interval->d;
}

FIRST REVISION

if (in_array($inc['order_address'], $wednesday)) {
    $order_collection = new DateTime(date('Ymd', strtotime('next thursday', strtotime($inc['order_dispatch_date']))));
}
if (in_array($inc['order_address'], $friday)) {
    $order_collection = new DateTime(date('Ymd', strtotime('next saturday', strtotime($inc['order_dispatch_date']))));
}

$order_date = new DateTime(date('Ymd', strtotime($inc['order_date'])));
$interval = $order_date->diff($order_collection)->d;
\$\endgroup\$
10
  • \$\begingroup\$ I think maybe I am misunderstanding your task. If the order falls on a Wednesday or a Friday, you want to the customer to pick it up 8 days later. Isn't the diff always going to be 8 days if found in either array? It seems you could skip some of these processes as soon as you know an order exists in one of the day arrays. What is the default collection time for all other days? next day? or is it variable? \$\endgroup\$ – mickmackusa Nov 29 '17 at 23:07
  • \$\begingroup\$ Can we see a sample input array? and the expected result? Seeing the loop structure may be helpful too. \$\endgroup\$ – mickmackusa Nov 29 '17 at 23:28
  • \$\begingroup\$ @mickmackusa it's based on dispatch date -so if it's dispatched on a Wednesday for a Wednesday collection, it will be picked up on the following Thursday which is +1 day. Loop structure added but it won't add much \$\endgroup\$ – pee2pee Nov 30 '17 at 9:58
  • \$\begingroup\$ Good. I just wanted to see that the arrays were declared outside of the loop. Double quote F. \$\endgroup\$ – mickmackusa Nov 30 '17 at 10:14
  • \$\begingroup\$ Where is the $order_collection declaration for non-Wed/Fri rows? \$\endgroup\$ – mickmackusa Nov 30 '17 at 10:19
2
\$\begingroup\$

I'll provide a snippet with some sample data to demonstrate a few of my suggested techniques.

Code: (Demo)

$incs=[
    ['order_date'=>'20171128','order_dispatch_date'=>'20171129','order_address'=>'Paris'],
    ['order_date'=>'20171128','order_dispatch_date'=>'20171129','order_address'=>'Munich'],
    ['order_date'=>'20171129','order_dispatch_date'=>'20171130','order_address'=>'London'],
    ['order_date'=>'20171129','order_dispatch_date'=>'20171130','order_address'=>'Cardiff'],
    ['order_date'=>'20171130','order_dispatch_date'=>'20171201','order_address'=>'New York'],
    ['order_date'=>'20171130','order_dispatch_date'=>'20171201','order_address'=>'Sydney']
];

$wednesday = array("Paris","London","New York");

foreach($incs as $inc){
    $order_date = DateTime::createFromFormat('Ymdhis', $inc['order_date'].'000000');
    $day_name = in_array($inc['order_address'], $wednesday) ? 'Thursday' : 'Saturday';
    $order_collection = new DateTime($adj_date=date('Y-m-d 00:00:00', strtotime("next $day_name {$inc['order_dispatch_date']}")));

    $interval = $order_date->diff($order_collection)->d;
    echo "\n{$inc['order_date']} - $adj_date = $interval";
}

Output:

20171128 - 2017-11-30 00:00:00 = 2
20171128 - 2017-12-02 00:00:00 = 4
20171129 - 2017-12-07 00:00:00 = 8
20171129 - 2017-12-02 00:00:00 = 3
20171130 - 2017-12-07 00:00:00 = 7
20171130 - 2017-12-02 00:00:00 = 2

Now for the fine points:

  • Because you state that every order_address is in the $wednesday or $friday array, then you should only be checking one of them for best efficiency. This check will determine the day name that will be fed to strtotime() later.
  • When generating your DateTime objects, assign them zero-ed times. This way php will not default them to the "current time" for the given date. Performing this declaration will avoid getting deviations in the diff() value later.
  • strtotime() will correctly interpret your Ymd format, so no additional string preparation is necessary.
  • The syntax for your strtotime() call is a single parameter with next $day_nameand$inc['order_dispatch_date']` all in a single string.
  • You can sensibly save a line of code by chaining ->d to your $interval declaration.

Here is how I think your new code should look:

$wednesday = array("Paris","London","New York");

$res = RNCPHP\ROQL::query( "SQL QUERY HERE")->next();
while($inc = $res->next()) {        

    $order_date = DateTime::createFromFormat('Ymdhis', $inc['order_date'].'000000');
    $day_name = in_array($inc['order_address'], $wednesday) ? 'Thursday' : 'Saturday';
    $order_collection = new DateTime(date('Y-m-d 00:00:00', strtotime("next $day_name {$inc['order_dispatch_date']}")));

    $interval = $order_date->diff($order_collection)->d;
}
\$\endgroup\$
1
  • \$\begingroup\$ @pee2pee I have updated my answer using the new details that you have provided. \$\endgroup\$ – mickmackusa Dec 1 '17 at 15:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.