Set custom cache expiration time for a block When returning info for a custom block we can specify what kind of caching that will be used for the block according to the values in: hook_block_info().
Notice that if the block is cached the hook_block_view() will not be called at all.
In a module I'm developing I would like the user to be able to set the expiration time for the block cache, so I have tried something like this:

/**
 * Implements hook_block_info().
 **/
function CUSTOM_MODULE_block_info() {
  return array(
    'custom_block' =&gt; array(
      'info' =&gt; t('Custom Block'),
      'cache' =&gt; DRUPAL_NO_CACHE,
    ),
  );
}

/**
 * Implements hook_block_configure().
 **/ 
function CUSTOM_MODULE_block_configure($delta = '') {
  $form = array();
  $form['custom_module_cache_expire'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Cache expire'),
    '#default_value' =&gt; variable_get('custom_module_cache_expire', 0),
  );
  return $form;
}

/**
 * Implements hook_block_view().
 **/
function CUSTOM_MODULE_block_view($delta = '') {
  $block = array();
  if ($delta == 'custom_block') {
    $cache = &amp;drupal_static(__FUNCTION__);
    if (empty($cache)) {
      // Try to get data from cache.
      $cache = cache_get('custom_module');
      if (!empty($cache-&gt;data)) {
        // Check the expiration time.
        if (time() &gt; $cache-&gt;expire) {
          // Remove the cache.
          cache_clear_all('custom_module');
        }
        $block = $cache-&gt;data;
      }
      else {
        // Build the renderable array and cache the result for 5 minutes.
        // The 'custom_module_get_items()' is a long running task and
        // the reason why we want to cache this block at a certain interval.
        $block['content'] = array(
          '#items' =&gt; custom_module_get_items(),
        );
        cache_set('custom_block', $block, 'cache', time() + (60 * 5));
      }
    }
    else {
      $block = $cache-&gt;data;
    }
  }
  return $block;
}


The above almost works as expected, but I was wondering if there some better way of doing this.

In Drupal 8 we can use the cache max-age to achieve this behavior.

I also tried to set the cache in the renderable array for the block, but I'm not sure what this does actually:

$block['content'] = array(
  '#items' =&gt; custom_module_get_items(),
  '#cache' =&gt; array(
    'expire' =&gt; time() + (5 * 60),
  ),
);


Perhaps the best way would be to simply set the caching to DRUPAL_NO_CACHE for the block and then in custom_module_get_items() use cache_set() and cache_get()?

I was also thinking that another way of doing this might be to just remove the default block cache from the database at a specific interval?
There is a real live example of custom cache for drupal 7 in forums:

Asis in Core forum module:

    /**
     * Implements hook_block_view().
     *
     * Generates a block containing the currently active forum topics and the most
     * recently added forum topics.
     */

function forum_block_view($delta = '') {
  $query = db_select('forum_index', 'f')
    -&gt;fields('f')
    -&gt;addTag('node_access');
  switch ($delta) {
    case 'active':
      $title = t('Active forum topics');
      $query
        -&gt;orderBy('f.last_comment_timestamp', 'DESC')
        -&gt;range(0, variable_get('forum_block_num_active', '5'));
      break;

    case 'new':
      $title = t('New forum topics');
      $query
        -&gt;orderBy('f.created', 'DESC')
        -&gt;range(0, variable_get('forum_block_num_new', '5'));
      break;
  }

  $block['subject'] = $title;
  // Cache based on the altered query. Enables us to cache with node access enabled.
  $block['content'] = drupal_render_cache_by_query($query, 'forum_block_view');
  $block['content']['#access'] = user_access('access content');
  return $block;
}


Here drupal_render_cache_by_query does caching based on query result.


  Prepares an element for caching based on a query.
  
  This smart caching strategy saves Drupal from querying and rendering to HTML >when the underlying query is unchanged.
  
  Expensive queries should use the query builder to create the query and then >call this function. Executing the query and formatting results should happen in >a #pre_render callback.


As in quote query executing and rendering happens in hook_block_pre_render() as in forum.

Another Example:

$block['content'] = array(
  '#items' =&gt; custom_module_get_items(),
  '#cache' =&gt; array(
   'cid' =&gt; 'custom_module',
   'bin' =&gt; 'cache',
    'expire' =&gt; time() + (5 * 60),
  ),
);


The above code is similar to what you did with cache_get, cache_set methods in much similar terms with less code, as drupal_render() function handles this for you setting up cache using drupal_render_cache_set(). 

You can read more from here: ADVANCED CACHING WITH RENDERABLE CONTENT

As for cache policy when you are caching stuff with custom code in hook_block_info DRUPAL_CACHE_CUSTOM and DRUPAL_NO_CACHE has no difference. However, using DRUPAL_CACHE_CUSTOM for custom caching is better standard.

Check out Block Caching for drupal 7.