Custom nested element and its child sub-elements callbacks
The whole workflow of form API is shown here  (source: https://www.drupal.org/node/165104). 

You can notice that #process is top-bottom whereas #after_build is bottom-top, and #element_validate is a whole another step and bottom-top. You can also see that #value_callback is called quite early (even before #process).

Thus, and by experience, your #value_callback should not be more than 15 lines long, and in the case of a nested element, always take form_type_checkboxes_value or form_type_radios_value as examples: they only care about edge cases and rarely modify values.

This said, another input to take into consideration is the timeperiod module, because your way of handling will depend entirely of this module. (source: http://cgit.drupalcode.org/timeperiod/tree/timeperiod.module)

/**
 * Implements hook_element_info().
 */
function timeperiod_element_info() {
  // A duration form element which represents the duration in seconds.
  $types['timeperiod_select'] = array(
    '#input' =&gt; TRUE,
    '#tree' =&gt; TRUE,
    '#default_value' =&gt; 0,
    '#value_callback' =&gt; 'timeperiod_element_value',
    '#process' =&gt; array('timeperiod_element_process', 'ajax_process_form'),
    '#after_build' =&gt; array('timeperiod_element_after_build'),
    '#pre_render' =&gt; array('form_pre_render_conditional_form_element'),
    // Controls the available units. Array keys are the units, see
    // timeperiod_element_units(). The values control the number of available
    // values per unit, taking steps in the configured size starting from 0.
    '#units' =&gt; array(
      '3600' =&gt; array('max' =&gt; 23, 'step size' =&gt; 1),
      '60' =&gt; array('max' =&gt; 55, 'step size' =&gt; 5),
    ),
  );
  return $types;
}



timeperiod_element_value() does literally nothing (see its comment)
timeperiod_element_process() breaks down into units and sets up sub-elements 
timeperiod_element_after_build() actually sets the
value


So based on these informations, you also need to implement #after_build, which is bottom-up, so it will run after timeperiod, and set the value using form_set_value()

Remember that validation is only for validation, and will always have processed values as input.