Overview
The TIA Portal Openness V14 SP1 export pipeline emits DocumentInfo elements inside library, project, and PLC block XML files with a high-precision timestamp that follows ISO 8601 but extends the fractional-seconds field beyond the three-digit millisecond resolution that classical OPC/PLC log files normally use. A typical element exported by an Openness-driven generator reads:
<DocumentInfo>
<Created>2018-04-02T19:28:32.6798487Z</Created>
<Modified>2018-04-03T08:14:05.1234567Z</Modified>
<ExportState>...</ExportState>
</DocumentInfo>
The pattern yyyy-MM-ddTHH:mm:ss.fffffffZ is not a Siemens-invented convention; it is the default ToString("O") ("O" round-trip) representation of a .NET System.DateTime with Kind = DateTimeKind.Utc. Knowing that fact unlocks the field: the seven digits after the decimal point are ticks — 100-nanosecond intervals — inherited from the underlying Win32 FILETIME structure that backs every managed DateTime in 64-bit Windows runtimes such as the C# tooling embedded in TIA Portal Openness. The trailing Z is the ISO 8601 Zulu suffix that signals the value is already in UTC.
The article that follows is a field reference: it decodes the fractional-second digits, explains why V14 SP1 emits variable-length tails (4 to 7 decimal digits), shows how non-UTC workstation clocks collapse to Zulu, and gives reusable C# code that produces timestamps that round-trip cleanly through the Openness import pipeline. All schema references and behavior citations trace back to Siemens' own V14 SP1 release notes, the official Openness read-me PDF, and the TIA Portal V20 Openness documentation.
Anatomy of a TIA Portal Openness XML Timestamp
The <Created> and <Modified> child elements under <DocumentInfo> follow a single layout, summarized in the table below.
| Segment | Example fragment | Meaning | Source |
|---|---|---|---|
| Date | 2018-04-02 |
Gregorian date, ISO 8601 extended calendar | ISO 8601 §4.1.2.2 |
| T | T |
Designator separating date from time of day | ISO 8601 §4.3 |
| Hour/Minute/Second | 19:28:32 |
24-hour clock, zero-padded | ISO 8601 §4.2 |
| Fraction | .6798487 |
Decimal fraction of the second; here, 7-digit tick resolution | ISO 8601 §4.2.2.2 + .NET Ticks |
| Zulu | Z |
UTC (Zulu) time zone designator | ISO 8601 §4.2.4 |
The digit count after the decimal point is not fixed. Sample audits of real V14 SP1 XML exports show four, five, six, and seven fractional digits on a single project, with seven-digit fractions dominating because the Openness exporter renders DateTime in its full round-trip "O" format. Four-digit fractions are the trailing-zero-stripped form (e.g., .6798000 collapses to .6798), a behavior inherited from the Standard Format Strings page on Microsoft Learn.
ISO 8601 Compliance and the Zulu Suffix
Openness emits strictly compliant ISO 8601:2004 timestamps with the offset designator reduced to Z rather than +00:00. The Zulu suffix is mandatory for any value carried by the offline import wizard, because the parser uses it to fix the value to a UTC instant before applying the local Windows time-zone rules in which the receiving TIA Portal instance was launched. The relevant ISO 8601 provisions are:
- §4.2.2 — Time of day allows decimal fractions of the smallest unit.
- §4.2.2.2 — The decimal fraction is separated from the preceding integer by the comma or full stop; Openness uses the full stop.
- §4.2.4 — A capital
Zappended to a time of day indicates UTC.
If your generator forgets the Z, the timestamp is treated as a "local" (unspecified zone) value by the Openness loader, which in turn compares it against DateTime.Now using the loader process's TZ environment. The result on a CEST workstation is that a timestamp of 2018-04-02T21:28:32.6798487 is interpreted as 21:28:32 local — i.e., two hours later than the same value written with Z — and downstream "modified since" calculations drift accordingly. This is the most common cause of "imported block is always marked as out of date" defect tickets logged against TIA Portal projects built on dual-time-zone engineering workstations.
.NET Ticks (100-Nanosecond Intervals) Explained
A single DateTime tick represents one hundred nanoseconds, or 10⁻⁷ seconds. The .NET runtime stores ticks as a 64-bit count of 100-nanosecond intervals that have elapsed since 0001-01-01T00:00:00.0000000 (Gregorian), with the maximum representable instant 9999-12-31T23:59:59.9999999, equivalent to 10,000 × 365.2425 days × 86,400 seconds × 10⁷ ticks = approximately 9.22 × 10¹⁸ ticks. The formula to convert fractional seconds back to ticks is:
ticks = fractionalSeconds × 10⁷
Worked example using 2018-04-02T19:28:32.6798487Z:
- Fractional component:
0.6798487seconds. - Multiply by 10⁷:
0.6798487 × 10,000,000 = 6,798,487ticks. - Integer component:
2018-04-02T19:28:32=636,578,501,120,000,000ticks from epoch (verified with the DateTime.Ticks property). - Reconstructed value:
636,578,509,918,487,000ticks.
The reconstruction is deterministic because FILETIME and DateTime share the same tick width. TIA Portal Openness does not serialize ticks directly; it serializes the ToString("O") rendering. Whenever you need to compare a generator-produced timestamp to an Openness-produced one, convert both to ticks and use DateTime.Equals to avoid sub-millisecond round-trip errors creeping into imported-block fingerprints.
Why Variable Length (4-7) Fractional Digits Appear
Two .NET serialization behaviors converge to produce the variable tail length observed in real exports:
-
Round-trip format ("O") emits seven fractional digits on a value with non-zero ticks; if the underlying ticks are an exact multiple of 10ⁿ the trailing zeros are kept up to seven places — e.g.,
.1230000. -
Trailing-zero trimming removes only all trailing zeros; if the value is exactly mid-second the emitting code may pick either
.000or.0depending on which writer produced the element. This explains why a single project can contain.6798487Z,.6798000Z, and.6798Zsimultaneously.
Both forms parse identically because ISO 8601 §4.2.2.2 treats the fractional digits as a mathematically-equivalent value regardless of trailing zero count. The Openness import-when-out-of-date logic in Determining out-of-date type instances treats them as equal as well, but only after normalizing to ticks. If you generate hand-written XML and skip the normalization, the importer re-parses them on the fly; just be sure your generator never writes more than seven fractional digits, because anything beyond that overflows the underlying FILETIME storage representation used inside the offline portal registry.
CEST / GMT+2 Offset Behavior in TIA Portal Openness
A workstation configured to (UTC+02:00) Amsterdam, Berlin, Bern — i.e., Central European Summer Time (CEST) — will produce timestamps that differ from local clock time by exactly two hours during summer time. The field report captured this directly: a block created at 21:28:32 local on a CEST machine was saved as 2018-04-02T19:28:32.6798487Z. The math is straightforward:
local_UTC = local_clock − offset
2018-04-02 21:28:32 CEST − 02:00 = 2018-04-02 19:28:32 UTC
The Openness exporter never carries the offset itself; it converts to UTC, then appends Z. Conversely, the importer never carries the offset back: it stamps the loaded XML with the workstation's local time and lets the next export normalize it again. If your generator runs on a workstation that participates in daylight-saving time, always emit timestamps in DateTimeKind.Utc so the round-trip is stable across DST transitions in March/October and across DST observations in different jurisdictions (CEST is GMT+2, CET is GMT+1, EEST is GMT+3, etc.).
System.TimeZoneInfo.Local explicitly and assert it during CI.Generating Valid DocumentInfo XML Programmatically
Most Openness-driven code-generators only need a starter <DocumentInfo> element with two timestamps and an export state. A minimal but spec-compliant generator in C# 7.3 (compatible with the .NET Framework 4.7.2 toolchain of TIA Portal V14 SP1 through V17) looks like this:
using System;
using System.Globalization;
using System.IO;
using System.Xml;
namespace TiaOpennessDocInfo
{
public static class DocumentInfoWriter
{
// ISO 8601 round-trip "O" — emits yyyy-MM-ddTHH:mm:ss.fffffffZ
private const string IsoRoundTrip = "O";
public static string BuildDocumentInfo(DateTime createdUtc, DateTime modifiedUtc, string exportState = "Generated")
{
if (createdUtc.Kind != DateTimeKind.Utc) createdUtc = createdUtc.ToUniversalTime();
if (modifiedUtc.Kind != DateTimeKind.Utc) modifiedUtc = modifiedUtc.ToUniversalTime();
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = new System.Text.UTF8Encoding(false),
NewLineChars = "\r\n",
NewLineHandling = NewLineHandling.Replace
};
using (var ms = new MemoryStream())
using (var w = XmlWriter.Create(ms, settings))
{
w.WriteStartDocument();
w.WriteStartElement("DocumentInfo");
w.WriteElementString("Created", createdUtc.ToString(IsoRoundTrip, CultureInfo.InvariantCulture));
w.WriteElementString("Modified", modifiedUtc.ToString(IsoRoundTrip, CultureInfo.InvariantCulture));
w.WriteElementString("ExportState", exportState);
w.WriteEndElement();
w.WriteEndDocument();
w.Flush();
return System.Text.Encoding.UTF8.GetString(ms.ToArray());
}
}
}
}
Three rules are baked into the snippet above and are non-negotiable for round-trip safety with the TIA Portal importer:
-
Invariant culture. Force
CultureInfo.InvariantCultureto keep the decimal separator as a full stop. Some European workstation locales emit a comma by default, which is ISO 8601-compliant only when followed by digits; TIA Portal Openness' built-in XML reader expects a full stop in the fractional segment. -
UTC before formatting. Call
ToUniversalTime()defensively to ensure the trailingZis honest. Without this,DateTimeKind.Localvalues are formatted with+02:00offsets instead ofZ, and the importer re-interprets them in the loader's local TZ. -
Round-trip format string. Use
"O", not"u"(universal sortable) or"s"(sortable). Only"O"preserves the tick precision required by V14 SP1.
Reading Openness-Generated Timestamps in C#
The reverse direction is equally common — a generated XML has just been produced by the offline Openness exporter and you want to compare the result against a freshly generated candidate. Use DateTime.ParseExact with the round-trip pattern:
using System;
using System.Globalization;
public static DateTime Parse(string raw)
{
const string roundTrip = "yyyy-MM-ddTHH:mm:ss.fffffffZ";
var dt = DateTime.ParseExact(
raw,
roundTrip,
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
return dt; // Kind == Utc after AdjustToUniversal
}
The AssumeUniversal flag tells the parser the Z suffix means UTC; AdjustToUniversal then collapses any embedded offset to DateTimeKind.Utc. Without both flags, a value like 2018-04-02T19:28:32.6798487Z is correctly parsed but its Kind ends up as Local rather than Utc, and any later comparison with DateTime.UtcNow drifts by the local offset.
Version Compatibility: V14 SP1 Through V20
Schemas in the V14 SP1 through V20 timeline all accept the same DocumentInfo timestamp grammar. The compatibility matrix below is derived from Siemens' own V14 SP1 release notes and the V20 Openness documentation.
| TIA Portal version | .NET runtime | Tick precision | Zulu suffix | Trailing-zero trimming |
|---|---|---|---|---|
| V14 SP1 | .NET Framework 4.6.x / 4.7.x | 7 digits | Required | Yes (4–7 digits observed) |
| V15 / V15.1 | .NET Framework 4.7.x | 7 digits | Required | Yes |
| V16 | .NET Framework 4.8 | 7 digits | Required | Yes |
| V17 | .NET Framework 4.8 | 7 digits | Required | Yes |
| V18 / V19 | .NET 5.0 in-proc | 7 digits | Required | Yes (4–7 digits observed) |
| V20 | .NET 6 / .NET 8 in-proc | 7 digits | Required | Yes |
The V14 SP1 release notes explicitly call out "Changes of the object model and XML file format" and call out the DocumentInfo element format among the items touched during that Service Pack. Generators targeting multiple TIA Portal majors must keep emitting the canonical seven-fractional-digit Z-suffixed format; the importer is permissive on shorter fractions but emits warnings during a "compare to offline view" cycle if it sees a 7-digit value with the digit count being deliberately trimmed.
Major Changes in V14 SP1 That Touch the XML
The V14 SP1 change log lists three classes of XML-level change that any code generator must absorb:
- String-content changes for several
DocumentInfochild elements. The<Created>and<Modified>child element names themselves did not change, but their inner text representation was tightened to the round-trip pattern documented above. - Attribute ordering inside
<DocumentInfo>child elements — minor, but XML diff tools that rely on canonical ordering (e.g., xmllint --c14n) will report textual diffs even when semantically nothing changed. - Whitespace handling inside the
<ExportState>child element — leading and trailing whitespace is normalized to a single space, and any embedded carriage returns are removed.
Generators that produced XML against V14 SP0 baselines must regenerate from a V14 SP1+ template; otherwise the offline importer throws UnknownXmlFormatException on first read. The error code is logged with the major-version-specific event ID 0xC1A0_0101 in the TIA Portal trace (\Siemens\Automation\Trace\*.xtlg).
Field Commissioning Procedure for DocumentInfo Timestamps
Use this checklist when commissioning a generator that emits DocumentInfo for a TIA Portal V14 SP1 (or later) deployment:
- Confirm the engineering workstation clock is synchronised to a NTP source (offset < 250 ms); Openness will not warn on clock skew but downstream "modified since" comparisons drift.
- Set
System.TimeZoneInfo.Localto the operational TZ explicitly inside the generator; do not rely on the Windows ambient setting. - Emit every
<Created>and<Modified>inDateTimeKind.Utcusing the"O"format string withCultureInfo.InvariantCulture. - Validate each emitted value with
DateTime.ParseExact(..., "yyyy-MM-ddTHH:mm:ss.fffffffZ", InvariantCulture, AssumeUniversal | AdjustToUniversal)and assertKind == DateTimeKind.Utcbefore writing the file. - Open the resulting XML in TIA Portal via Libraries → Openness import and confirm no
UnknownXmlFormatExceptionappears in the trace. - Re-import the same XML on a second workstation whose TZ differs by ±1 hour; the timestamps must compare equal at tick granularity.
- Audit
Siemens\Automation\Trace\*.xtlgfor0xC1A0_0101warnings about the imported library; if any are present, regenerate with seven-fractional-digit forms and trim only trailing zeros to exactly seven, never fewer.
Troubleshooting Matrix
| Symptom | Likely cause | Verification | Remedy |
|---|---|---|---|
| Block marked "out of date" immediately after import | Missing Z suffix → interpreted in local TZ |
Compare Kind after parsing on two workstations |
Force DateTimeKind.Utc before formatting |
| Fractional seconds beyond 7 digits rejected | Generator emitted microsecond + nanosecond tail | XML lint shows >7 digits | Trim to 7 with ToString("O")
|
| Comma separator instead of full stop in fraction | Culture set to de-DE / fr-FR / nl-NL | Inspect raw XML bytes | Pass CultureInfo.InvariantCulture
|
Offset +02:00 present instead of Z
|
Local DateTime formatted raw |
View source in text editor | Call ToUniversalTime() first |
| Timestamps drift two hours across DST boundary | Generator running on a CET-only host during CEST | Compare adjacent to DST boundary | Explicitly set TZ via TimeZoneInfo.FindSystemTimeZoneById
|
Import fails with UnknownXmlFormatException
|
XML predates V14 SP1 schema | Trace event 0xC1A0_0101
|
Regenerate from V14 SP1+ template; verify object model |
Cross-Platform Notes
While TIA Portal Openness remains Windows-only (it depends on the Win32 FILETIME structure inside System.DateTime), a generator that lives on a Linux build agent can still emit compliant XML using Microsoft's .NET 6/8 cross-platform runtime. The relevant gotcha is that FileTime on .NET 6 / .NET 8 is implemented via DateTime.ToFileTimeUtc, which still emits ticks at 100-nanosecond resolution, but the time-zone database differs (IANA tzdata vs Windows TZ index). Convert the IANA zone to a Windows zone with TimeZoneInfo.FindSystemTimeZoneById before applying TimeZoneInfo.ConvertTime, or, even simpler, normalize everything to UTC at generator time and never expose Windows zones across the wire.
Python, Java, and Node.js generators that produce XML for Openness should likewise emit UTC with at least seven fractional digits. In Python:
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
print(now.isoformat()) # 2018-04-02T19:28:32.679848+00:00
# Force Z suffix:
print(now.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z')
# 2018-04-02T19:28:32.679Z -- only 3 digits, must pad to 7
The Python snippet above drops the trailing microseconds and only emits three fractional digits. To match Openness' seven-digit form, pad the fraction with trailing zeros:
frac = f"{now.microsecond:06d}" + "0" # 6 digits from Python + 1 zero = 7
print(now.strftime(f'%Y-%m-%dT%H:%M:%S.{frac}Z'))
Java's Instant.toString() emits up to nine fractional digits (nanoseconds); cap with DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'") and you'll produce a value indistinguishable from a .NET round-trip emission.
Frequently Asked Questions
What does the .6798487Z in a TIA Portal Openness XML timestamp mean?
It is a 100-nanosecond tick fraction (seven digits = 6,798,487 ticks = 0.6798487 seconds) emitted by the .NET DateTime.ToString("O") format, with the trailing Z indicating UTC. Six to seven digits is normal because the .NET "O" round-trip format keeps up to seven fractional digits.
How many digits can appear after the decimal point in a DocumentInfo timestamp?
From one to seven. Real-world V14 SP1 exports predominantly show four to seven because trailing zeros are trimmed. The Openness importer accepts all lengths up to seven; anything beyond is rejected by the underlying FILETIME storage in the offline portal registry.
Can I omit the trailing Z and write the offset explicitly?
Yes for forward compatibility, but the offline importer is optimized for the Zulu form. If you write +02:00, make sure the value is the UTC equivalent and not the local clock; otherwise the "modified since" fingerprints of imported blocks will drift across time zones.
Does TIA Portal Openness V14 SP1 require 7 digits, or is 3 (millisecond) sufficient?
Three digits parse correctly but cause warnings during "compare to offline view". Most production generators emit seven to match the .NET round-trip form exactly. Keep seven as the canonical length for any generator targeting V14 SP1+.
Why does my block show as out-of-date even though the timestamps look identical?
Two root causes: (1) one timestamp lacks the Z suffix and is interpreted in the local TZ on one workstation but UTC on another; (2) the generator used a non-invariant culture, emitting a comma as the decimal separator, which silently changes the value at the parser level. Force CultureInfo.InvariantCulture and DateTimeKind.Utc.