--- ./include/views/configuration.services.edit.php.orig	2015-03-12 10:25:15.000000000 +0100
+++ ./include/views/configuration.services.edit.php	2015-06-08 01:56:15.000000000 +0200
@@ -145,6 +145,16 @@
 			$from = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_from']);
 			$to = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_to']);
 			break;
+		case SERVICE_TIME_TYPE_PROBLEM_CORRECTION:
+			$type = new CSpan(_('Problem correction'), 'enabled');
+			$from = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_from']);
+			$to = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_to']);
+			break;
+		case SERVICE_TIME_TYPE_OK_CORRECTION:
+			$type = new CSpan(_('OK correction'), 'disabled');
+			$from = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_from']);
+			$to = zbx_date2str(_('d M Y H:i'), $serviceTime['ts_to']);
+			break;
 	}
 	$row = new CRow(array(
 		array(
@@ -169,7 +179,9 @@
 
 // create service time table
 $serviceTimeTable = new CTable(null, 'formElementTable');
-if ($this->data['new_service_time']['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME) {
+if ($this->data['new_service_time']['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME ||
+	$this->data['new_service_time']['type'] == SERVICE_TIME_TYPE_PROBLEM_CORRECTION ||
+	$this->data['new_service_time']['type'] == SERVICE_TIME_TYPE_OK_CORRECTION) {
 	// downtime since
 	if (isset($_REQUEST['new_service_time']['from'])) {
 		$fromYear = get_request('new_service_time_from_year');
@@ -257,6 +269,8 @@
 $timeTypeComboBox->addItem(SERVICE_TIME_TYPE_UPTIME, _('Uptime'));
 $timeTypeComboBox->addItem(SERVICE_TIME_TYPE_DOWNTIME, _('Downtime'));
 $timeTypeComboBox->addItem(SERVICE_TIME_TYPE_ONETIME_DOWNTIME, _('One-time downtime'));
+$timeTypeComboBox->addItem(SERVICE_TIME_TYPE_PROBLEM_CORRECTION, _('Problem correction'));
+$timeTypeComboBox->addItem(SERVICE_TIME_TYPE_OK_CORRECTION, _('OK correction'));
 $servicesTimeFormList->addRow(
 	_('New service time'),
 	new CDiv(array(
--- ./include/defines.inc.php.orig	2015-03-15 09:11:07.000000000 +0100
+++ ./include/defines.inc.php	2015-06-08 01:54:02.000000000 +0200
@@ -592,6 +592,8 @@
 define('SERVICE_TIME_TYPE_UPTIME',				0);
 define('SERVICE_TIME_TYPE_DOWNTIME',			1);
 define('SERVICE_TIME_TYPE_ONETIME_DOWNTIME',	2);
+define('SERVICE_TIME_TYPE_PROBLEM_CORRECTION',	3);
+define('SERVICE_TIME_TYPE_OK_CORRECTION',	4);
 
 define('USER_TYPE_ZABBIX_USER',		1);
 define('USER_TYPE_ZABBIX_ADMIN',	2);
--- ./include/services.inc.php.orig	2015-03-12 10:25:15.000000000 +0100
+++ ./include/services.inc.php	2015-06-08 02:05:34.000000000 +0200
@@ -479,14 +479,18 @@
 	$serviceTypes = array(
 		SERVICE_TIME_TYPE_DOWNTIME,
 		SERVICE_TIME_TYPE_ONETIME_DOWNTIME,
-		SERVICE_TIME_TYPE_UPTIME
+		SERVICE_TIME_TYPE_UPTIME,
+		SERVICE_TIME_TYPE_PROBLEM_CORRECTION,
+		SERVICE_TIME_TYPE_OK_CORRECTION
 	);
 	if (!isset($serviceTime['type']) || !in_array($serviceTime['type'], $serviceTypes)) {
 		throw new APIException(ZBX_API_ERROR_PARAMETERS, _('Incorrect service time type.'));
 	}
 
 	// one-time downtime validation
-	if ($serviceTime['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME) {
+	if ($serviceTime['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME ||
+		$serviceTime['type'] == SERVICE_TIME_TYPE_PROBLEM_CORRECTION ||
+		$serviceTime['type'] == SERVICE_TIME_TYPE_OK_CORRECTION) {
 		if (!isset($serviceTime['ts_from']) || !validateUnixTime($serviceTime['ts_from'])) {
 			throw new APIException(ZBX_API_ERROR_PARAMETERS, _('Incorrect service start time.'));
 		}
@@ -508,3 +512,57 @@
 		throw new APIException(ZBX_API_ERROR_PARAMETERS, _('Service start time must be less than end time.'));
 	}
 }
+
+function serviceType($type = null) {
+	$types = array(
+		SERVICE_TIME_TYPE_UPTIME => _('Uptime'),
+		SERVICE_TIME_TYPE_DOWNTIME => _('Downtime'),
+		SERVICE_TIME_TYPE_ONETIME_DOWNTIME => _('One-time downtime'),
+		SERVICE_TIME_TYPE_PROBLEM_CORRECTION => _('Problem correction'),
+		SERVICE_TIME_TYPE_OK_CORRECTION => _('OK correction')
+	);
+
+	if ($type === null) {
+		return $types;
+	}
+	elseif (isset($types[$type])) {
+		return $types[$type];
+	}
+	else {
+		return false;
+	}
+}
+
+function make_popup_servicetimes($serviceId, $timeIds) {
+	$config = select_config();
+
+	$table = new CTableInfo();
+	$table->setAttribute('style', 'width: 400px;');
+	$table->setHeader(array(_('Service time'), _('Interval'), _('Duration'), _('Note')));
+
+	$services = API::Service()->get(array(
+		'serviceids' => $serviceId,
+		'selectTimes' => API_OUTPUT_EXTEND,
+		'output' => API_OUTPUT_REFER,
+		'limit' => ZBX_WIDGET_ROWS
+	));
+
+	foreach ($services[0]['times'] as $time) {
+		if (!in_array($time['timeid'], $timeIds)) {
+			continue;
+		}
+
+		$from = zbx_date2str(_('d M Y H:i'), $time['ts_from']);
+		$to = zbx_date2str(_('d M Y H:i'), $time['ts_to']);
+		$duration = $time['ts_to'] - $time['ts_from'];
+
+		$table->addRow(array(
+			serviceType($time['type']),
+			$from . ' - ' . $to,
+			convert_units(array('value' => $duration, 'units' => 'uptime')),
+			$time['note']
+		));
+	}
+
+	return $table;
+}
--- ./api/classes/CService.php.orig	2015-03-12 10:25:29.000000000 +0100
+++ ./api/classes/CService.php	2015-06-08 01:54:02.000000000 +0200
@@ -626,7 +626,11 @@
 								'ok' => null,
 								'okTime' => null,
 								'problemTime' => null,
-								'downtimeTime' => null
+								'downtimeTime' => null,
+								'problemCorrection' => null,
+								'problemTimeIds' => null,
+								'okCorrection' => null,
+								'okTimeIds' => null
 							);
 						}
 
@@ -636,7 +640,11 @@
 							'sla' => $intervalSla['ok'],
 							'okTime' => $intervalSla['okTime'],
 							'problemTime' => $intervalSla['problemTime'],
-							'downtimeTime' => $intervalSla['downtimeTime']
+							'downtimeTime' => $intervalSla['downtimeTime'],
+							'problemCorrection' => $intervalSla['problemCorrection'],
+							'problemTimeIds' => $intervalSla['problemTimeIds'],
+							'okCorrection' => $intervalSla['okCorrection'],
+							'okTimeIds' => $intervalSla['okTimeIds']
 						);
 					}
 				}
@@ -778,21 +786,81 @@
 					$data[$time['ts_to']]['dt_e'] = 1;
 				}
 			}
+			elseif($time['type'] == SERVICE_TIME_TYPE_PROBLEM_CORRECTION && $time['ts_to'] >= $periodStart && $time['ts_from'] <= $periodEnd) {
+				if ($time['ts_from'] < $periodStart) {
+					$time['ts_from'] = $periodStart;
+				}
+				if ($time['ts_to'] > $periodEnd) {
+					$time['ts_to'] = $periodEnd;
+				}
+
+				if (isset($data[$time['ts_from']]['pc_s'])) {
+					$data[$time['ts_from']]['pc_s']++;
+				}
+				else {
+					$data[$time['ts_from']]['pc_s'] = 1;
+				}
+
+				if (isset($data[$time['ts_to']]['pc_e'])) {
+					$data[$time['ts_to']]['pc_e']++;
+				}
+				else {
+					$data[$time['ts_to']]['pc_e'] = 1;
+				}
+
+				$data['pcTimeIds'][] = $time['timeid'];
+			}
+			elseif($time['type'] == SERVICE_TIME_TYPE_OK_CORRECTION && $time['ts_to'] >= $periodStart && $time['ts_from'] <= $periodEnd) {
+				if ($time['ts_from'] < $periodStart) {
+					$time['ts_from'] = $periodStart;
+				}
+				if ($time['ts_to'] > $periodEnd) {
+					$time['ts_to'] = $periodEnd;
+				}
+
+				if (isset($data[$time['ts_from']]['oc_s'])) {
+					$data[$time['ts_from']]['oc_s']++;
+				}
+				else {
+					$data[$time['ts_from']]['oc_s'] = 1;
+				}
+
+				if (isset($data[$time['ts_to']]['oc_e'])) {
+					$data[$time['ts_to']]['oc_e']++;
+				}
+				else {
+					$data[$time['ts_to']]['oc_e'] = 1;
+				}
+
+				$data['ocTimeIds'][] = $time['timeid'];
+			}
 		}
 
 		if (!isset($data[$periodEnd])) {
 			$data[$periodEnd] = array();
 		}
 
+		if (!isset($data['pcTimeIds'])) {
+			$data['pcTimeIds'] = array();
+		}
+
+		if (!isset($data['ocTimeIds'])) {
+			$data['ocTimeIds'] = array();
+		}
+
 		// sort by time stamp
 		ksort($data);
 
 		// calculate times
 		$dtCnt = 0;
 		$utCnt = 0;
+		$pcCnt = 0;
+		$ocCnt = 0;
 		$slaTime = array(
 			'dt' => array('problemTime' => 0, 'okTime' => 0),
-			'ut' => array('problemTime' => 0, 'okTime' => 0)
+			'ut' => array('problemTime' => 0, 'okTime' => 0),
+			'pc' => array('problemTime' => 0, 'okTime' => 0),
+			'oc' => array('problemTime' => 0, 'okTime' => 0)
 		);
 		$prevTime = $periodStart;
 
@@ -808,6 +876,18 @@
 		if (isset($data[$periodStart]['dt_e'])) {
 			$dtCnt -= $data[$periodStart]['dt_e'];
 		}
+		if (isset($data[$periodStart]['pc_s'])) {
+			$pcCnt += $data[$periodStart]['pc_s'];
+		}
+		if (isset($data[$periodStart]['pc_e'])) {
+			$pcCnt -= $data[$periodStart]['pc_e'];
+		}
+		if (isset($data[$periodStart]['oc_s'])) {
+			$ocCnt += $data[$periodStart]['oc_s'];
+		}
+		if (isset($data[$periodStart]['oc_e'])) {
+			$ocCnt -= $data[$periodStart]['oc_e'];
+		}
 		foreach ($data as $ts => $val) {
 			// skip first data [already read]
 			if ($ts == $periodStart) {
@@ -817,6 +897,12 @@
 			if ($dtCnt > 0) {
 				$periodType = 'dt';
 			}
+			elseif ($pcCnt > 0) {
+				$periodType = 'pc';
+			}
+			elseif ($ocCnt > 0) {
+				$periodType = 'oc';
+			}
 			elseif ($utCnt > 0) {
 				$periodType = 'ut';
 			}
@@ -844,16 +930,36 @@
 			if (isset($val['dt_e'])) {
 				$dtCnt -= $val['dt_e'];
 			}
+			if (isset($val['pc_s'])) {
+				$pcCnt += $val['pc_s'];
+			}
+			if (isset($val['pc_e'])) {
+				$pcCnt -= $val['pc_e'];
+			}
 			if (isset($val['alarm'])) {
 				$prevAlarm = $val['alarm'];
 			}
+			if (isset($val['oc_s'])) {
+				$ocCnt += $val['oc_s'];
+			}
+			if (isset($val['oc_e'])) {
+				$ocCnt -= $val['oc_e'];
+			}
 
 			$prevTime = $ts;
 		}
 
 		$slaTime['problemTime'] = &$slaTime['ut']['problemTime'];
+		$slaTime['problemTime'] += $slaTime['oc']['problemTime'];
+		$slaTime['problemTime'] += $slaTime['oc']['okTime'];
 		$slaTime['okTime'] = &$slaTime['ut']['okTime'];
+		$slaTime['okTime'] += $slaTime['pc']['okTime'];
+		$slaTime['okTime'] += $slaTime['pc']['problemTime'];
 		$slaTime['downtimeTime'] = $slaTime['dt']['okTime'] + $slaTime['dt']['problemTime'];
+		$slaTime['problemCorrection'] = $slaTime['pc']['problemTime'];
+		$slaTime['problemTimeIds'] = $data['pcTimeIds'];
+		$slaTime['okCorrection'] = $slaTime['oc']['okTime'];
+		$slaTime['okTimeIds'] = $data['ocTimeIds'];
 
 		$fullTime = $slaTime['problemTime'] + $slaTime['okTime'];
 		if ($fullTime > 0) {
--- ./services.php.orig	2015-03-12 10:25:29.000000000 +0100
+++ ./services.php	2015-06-08 01:54:02.000000000 +0200
@@ -168,7 +168,9 @@
 		$_REQUEST['times'] = get_request('times', array());
 		$new_service_time['type'] = $_REQUEST['new_service_time']['type'];
 		$result = true;
-		if ($_REQUEST['new_service_time']['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME) {
+		if ($_REQUEST['new_service_time']['type'] == SERVICE_TIME_TYPE_ONETIME_DOWNTIME ||
+			$_REQUEST['new_service_time']['type'] == SERVICE_TIME_TYPE_PROBLEM_CORRECTION ||
+			$_REQUEST['new_service_time']['type'] == SERVICE_TIME_TYPE_OK_CORRECTION) {
 			if (!validateDateTime($_REQUEST['new_service_time_from_year'],
 					$_REQUEST['new_service_time_from_month'],
 					$_REQUEST['new_service_time_from_day'],
--- ./report3.php.orig	2015-03-12 10:25:16.000000000 +0100
+++ ./report3.php	2015-06-08 02:10:17.000000000 +0200
@@ -190,20 +190,56 @@
 $sla = reset($sla);
 
 foreach ($sla['sla'] as $intervalSla) {
-	$ok = new CSpan(
+	if (0 < $intervalSla['problemCorrection']) {
+		$problemCorrection = new CSpan(
+			sprintf(' (-%dd %dh %dm)',
+				$intervalSla['problemCorrection'] / SEC_PER_DAY,
+				($intervalSla['problemCorrection'] % SEC_PER_DAY) / SEC_PER_HOUR,
+				($intervalSla['problemCorrection'] % SEC_PER_HOUR) / SEC_PER_MIN
+			), 'orange'
+		);
+		$problemCorrection->setHint(
+			make_popup_servicetimes($service['serviceid'], $intervalSla['problemTimeIds'])
+		);
+	}
+	else {
+		$problemCorrection = null;
+	}
+
+	if (0 < $intervalSla['okCorrection']) {
+		$okCorrection = new CSpan(
+			sprintf(' (-%dd %dh %dm)',
+				$intervalSla['okCorrection'] / SEC_PER_DAY,
+				($intervalSla['okCorrection'] % SEC_PER_DAY) / SEC_PER_HOUR,
+				($intervalSla['okCorrection'] % SEC_PER_HOUR) / SEC_PER_MIN
+			), 'orange'
+		);
+		$okCorrection->setHint(
+			make_popup_servicetimes($service['serviceid'], $intervalSla['okTimeIds'])
+		);
+	}
+	else {
+		$okCorrection = null;
+	}
+
+	$ok = array(new CSpan(
 		sprintf('%dd %dh %dm',
 			$intervalSla['okTime'] / SEC_PER_DAY,
 			($intervalSla['okTime'] % SEC_PER_DAY) / SEC_PER_HOUR,
 			($intervalSla['okTime'] % SEC_PER_HOUR) / SEC_PER_MIN
 		), 'off'
+	),
+		$okCorrection
 	);
 
-	$problems = new CSpan(
+	$problems = array(new CSpan(
 		sprintf('%dd %dh %dm',
 			$intervalSla['problemTime'] / SEC_PER_DAY,
 			($intervalSla['problemTime'] % SEC_PER_DAY) / SEC_PER_HOUR,
 			($intervalSla['problemTime'] % SEC_PER_HOUR) /SEC_PER_MIN
 		), 'on'
+	),
+		$problemCorrection
 	);
 
 	$downtime = sprintf('%dd %dh %dm',
