Overview
WinCC TagLogging (and Alarm Logging) persist every archive value with a UTC timestamp, independent of the operator station's local time zone and independent of daylight saving time. WinCC's standard controls — OnlineTrendControl, OnlineTableControl, AlarmControl, UserArchiveControl — perform the UTC→local conversion internally so the operator always sees the configured local time. The moment you bypass those controls and read the archive tables directly with T-SQL, OLE DB, ADO.NET, the WinCC ODK, or the Connectivity Pack, you receive raw UTC timestamps. If your local clock is GMT+1 with summer time active (CEST = UTC+2), every row appears 2 hours early; if your local clock is EST (UTC-5), every row appears 5 hours late. This is expected behavior, not a bug, and the conversion is the caller's responsibility.
Root Cause: Why WinCC Stores Timestamps in UTC
The archive engine writes the TimeStamp column (in TagUncompressed, TagCompressed, and the analogous alarm tables) using the system UTC clock. Three engineering reasons drive this decision:
- Cross-site consistency. Distributed WinCC stations and WinCC/Server–WinCC/Client topologies can span time zones. UTC keeps every station writing the same canonical instant, which makes redundant archives comparable.
- DST ambiguity. Local time loses uniqueness during the autumn "fall-back" hour (02:00–03:00 in Europe, 01:00–02:00 in the US). UTC eliminates the duplicate-hour problem entirely.
-
Database portability. Plain
datetimein SQL Server is a monotonic absolute instant. UTC lets you replicate, back up, and query the database on a server whose OS clock is in a different time zone without remapping rows.
Siemens documents this behavior in the WinCC Information System under the TagLogging → Data Storage and Time Stamp topics, and in the public support FAQ entries Entry ID 17811102, Entry ID 23067556, and Entry ID 23542699.
Affected Versions, Components, and Data Sources
| WinCC Product | Version Tested | Archive Engine | UTC Behavior |
|---|---|---|---|
| WinCC V6 (Classic) | V6.0 SP4 through V6.2 | MS SQL Server 2000/2005 | UTC, no DST |
| WinCC V7 | V7.0, V7.2, V7.3, V7.4 SP1 | MS SQL Server 2005–2014 | UTC, no DST |
| WinCC V7.5 / V7.5 SP1 | V7.5, V7.5 SP1, Update 4+ | MS SQL Server 2014 / 2016 / 2019 | UTC, no DST |
| WinCC Professional (TIA Portal) | V13 SP1–V18 | SQLite (logs DB) and MS SQL (archive) | UTC, no DST |
| WinCC Runtime Professional | V15–V18 | MS SQL via Connectivity Pack | UTC, no DST |
Every direct-access path into the archive returns the same UTC instant:
-
Tag Logging RT tables:
dbo.TagUncompressed,dbo.TagCompressed,dbo.TagUncompressed_,dbo.TagCompressed_. -
Alarm Logging tables:
dbo.MSArcNew,dbo.MSArcConfNew,dbo.MSArcCamNew,dbo.MSEdArcNew. -
Connectivity Pack:
CC_OpenArchiveviaWinCCOLEDBProvider.1— see WinCC Connectivity Pack V7.5 documentation. -
WinCC ODK:
DMGetArchiveTagValues,DMGetArchive,DMGetAlarm— return UTC by contract.
Confirming the UTC Offset with a Diagnostic Query
Before applying any conversion, prove the offset is real and measure it. Open SQL Server Management Studio (or Query Analyzer for legacy sites) against the runtime database CC_<Project>_<YYMMDD>_<HHMMSS>_<NNN> and run the following diagnostic:
-- Replace 7 with the ValueID of your test tag
SELECT TOP 10
ut.TimeStamp AS ArchiveUTC,
GETUTCDATE() AS ServerNowUTC,
GETDATE() AS ServerLocal,
DATEDIFF(HOUR, ut.TimeStamp, GETUTCDATE()) AS HourDelta
FROM dbo.TagUncompressed AS ut
WHERE ut.ValueID = 7
ORDER BY ut.TimeStamp DESC;
Compare GETUTCDATE() with GETDATE() — that is the server's current DST-aware local offset. Compare it again with DATEDIFF(HOUR, ut.TimeStamp, GETUTCDATE()) on the most recent row. If both deltas agree, the archive is writing UTC and your offset is the only transformation missing.
| Symptom | Typical Cause | Confirmation |
|---|---|---|
| Rows are N hours early | UTC stored, viewer reads raw |
GETUTCDATE() ≈ TimeStamp + N hours
|
| Rows are N hours late | Reader already applies local-to-UTC twice | Compare with control display |
| Rows jump ±1 hour at boundary | DST switch crossed without DST logic | Run query at 02:30 local on DST changeover |
| Rows appear doubled in autumn | Local time re-entered twice | Filter raw timestamps for 01:00–02:59 local |
SQL Conversion: Local Time from UTC Archive Timestamps
The base conversion is a single DATEADD. The choice of offset depends entirely on the operator station and the date being converted — DST matters (see next section).
-- Fixed-offset conversion (e.g., a non-DST site or a region without DST)
SELECT
DATEADD(HOUR, +1, tu.TimeStamp) AS TimeStamp_Local,
tu.RealValue,
a.ValueName
FROM dbo.TagUncompressed AS tu
JOIN dbo.Archive AS a ON a.ValueID = tu.ValueID
WHERE tu.ValueID = 7
ORDER BY tu.TimeStamp DESC;
For a static GMT+1 / CET site without DST, that is the complete fix. For European, North American, and most Asian–Pacific industrial sites you need DST awareness.
Handling Daylight Saving Time (DST) in SQL
DST rules vary by jurisdiction. Two practical strategies:
Strategy 1 — Static DST table
Maintain a small reference table that lists each DST transition and join it onto the archive row. This is the most portable method across SQL Server versions.
CREATE TABLE dbo.DST_Europe_West (
BoundaryUTC DATETIME NOT NULL PRIMARY KEY,
LocalOffsetH TINYINT NOT NULL -- 1 = CET, 2 = CEST
);
INSERT INTO dbo.DST_Europe_West (BoundaryUTC, LocalOffsetH) VALUES
('2023-03-26 01:00:00', 2), -- CEST starts
('2023-10-29 01:00:00', 1), -- CEST ends
('2024-03-31 01:00:00', 2), -- CEST starts
('2024-10-27 01:00:00', 1), -- CEST ends
('2025-03-30 01:00:00', 2),
('2025-10-26 01:00:00', 1);
SELECT
DATEADD(HOUR, d.LocalOffsetH, tu.TimeStamp) AS TimeStamp_Local,
tu.RealValue,
a.ValueName
FROM dbo.TagUncompressed AS tu
JOIN dbo.Archive AS a ON a.ValueID = tu.ValueID
JOIN dbo.DST_Europe_West AS d ON tu.TimeStamp >= d.BoundaryUTC
WHERE tu.ValueID = 7
AND tu.TimeStamp < ISNULL(
(SELECT MIN(d2.BoundaryUTC) FROM dbo.DST_Europe_West d2
WHERE d2.BoundaryUTC > d.BoundaryUTC),
'9999-12-31')
ORDER BY tu.TimeStamp DESC;
Strategy 2 — Use datetimeoffset and AT TIME ZONE (SQL Server 2016+)
If your WinCC site runs V7.5 with SQL Server 2016 or newer, the modern built-in is by far the cleanest.
SELECT
tu.TimeStamp AT TIME ZONE 'UTC'
AT TIME ZONE 'Central European Standard Time' AS TimeStamp_Local,
tu.RealValue,
a.ValueName
FROM dbo.TagUncompressed AS tu
JOIN dbo.Archive AS a ON a.ValueID = tu.ValueID
WHERE tu.ValueID = 7
ORDER BY tu.TimeStamp DESC;
Windows time zone names — 'Central European Standard Time', 'Pacific Standard Time', 'Tokyo Standard Time', etc. — are stored in the server's registry under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones. Each entry contains the DST rules that SQL Server uses for AT TIME ZONE. Reference: Microsoft Docs — AT TIME ZONE (Transact-SQL).
AT TIME ZONE was first introduced in SQL Server 2016. WinCC V7.4 SP1 and earlier typically install SQL Server 2008 R2 or 2014; on those versions only Strategy 1 will work. Verify the SQL Server build with SELECT @@VERSION before choosing Strategy 2.
Using the WinCC Connectivity Pack (OLE DB)
The WinCC Connectivity Pack exposes the archive through a managed OLE DB provider, WinCCOLEDBProvider.1. A typical T-SQL query against it looks like a normal T-SQL query but the TAG:R (range) or TAG:L (last) prefix activates the WinCC archive query syntax:
SELECT
DateTime AS TimeStampUTC,
RealValue,
Quality,
Flags
FROM
OPENQUERY(
WinCC_OLE_DB,
'SELECT * FROM TAG:R(''YourArchive\',''YourTag'',
''2024-06-15 00:00:00.000'',''2024-06-16 00:00:00.000'')'
);
Wrap the returned DateTime with the same DATEADD logic as above:
SELECT
DATEADD(HOUR, 2, DateTime) AS TimeStampLocal,
RealValue,
Quality
FROM OPENQUERY(WinCC_OLE_DB, ...);
For Connectivity Pack configuration prerequisites, see the Connectivity Pack V7.5 SP1 manual. The provider is documented in the WinCC Information System path "Options for Process Control → Connectivity Pack → OLE DB Provider".
VB and VBScript Integration
WinCC scripts that read directly from the archive (e.g., a VBS action on a button click) inherit the same UTC contract. Use the Windows Script Host time-zone object or roll the offset manually.
' VBScript running inside WinCC Graphics Runtime
Dim conn, rs, sql, sLocal
Set conn = CreateObject("ADODB.Connection")
conn.Provider = "WinCCOLEDBProvider.1"
conn.Properties("Data Source").Value = ".\WinCC"
conn.Properties("Catalog").Value = "CC_OpenArchive"
conn.Properties("User ID").Value = "WinCCAdmin"
conn.Properties("Password").Value = "WinCCPass"
conn.Open
sql = "SELECT DateTime, RealValue FROM TAG:R(''ProcessValueArchive''," & _
"''Tank1.Level'',''2024-06-15 00:00:00.000'',''2024-06-16 00:00:00.000'')"
Set rs = conn.Execute(sql)
Do While Not rs.EOF
' Add 2 hours for CEST (1 hour for CET)
sLocal = DateAdd("h", 2, CDate(rs.Fields("DateTime").Value))
Trace sLocal & vbTab & rs.Fields("RealValue").Value
rs.MoveNext
Loop
rs.Close : conn.Close
Set rs = Nothing : Set conn = Nothing
For DST-aware VB conversion, a small helper such as IsInDST(d) that returns the active offset (1 or 2 for Europe) keeps the rest of the code clean.
C# / .NET Integration with WinCC Archives
For OPC UA, custom dashboards, or reporting services that target the WinCC SQL archive, convert in C# using TimeZoneInfo. This avoids the offset-table maintenance entirely.
// C# / .NET Framework 4.8+ example (WinCC V7.5)
using System;
using System.Data.SqlClient;
public static class WinCCArchiveReader
{
public static DateTime UtcToLocal(DateTime utc)
{
// Force DateTimeKind.Utc because SQL Server datetime is kind=Unspecified
var asUtc = DateTime.SpecifyKind(utc, DateTimeKind.Utc);
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(
asUtc,
"Central European Standard Time"); // adjust per site
}
public static void ReadTankLevel(string connectionString, int valueId)
{
const string sql = @"
SELECT TOP 100 TimeStamp, RealValue
FROM dbo.TagUncompressed
WHERE ValueID = @vid
ORDER BY TimeStamp DESC;";
using (var cn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("@vid", valueId);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
DateTime utc = rdr.GetDateTime(0);
DateTime local = UtcToLocal(utc);
Console.WriteLine($"{local:yyyy-MM-dd HH:mm:ss.fff}\t{rdr.GetDouble(1)}");
}
}
}
}
}
Reference: Microsoft Docs — TimeZoneInfo.ConvertTimeBySystemTimeZoneId.
WinCC Configuration Items That Affect Time Conversion
| Setting | Location | Effect |
|---|---|---|
| Computer Time Zone (Windows) | Control Panel → Date and Time | Determines the local offset WinCC controls display; does NOT change archive storage |
| WinCC Computer Properties → Time Synchronization | WinCC Explorer | If NTP-synced, the displayed local time matches the controlled offset |
| WinCC Project Properties → Time Base | WinCC Explorer | Selects "Local Time" or "UTC" for runtime formulas; archive is always UTC regardless |
| SQL Server Collation & OS TZ | Windows Registry / SQL Server Configuration Manager |
AT TIME ZONE resolves against the SQL Server host registry, not the WinCC server |
| Time Stamp for Display | Alarm Logging → Configuration → Message Blocks | Forces local conversion for selected fields only; archives still UTC |
AT TIME ZONE. Always cross-check both servers' GETDATE() and GETUTCDATE() before commissioning the conversion.
Verification Checklist
After applying the conversion, run these checks in order:
-
Current row check:
SELECT MAX(TimeStamp) FROM dbo.TagUncompressed;against the same value displayed in an OnlineTrendControl within 1 second. -
Boundary check: Pick a row stamped
2024-03-31 00:30:00UTC (i.e., 01:30 CET, 02:30 CEST). Confirm your converted local time is 02:30 after the boundary and 01:30 before. - Historical span check: Plot a 1-year trend. Verify that no hour is skipped on the spring-forward day and no hour appears duplicated on the fall-back day. Duplicates in autumn confirm your query is reading raw UTC; missing rows on the spring day suggest you double-applied an offset.
-
Alarm coincidence check: Export the same alarm from the AlarmControl (which auto-converts) and from a manual SQL query against
dbo.MSArcNew. Both timestamps must agree after your conversion. - DST regression test: Re-run step 1 at 01:30 local on the day of the next DST switch. The converted timestamp must jump by exactly +1 hour (or fall back by 1 hour) at the boundary, never continuously drift.
Troubleshooting Matrix
| Observed Symptom | Likely Cause | Fix |
|---|---|---|
| Offset is constant 2 h, all year | Fixed DATEADD(HOUR, 2, ...) on a CET site |
Switch to DST-aware conversion or use AT TIME ZONE
|
| Offset is 1 h in winter, 2 h in summer | Database is on DST-aware Windows OS, queries inherit server DST | Convert explicitly with TimeZoneInfo instead of trusting server TZ |
| Duplicate timestamps in autumn | Reading local time from a layer that already converted once | Strip any prior conversion, start from raw TimeStamp
|
| Missing hour in spring | Range filter applied in local time but compared to UTC | Convert filter bounds to UTC before the BETWEEN clause |
AT TIME ZONE throws on SQL 2012 |
Function not available pre-2016 | Apply Strategy 1 with the boundary table |
| Reports appear correct in OnlineTableControl but wrong in SSRS | SSRS reads SQL directly; control reads via WinCC layer | Apply the same conversion inside the SSRS dataset query |
| SSRS dataset parameter "today" shows yesterday after 23:00 | Parameter is built from local time but compared to UTC column | Use DateAdd("h", -2, Today()) for the lower bound during CEST |
FAQ
Why does WinCC store the timestamp in UTC instead of my local time?
WinCC uses UTC so that distributed stations in different time zones, redundant servers, and SQL replicas all see the same canonical instant. UTC also eliminates the autumn fall-back duplicate hour that breaks local-time archives. The standard WinCC controls convert UTC to local time on display.
How do I convert UTC archive timestamps to my local time in SQL?
Use DATEADD(HOUR, <offset>, TimeStamp) where offset is the active local offset (1 hour for CET, 2 hours for CEST). On SQL Server 2016+ prefer TimeStamp AT TIME ZONE 'UTC' AT TIME ZONE 'Central European Standard Time', which automatically applies DST rules from the Windows registry.
My site is in CET/GMT+1 but I see a 2-hour offset in summer. Is that a bug?
No — your local clock is GMT+2 during Central European Summer Time. Because WinCC stores UTC, the difference between UTC and your wall clock is 2 hours in summer and 1 hour in winter. A static offset will be wrong six months of the year.
Does the WinCC Connectivity Pack return UTC or local time?
UTC. The Connectivity Pack's OLE DB provider, the WinCC ODK DM functions, and the OPC UA Historical Access server all return timestamps in UTC by contract. Apply the same DATEADD or TimeZoneInfo conversion as you would for direct SQL access.
Where in the Siemens documentation is the UTC behavior officially stated?
The UTC storage convention is documented in the WinCC Information System under TagLogging → Data Storage, in the Connectivity Pack manual (Entry ID 37414113), and in the public Siemens Industry Online Support FAQ entries 17811102, 23067556, and 23542699.