diff --git a/timefield.module b/timefield.module
index cfd8273..0c2bc74 100644
--- a/timefield.module
+++ b/timefield.module
@@ -554,51 +554,9 @@ function timefield_time_validate($element, &$form_state, $form) {
 
     $values = $field_value[$field_name][$element['#language']][$delta];
 
-    $new_values = array();
-
-    // If empty, set to null.
-    if (strlen($values['value']) == 0) {
-      if ($field && isset($field['#required']) && $field['#required']) {
-        form_error($element['value'], t('!name field is required.', array('!name' => $element['#title'])));
-      }
-      form_set_value($element, array('value' => NULL), $form_state);
-      return;
-    }
-    $date_value = date_parse($values['value']);
-    if ($date_value['error_count']) {
-      form_error($element['value'], t('The time is not in a format that I understand.'));
-    }
-    else {
-      $parsed_value = timefield_time_to_integer($values['value']);
-      $new_values['value'] = $parsed_value;
-    }
-
-    if (!empty($values['value2'])) {
-      $date_value2 = date_parse($values['value2']);
-      if ($date_value2['error_count']) {
-        form_error($element['value2'], t('The to time is not in a format that I understand.'));
-      }
-      else {
-        $parsed_value = timefield_time_to_integer($values['value2']);
-        if ($values['value'] > $parsed_value || $parsed_value == 0) {
-          $parsed_value += 86400;
-        }
-        $new_values['value2'] = $parsed_value;
-      }
-    }
-
-    if (!empty($values['days'])) {
-      foreach ($values['days'] as $index => $day) {
-        $new_values[$index] = ($day === 0) ? $day : 1;
-      }
-    }
-    if (!empty($values['label'])) {
-      $new_values['label'] = isset($values['label']) ? $values['label'] : '';
-    }
-
-    form_set_value($element, $new_values, $form_state);
-
+    $required = $field && isset($field['#required']) && $field['#required'];
 
+    _timefield_element_validate($values, $element, $form_state, $required);
   }
 }
 
@@ -763,68 +721,86 @@ function timefield_field_widget_form(&$form, &$form_state, $field, $instance, $l
         '#element_validate' => array('timefield_time_validate'),
       );
 
-      if (!$instance_settings['disable_plugin']) {
-        $js_settings = _timefield_js_settings($instance_class, $instance_settings['input_format']);
-
-        $element['#attached'] = array(
-          'library' => array(array('timefield', 'timepicker')),
-          'js' =>  array(
-            drupal_get_path('module', 'timefield') . '/js/timefield.js',
-            array(
-              'data' => array('timefield' => $js_settings),
-              'type' => 'setting',
-            )
-          ),
-        );
-      }
+      $element += _timefield_element_process(
+        $value,
+        isset($value2) ? $value2 : '',
+        $instance_settings['disable_plugin'],
+        $instance_settings['input_format'],
+        isset($items[$delta]['label']) ? $items[$delta]['label'] : '',
+        $instance_class,
+        $settings['weekly_summary'],
+        $settings['weekly_summary_with_label'],
+        $settings['totime'],
+        isset($days) ? $days : array()
+      );
 
-      if ($settings['weekly_summary_with_label']) {
-        $element['label'] = array(
-          '#title' => t('Label'),
-          '#description' => t('Enter a label for the summary'),
-          '#type' => 'textfield',
-          '#default_value' => isset($items[$delta]['label']) ? $items[$delta]['label'] : '',
-          '#size' => 40,
-          '#maxlength' => 60,
-        );
-      }
+      break;
+  }
+  return $element;
+}
 
