Durations and Timezones

Duration Arithmetic and Timezone Handling

xs:yearMonthDuration counts months (P1Y2M) and xs:dayTimeDuration seconds (P3DT4H); they never mix. Two dateTimes subtract to a dayTimeDuration, and a date plus a duration is a date. Values with zones compare on the timeline; one without a zone takes the processor's implicit timezone, so results can differ between servers. adjust-dateTime-to-timezone() moves a value to a zone, or strips it.

Month-end arithmetic and timezone comparison
xp 'xs:dateTime(//sent) - xs:dateTime("2026-09-01T00:00:00Z")' \
   'xs:date("2026-01-31") + xs:yearMonthDuration("P1M")' \
   'xs:dateTime("2026-10-01T08:00:00") eq xs:dateTime("2026-10-01T08:00:00Z")' \
   'adjust-dateTime-to-timezone(xs:dateTime(//sent), xs:dayTimeDuration("PT8H"))'
Output
xs:dateTime(//sent) - xs:dateTime("2026-09-01T00:00:00Z") => xs:duration("P30DT8H")
xs:date("2026-01-31") + xs:yearMonthDuration("P1M") => xs:date("2026-02-28")
xs:dateTime("2026-10-01T08:00:00") eq xs:dateTime("2026-10-01T08:00:00Z") => false()
adjust-dateTime-to-timezone(xs:dateTime(//sent), xs:dayTimeDuration("PT8H")) =>
  xs:dateTime("2026-10-01T16:00:00+08:00")

Month arithmetic clamps to the last valid day, so January 31 plus a month is February 28. The comparison is false only because this machine's implicit zone is +08:00: store timestamps with an explicit zone, preferably Z.