NotesDateTime and Time Zones: GMTTime, ConvertToZone, and the Sign Convention That Trips Everyone

NotesDateTime and Time Zones: GMTTime, ConvertToZone, and the Sign Convention That Trips Everyone

Jul 13, 2026 719 words

A user in Taipei creates a record at 9 AM; a scheduled agent on a server in Frankfurt processes it; a report renders it for a reader in New York. If you stored and compared the raw local-time strings, all three see a different “9:00” and your sort order is nonsense. NotesDateTime has the tools to get this right — but they come with a sign convention and a DST rule that catch almost everyone the first time.

The mental model that unlocks the class: one NotesDateTime is a single absolute instant, and GMTTime / LocalTime / ZoneTime are three views of it. ConvertToZone changes the view, not the instant. This is the third angle on the class — the general NotesDateTime walkthrough covers construction and arithmetic; this one is about zones.


TL;DR

  • GMTTime (read-only) is the instant as Greenwich Mean Time — the same value no matter which machine reads it. This is the canonical form: store and compare on GMTTime.
  • LocalTime (read-write) is the instant in the running machine’s zone; ZoneTime (read-only) is the instant in whatever zone ConvertToZone set (equal to LocalTime until you convert).
  • TimeZone (read-only integer) uses the classic Notes convention: it’s “the number of hours which must be added to the time to get Greenwich Mean Time” — so positive means west of GMT (US Eastern is 5, not -5). The docs hedge “in many cases, but not all,” so don’t treat it as a clean universal offset.
  • ConvertToZone(newzone, dst) re-views the instant in another zone — it changes TimeZone/IsDST/ZoneTime but “does not affect the GMTTime and the LocalTime properties.” Its DST gotcha: it “uses the daylight saving time rules of the zone being converted from, not the zone being converted to.”
  • For native date math use LSGMTTime / LSLocalTime (LotusScript Date variants); the string GMTTime/LocalTime are for storage and display.

Three views of one instant

Dim dt As New NotesDateTime("04/16/96 05:36 PM")
Print "LocalTime: " & dt.LocalTime ' machine-zone string
Print "TimeZone : " & dt.TimeZone ' integer offset (see below)
Print "GMTTime : " & dt.GMTTime ' absolute GMT string

On a US-Eastern machine that same instant prints its GMTTime as 04/16/96 09:36:00 PM GMT; on a machine 11 zones west it prints a different local time but the same GMTTime. That’s the whole point: GMTTime is machine-independent, so two NotesDateTime values created on different servers compare and sort correctly only when you compare on GMT — not on the locale-formatted LocalTime strings.

The TimeZone sign convention

This is the one that produces off-by-hours bugs. Per the TimeZone docs, the integer “indicates the number of hours which must be added to the time to get Greenwich Mean Time.” So GMT is 0, US Eastern Standard Time is 5, and Alaska-Hawaii is 10positive is west of GMT, the opposite sign from the UTC+8 / UTC−5 notation most developers carry in their heads. Taipei (UTC+8) reads as -8 here. The docs add “in many cases, but not all,” their own hedge that half-hour zones and historical rules don’t map to a clean integer — so read TimeZone as Notes’ internal marker, not as a portable offset you do arithmetic on.

ConvertToZone, and its DST trap

ConvertToZone(newzone, dst) re-labels the same absolute instant into another zone’s view. The official example walks an instant across every zone:

Sub Initialize
Dim dateTime As New NotesDateTime("Today 06:00")
Dim msg As String
msg = "Zone" & Chr(9) & "Time"
For i = -12 To 12
Call dateTime.ConvertToZone(i, True)
msg = msg & Chr(10) & dateTime.TimeZone & Chr(9) & dateTime.ZoneTime
Next
Messagebox msg,, "Today 06:00 across zones"
End Sub

Two things the docs are explicit about. First, the conversion “does not affect the GMTTime and the LocalTime properties” — after ConvertToZone you read the result from ZoneTime, while GMTTime (the absolute instant) and LocalTime stay put. Second, the DST trap: it “uses the daylight saving time rules of the zone being converted from, not the zone being converted to.” So converting between two zones with different DST rules can produce a wall-clock time that’s off by the DST offset — if precise wall time in the target zone matters, verify against that zone’s actual rules rather than trusting the conversion blindly.

Native date math: LSGMTTime

GMTTime and LocalTime return locale-formatted strings — good for storage and display, awkward for computation. When you need to feed a value into LotusScript date math or Format$, use the LS* variants, which return a native Date:

Dim dt As New NotesDateTime("2026-07-09 09:00:00")
Dim gmt As Variant
gmt = dt.LSGMTTime ' a LotusScript Date, in GMT — safe for comparison

Use LSGMTTime (or the string GMTTime) as the canonical value you persist and compare; reach for LocalTime / ZoneTime only when you’re formatting something for a human to read. For elapsed time between two instants, TimeDifference returns the gap in seconds (self minus the parameter), and TimeDifferenceDouble returns the same as a Double to avoid overflow on multi-decade spans — because both operands carry their own zone information, the difference is computed on the absolute instants and is zone-correct.

What about Java and SSJS?

LotusScriptJavaSSJS / XPages
NotesDateTimeDateTimeDateTime

Java’s lotus.domino.DateTime (via session.createDateTime(...)) exposes the same model — getGMTTime(), getLocalTime(), getTimeZone(), convertToZone(int, boolean), timeDifference() — with the identical sign convention and DST caveat. Java has no LS* native-variant analogue; it offers toJavaDate() for a java.util.Date instead. SSJS reaches the same backing class through session.createDateTime(...). The one rule to carry everywhere: persist and compare on GMT.

Sources

← Back to all posts