-      $element['value'] = array(
-        '#title' => t('Time'),
-        '#description' => t('Enter a time value, in any format'),
-        '#type' => 'textfield',
-        '#default_value' => _timefield_map_input_format_to_display_format($value, $instance_settings['input_format']),
-        '#size' => 15,
-        '#maxlength' => 15,
-        '#attributes' => array('class' => array('edit-timefield-timepicker', $instance_class)),
-      );
+function _timefield_element_process($value, $value2, $disable_plugin, $input_format, $label, $class, $weekly_summary, $weekly_summary_with_label, $totime, $days) {
 
-      // Add second element if totime is required or optional.
-      if ($settings['totime'] == 'required' || $settings['totime'] == 'optional') {
-        $element['value2'] = array(
-          '#title' => t('End Time'),
-          '#description' => t('Enter a time value, in any format'),
-          '#type' => 'textfield',
-          '#default_value' => _timefield_map_input_format_to_display_format($value2, $instance_settings['input_format']),
-          '#size' => 15,
-          '#maxlength' => 15,
-          '#attributes' => array('class' => array('edit-timefield-timepicker', $instance_class)),
-        );
-      }
+  if (!$disable_plugin) {
+    $js_settings = _timefield_js_settings($class, $input_format);
 
-      if ($settings['weekly_summary'] || $settings['weekly_summary_with_label']) {
-        $element['days'] = array(
-          '#title' => t('Days'),
-          '#description' => t('Select the days this schedule applies to'),
-          '#type' => 'checkboxes',
-          '#options' => _timefield_weekly_summary_days(),
-          '#default_value' => $days,
-          '#attributes' => array('class' => array('edit-field-timefield-days')),
-        );
-      }
+    $element['#attached'] = array(
+      'library' => array(array('timefield', 'timepicker')),
+      'js' =>  array(
+        drupal_get_path('module', 'timefield') . '/js/timefield.js',
+        array(
+          'data' => array('timefield' => $js_settings),
+          'type' => 'setting',
+        )
+      ),
+    );
+  }
 
-      break;
+  if ($weekly_summary_with_label) {
+    $element['label'] = array(
+      '#title' => t('Label'),
+      '#description' => t('Enter a label for the summary'),
+      '#type' => 'textfield',
+      '#default_value' => $label,
+      '#size' => 40,
+      '#maxlength' => 60,
+    );
   }
+
+  $element['value'] = array(
+    '#title' => t('Time'),
+    '#description' => t('Enter a time value, in any format'),
+    '#type' => 'textfield',
+    '#default_value' => _timefield_map_input_format_to_display_format($value, $input_format),
+    '#size' => 15,
+    '#maxlength' => 15,
+    '#attributes' => array('class' => array('edit-timefield-timepicker', $class)),
+  );
+
+  // Add second element if totime is required or optional.
+  if ($totime == 'required' || $totime == 'optional') {
+    $element['value2'] = array(
+      '#title' => t('End Time'),
+      '#description' => t('Enter a time value, in any format'),
+      '#type' => 'textfield',
+      '#default_value' => _timefield_map_input_format_to_display_format($value2, $input_format),
+      '#size' => 15,
+      '#maxlength' => 15,
+      '#attributes' => array('class' => array('edit-timefield-timepicker', $class)),
+    );
+  }
+
+  if ($weekly_summary || $weekly_summary_with_label) {
+    $element['days'] = array(
+      '#title' => t('Days'),
+      '#description' => t('Select the days this schedule applies to'),
+      '#type' => 'checkboxes',
+      '#options' => _timefield_weekly_summary_days(),
+      '#default_value' => $days,
+      '#attributes' => array('class' => array('edit-field-timefield-days')),
+    );
+  }
+
   return $element;
 }
 
