T_COMP Time Compare Not Matching in TIA Portal: Troubleshooting

David Krause10 min read
SiemensTIA PortalTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Problem: T_COMP Output Never Activates When Scheduled Times Match

Symptom reported on S7-300/S7-400 and S7-1500 controllers programmed with TIA Portal (commonly v12 through v20): a Boolean output driven by the result of T_COMP comparing two DATE_AND_TIME (DT) tags never turns ON, even though a real-time clock value equals the scheduled set-time value visible in the watch table.

A typical implementation uses two T_COMP instances:

  • Instance 1: T_COMP(IN1 := RealTime, IN2 := TimeToSet, OUT => SetBrand)
  • Instance 2: T_COMP(IN1 := RealTime, IN2 := TimeToReset, OUT => ResetBrand)

The boolean output SetBrand never asserts, so the scheduled brand (bit, marker, or coil) is never set, and the matching reset likewise never fires. The PLC does not report an error; the comparison result simply never evaluates as TRUE.

Field observation: This is one of the most common DATE_AND_TIME comparison mistakes in STEP 7 / TIA Portal. The instruction itself works correctly; the issue is the logical expectation that two sampled values will be bit-identical at the moment of evaluation.

Root Cause: Bit-Exact Equality on a Sampled Real-Time Clock

T_COMP returns TRUE only when the two input tags contain bit-identical values. The DT (DATE_AND_TIME) format encodes time down to 100 ms increments in the legacy S7-300/S7-400 format, but the wall-clock source — read from the CPU real-time clock via READ_CLK / RD_SYS_T / IEC timers — is sampled only at the OB1 scan boundary.

