How to rearrange a pool of posts joined using two queries?

This is how I would approach it:

Code

function my_pseudo_date_query( $where, $query ) {

    global $wpdb;

    $dq = $query->get('my_date_query');

    if( $dq && !empty( $dq['after'] ) ){

        $where .=  $wpdb->prepare( 
                      " AND {$wpdb->posts}.post_date >= %s"
                      $dq['after']
                   );
    }

    if( $dq && !empty( $dq['before'] ) ){

        $where .=  $wpdb->prepare( 
                     " AND {$wpdb->posts}.post_date <= %s",
                      $dq['before']
                   );
    }

    return $where;
}
add_filter( 'post_where', 'my_pseudo_date_query', 10, 2 );

Example usage:

$now = new DateTime( 'now' );
$first_of_last_month = new DateTime( 'first day of last month' );
$my_query = new WP_Query( array(
 'my_date_query' => array(
      'before' => $now->format( 'Y-m-d H:i:s' ),
      'after' => $first_of_last_month->format( 'Y-m-d H:i:s' ),
  );
 ) );

The before argument is redundant in this example.

Remarks

  1. This hasn’t been tested, it’s code ‘in principle’.
  2. I’ve been quite lazy here and the before and after keys of the my_date_query attribute are quite strict. They must be in the Y-m-d H:i:s (php) format. But it’s enough for this answer.
  3. As noted in the comments WordPress 3.7 will provide date_query as an argument. The above code is ‘forward compatible’ in the sense that once you’ve upgraded to 3.7, you can remove the my_ prefix from the example.
  4. The example assumes PHP5.3+. Though its fairly simple to workaround this limitation.
  5. If using with get_posts() don’t forget to set suppress_filters to false.