@@ -863,6 +839,153 @@ function timefield_field_load($entity_type, $entities, $field, $instances, $lang
 }
 
 /**
+ * Implements hook_element_info().
+ */
+function timefield_element_info() {
+  $type['timefield'] = array(
+    '#input' => TRUE,
+    '#process' => array('timefield_element_process'),
+    '#title' => 'Time',
+    // Form element settings
+    '#totime' => '',
+    '#weekly_summary' => FALSE,
+    '#weekly_summary_with_label' => FALSE,
+    '#disable_plugin' => FALSE,
+    '#input_format' => array(
+      'separator' => ':',
+      'showLeadingZero' => FALSE,
+      'showMinutesLeadingZero' => TRUE,
+      'showPeriod' => TRUE,
+      'periodSeparator' => '',
+      'showHours' => TRUE,
+      'showMinutes' => TRUE,
+      'am_text' => 'AM',
+      'pm_text' => 'PM',
+      'minute_interval' => 5,
+      'showCloseButton' => FALSE,
+      'closeButtonText' => 'Done',
+      'showNowButton' => FALSE,
+      'nowButtonText' => 'Now',
+      'showDeselectButton' => FALSE,
+      'deselectButtonText' => 'Deselect',
+      'myPosition' => 'left top',
+      'atPosition' => 'left bottom',
+    ),
+    '#display_format' => array(
+      'hour' => 'g',
+      'minute' => 'i',
+      'period' => 'a',
+      'period_separator' => '',
+      'separator' => ':',
+    ),
+    '#days' => array(
+      'mon' => t('Monday'),
+      'tue' => t('Tuesday'),
+      'wed' => t('Wednesday'),
+      'thu' => t('Thursday'),
+      'fri' => t('Friday'),
+      'sat' => t('Saturday'),
+      'sun' => t('Sunday'),
+    ),
+    '#value' => time(),
+    '#value2' => time(),
+  );
+  return $type;
+}
+
+/**
+ * Element validation function
+ */
+function timefield_form_validate($element, &$form_state, $form) {
+  $values = $form_state['values'];
+  $required = isset($element['#required']) && $element['#required'];
+
+  _timefield_element_validate($values, $element, $form_state, $required);
+}
+
+function _timefield_element_validate($values, $element, &$form_state, $required) {
+  $new_values = array();
+
+  // If empty, set to null.
+  if (strlen($values['value']) == 0) {
+    if ($required) {
+      form_error($element['value'], t('!name field is required.', array('!name' => $element['#title'])));
+    }
+    form_set_value($element, array('value' => NULL), $form_state);
+    return;
+  }
+  $date_value = date_parse($values['value']);
+  if ($date_value['error_count']) {
+    form_error($element['value'], t('The time is not in a format that I understand.'));
+  }
+  else {
+    $parsed_value = timefield_time_to_integer($values['value']);
+    $new_values['value'] = $parsed_value;
+  }
+
+  if (!empty($values['value2'])) {
+    $date_value2 = date_parse($values['value2']);
+    if ($date_value2['error_count']) {
+      form_error($element['value2'], t('The to time is not in a format that I understand.'));
+    }
+    else {
+      $parsed_value = timefield_time_to_integer($values['value2']);
+      if ($values['value'] > $parsed_value || $parsed_value == 0) {
+        $parsed_value += 86400;
+      }
+      $new_values['value2'] = $parsed_value;
+    }
+  }
+
+  if (!empty($values['days'])) {
+    foreach ($values['days'] as $index => $day) {
+      $new_values[$index] = ($day === 0) ? $day : 1;
+    }
+  }
+  if (!empty($values['label'])) {
+    $new_values['label'] = isset($values['label']) ? $values['label'] : '';
+  }
+
+  form_set_value($element, $new_values, $form_state);
+}
+
+/**
+ * Timefield process function.
+ */
+function timefield_element_process($element, &$form_state, $form) {
+  $element += array(
+    '#type' => 'fieldset',
+    '#element_validate' => array('timefield_form_validate'),
+  );
+  $class = str_replace('_', '-', $element['#name']);
+
+  $value = isset($element['#value']) ? timefield_integer_to_time($element['#display_format'], $element['#value']) : '';
+
+  if ($element['#totime'] == 'required' || $element['#totime'] == 'optional') {
+    $value2 = isset($element['#value2']) ? timefield_integer_to_time($element['#display_format'], $element['#value2']) : '';
+  }
+
+  if ($element['#weekly_summary'] || $element['#weekly_summary_with_label']) {
+    $days = isset($element['#days']['mon']) ? _timefield_weekly_summary_days_map($element['#days']) : array();
+  }
+
+  $element += _timefield_element_process(
+    $value,
+    isset($value2) ? $value2 : '',
+    $element['#disable_plugin'],
+    $element['#input_format'],
+    $element['#title'],
+    $class,
+    $element['#weekly_summary'],
+    $element['#weekly_summary_with_label'],
+    $element['#totime'],
+    isset($days) ? $days : array()
+  );
+
+  return $element;
+}
+
+/**
  * Preprocess function for the timefield formatter.
  */
 function template_preprocess_timefield_formatter(&$variables) {
@@ -884,7 +1007,7 @@ function template_preprocess_timefield_formatter(&$variables) {
           $days[$day] = $day_text;
         }
       }
-      if ($days) {
+      if (isset($days) && !empty($days)) {
         $variables['time']['days'] = $days;
         $variables['time']['time'] = implode(', ', $days) . ' ' . $variables['time']['time'];
       }