Two consequences follow:

  1. The pre-loaded scheduled value (e.g., D#2024-01-15-14:30:00.000) is static; the live real-time value increments every cycle.
  2. The OB1 cycle time (typically 5–50 ms for compact logic, up to 150 ms for complex FBD) determines the alignment window. The chance that the sampled RealTime tag equals the scheduled TimeToSet tag at the exact 100 ms boundary is roughly 1 in (cycle_time / 100 ms).

For a 10 ms OB1, the window is so narrow that T_COMP practically never returns TRUE. For a 100 ms OB1, the value may match once and then drift away before the user sees it in the watch table.

T_COMP Instruction Reference (S7-300/S7-400 and S7-1500)

The T_COMP instruction is documented in the Siemens TIA Portal "Extended Instructions" manual under "Date and Time".

Parameter Declaration Data Type Description
IN1 Input DATE, TIME, LTIME, TOD, DT, DTL, LDTL* First comparison value
IN2 Input Same as IN1 Second comparison value
OUT Return BOOL Result of the comparison (TRUE if equal)

* Allowed types depend on CPU family. S7-1500 supports DTL (DATE_AND_TIME_LONG, ns resolution). S7-300/400 typically uses DT (BCD-encoded, 100 ms resolution).

Official reference documentation:

Why a Direct Equality Test Is Wrong for Time-of-Day Scheduling

For scheduling actions at a specific wall-clock time, the correct semantic is "the current time has passed the scheduled time", not "the current time equals the scheduled time". T_COMP was designed for testing equality between two static DT values, not for edge detection on a free-running clock.

The recommended engineering pattern is one of the following:

  1. Difference + epsilon (window compare): Subtract the two times, take the absolute value, and compare against a tolerance (e.g., 10 ms for S7-1500 DTL, 100 ms for S7-300/400 DT).
  2. Greater-than-or-equal (level compare): Detect a falling or rising edge when RealTime >= TimeToSet while RealTime < TimeToSet + interval. This is the standard pattern for one-shot schedule events.
  3. Periodic interrupt (OB10 / OB1x): Move the comparison into a time-of-day OB that fires once per second or once per minute, removing scan-cycle jitter.

Solution 1: Difference with Epsilon Window (SCL)

Subtract the two values, take the absolute value, and compare against a tolerance. On S7-1500 use TIME or LTIME (millisecond / nanosecond resolution). On S7-300/400 the same code works with TIME (millisecond resolution only — DT resolution is 100 ms so any epsilon < 100 ms will miss).

// SCL — S7-1500 or S7-300/400
// Tags
// RealTime     : DTL       (S7-1500) or DT (S7-300/400), read from RD_SYS_T / READ_CLK
// TimeToSet    : DTL or DT, scheduled activation time
// TimeToReset  : DTL or DT, scheduled reset time
// Tolerance    : TIME      = T#10ms (S7-1500) or T#100ms (S7-300/400)
// SetBrand     : BOOL
// ResetBrand   : BOOL

#DiffSet   := ABS_TIME(TIME_DIFF(IN1 := #RealTime, IN2 := #TimeToSet));
#DiffReset := ABS_TIME(TIME_DIFF(IN1 := #RealTime, IN2 := #TimeToReset));

IF #DiffSet <= #Tolerance THEN
    #SetBrand := TRUE;
END_IF;

IF #DiffReset <= #Tolerance THEN
    #ResetBrand := TRUE;
END_IF;

On S7-1500, TIME_DIFF returns LTIME (ns) so a 10 ms tolerance is meaningful. On S7-300/400 use the standard library FC "FC_TIMEDIFF" or compute with DTL-to-TIME conversion.

Solution 2: Edge Detection on Crossing the Scheduled Time

The most robust scheduling pattern on a free-running clock. Use the previous scan's value to detect when the clock crosses the scheduled threshold.

// SCL — one-shot pulse when the clock crosses TimeToSet
// Tags
// RealTime      : DTL / DT
// RealTimePrev  : DTL / DT, latched from last cycle
// TimeToSet     : DTL / DT
// TimeToReset   : DTL / DT
// SetPulse      : BOOL   (TRUE for one cycle when crossing TimeToSet)
// ResetPulse    : BOOL   (TRUE for one cycle when crossing TimeToReset)

IF (#RealTimePrev < #TimeToSet) AND (#RealTime >= #TimeToSet) THEN
    #SetPulse := TRUE;
END_IF;

IF (#RealTimePrev < #TimeToReset) AND (#RealTime >= #TimeToReset) THEN
    #ResetPulse := TRUE;
END_IF;

#RealTimePrev := #RealTime;

This pattern is immune to scan-cycle jitter and to TIA Portal v12 / v15 / v16 / v17 / v18 / v19 / v20 differences. It fires exactly once per crossing.

Solution 3: Move the Comparison into a Time-of-Day OB

If the schedule resolution is in whole seconds or minutes, configure a Time-of-Day interrupt OB on the CPU:

  1. In the device configuration, enable Time-of-day interrupts and assign OB10.
  2. Set the start time and the period (e.g., every 60 s).
  3. In OB10, perform the comparison against the scheduled time. Because OB10 runs once per configured period, the comparison window is deterministic and T_COMP / greater-than-equal both work reliably.
  4. From OB10, set the brand flag; reset it from OB1 once the action is acknowledged.

Ladder / FBD Equivalent for Time Difference

If you must stay in LAD or FBD (no SCL compiler available on the target CPU), implement the same logic with the IEC standard arithmetic:

Network Operation Note
1 SUB_TIME / T_SUB: diff := RealTime - TimeToSet Sign matters; branch to ABS
2 ABS / ABS_TIME: |diff| S7-1500 only; for S7-300/400 use conditional swap
3 LE_TIME / <= DTL: |diff| <= Tolerance Drives SetBrand
4 Repeat for Reset with TimeToReset Drives ResetBrand

Compatible Data Types per CPU Family

CPU Time Data Type Resolution Recommended Tolerance T_COMP Returns TRUE?
S7-300 / S7-400 (DT) DATE_AND_TIME (DT) 100 ms (BCD-encoded seconds field) ≥ T#100ms (T#200ms recommended) Rarely — depends on OB1 alignment
S7-1500 (DTL) DTL (DATE_AND_TIME_LONG) 1 ns (nanosecond field) ≥ T#10ms for scheduling Essentially never for scheduled values
S7-1200 DTL 1 ms ≥ T#10ms Same caveat as S7-1500

Step-by-Step Procedure to Fix a T_COMP Time-Match Application

  1. Open the affected FB/FC in TIA Portal.
  2. Identify the two T_COMP instances driving SetBrand and ResetBrand.
  3. Replace T_COMP with a time-difference calculation: diff := abs(realTime - scheduledTime).
  4. Insert a constant Tolerance (TIME tag, default value T#10ms for S7-1500 or T#200ms for S7-300/400).
  5. Replace the equality test with diff <= Tolerance.
  6. If using LAD/FBD without SCL, use the SUB / ABS / LE instructions on TIME-tag operands. Note that S7-300/400 DT arithmetic requires conversion via the IEC library functions FC_TIMEDIFF or manual BCD subtraction.
  7. If you must keep the boolean equality semantic, drive the comparison from a Time-of-Day OB (OB10) instead of OB1.
  8. Compile and download to the CPU.

Verification Procedure

After applying the fix, confirm operation with the following checks:

  1. Add RealTime, TimeToSet, and DiffSet to a watch table with cycle-time monitoring enabled.
  2. Set TimeToSet to RealTime + 30s using the modify function (with watch table in non-productive mode during commissioning).
  3. Observe SetBrand asserting when the difference crosses into the tolerance window.
  4. Force RealTime from the watch table and step through several scheduled times to confirm one-shot behavior.
  5. If using OB10, confirm in the diagnostic buffer (Online > Diagnostics > Diagnostic buffer) that OB10 is being called at the configured period and not being aborted by higher-priority OBs.
  6. Run a 24-hour soak test with multiple scheduled events to verify no spurious matches and no missed events.

Troubleshooting Matrix

Symptom Likely Cause Fix
T_COMP output never TRUE despite matching watch table values Equality test against a sampled clock Switch to difference + epsilon or edge-detect
T_COMP output flickers for one cycle then drops Equality holds briefly during scan jitter Use >= edge detection; latch the pulse for one cycle
Compiler error: "T_COMP does not support operand type DTL" Old library version on S7-1500 Upgrade TIA Portal to v16 or later; reload the "Date and Time" extended instructions
Time difference shows as negative on S7-300/400 DT subtraction overflow at midnight Convert DT to TIME first, or wrap-around the comparison across midnight
SetBrand fires but ResetBrand never does OB1 cycle exceeds the scheduled reset interval Use a Time-of-Day OB or increase the tolerance to match the cycle time
SetBrand fires on every cycle once the time has passed No edge detection; comparison is now a level Add the previous-cycle latch as in Solution 2
OB10 never executes OB10 not configured or disabled by RUN-to-STOP transition Re-arm OB10 in OB100 / via SET_TINT and verify with diagnostic buffer

Edge Cases and Field-Proven Caveats

  • Day boundary: Comparing DT values across midnight produces an apparent "negative" difference because the underlying BCD encoding wraps. The standard remedy is to split the schedule into a date and a time-of-day and compare each component.
  • PLC clock drift: If the CPU is unsynchronized, the scheduled time may drift several seconds per day. Enable NTP or SIMATIC time-of-day synchronization via Siemens Industry Online Support knowledge base entry on time synchronization.
  • OB1 priority inversion: If OB1 is interrupted by a higher-priority OB (OB35 cyclic, OB82 diagnostic, OB121 error), the cycle can stretch. Use a tolerance greater than the worst-case OB1 cycle.
  • TIA Portal version differences: T_COMP behavior is consistent from TIA Portal v12 through v20 for both S7-300/400 and S7-1500. Differences appear only in supported operand types (S7-1500 gained LTIME / LDTL support in v16).
  • Watch-table sampling: Watch tables refresh at 500 ms by default; a transient match can be missed entirely in the watch table even though the PLC fired the output. Cross-check with a latch in the PLC rather than relying on watch-table observation alone.

FAQ

Why does T_COMP never return TRUE for matching scheduled times?

T_COMP performs bit-exact equality. The PLC real-time clock value is sampled once per OB1 cycle, so it almost never equals the scheduled static value at the exact instant of evaluation. Use a difference-with-tolerance comparison (e.g., |diff| ≤ T#10ms) or an edge-detect on RealTime crossing TimeToSet.

What tolerance should I use when comparing DTL or DT values?

On S7-1500 (DTL, ns resolution) use T#10ms or larger. On S7-300/400 (DT, 100 ms resolution) use T#200ms or larger. The tolerance must exceed the worst-case OB1 cycle time of your program.

Can I keep using T_COMP if I move the comparison into OB10?

Yes. OB10 fires once per configured period (typically 1 s, 10 s, or 60 s), so the comparison window is deterministic and T_COMP reliably returns TRUE when the values match. This is the cleanest pattern when you do not need sub-second scheduling precision.

Does T_COMP work on S7-1500 with DTL operands in TIA Portal v12?

The DTL data type was introduced with S7-1500 and TIA Portal v12 SP1. T_COMP supports DTL operands from that release onward. If you are on a pre-SP1 v12 install, upgrade to the latest service pack or use DT (DATE_AND_TIME) instead.

How do I detect a one-shot schedule event without missing it or firing it twice?

Latch the previous cycle's RealTime value and assert the pulse only when RealTimePrev < TimeToSet AND RealTime >= TimeToSet. This edge-detect pattern fires exactly once per crossing and is immune to scan-cycle jitter. Reset the latch from a separate network after the action is acknowledged.

Back to blog