Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception?
Added by Martin Honnen over 2 years ago
The .NET API has methods https://www.saxonica.com/html/documentation11/dotnetdoc/Saxon/Api/XdmAtomicValue.html#XdmAtomicValue(DateTime) and https://www.saxonica.com/html/documentation11/dotnetdoc/Saxon/Api/XdmAtomicValue.html#XdmAtomicValue(DateTimeOffset) that seem to be offered to pass in a .NET DateTime
or DateTimeOffset
to the XdmAtomicValue
constructor.
The easiest way to construct such values are e.g. DateTime.Now
or DateTimeOffset.Now
; however, I am kind of confused that passing these values in to XdmAtomicValue
gives an exception:
<System.OverflowException: Value was either too large or too small for an unsigned byte.
at System.Convert.ThrowByteOverflowException()
at System.Convert.ToByte(UInt64 value)
at System.Convert.ToByte(Int64 value)
at Saxon.Api.XdmAtomicValue._init(DateTime dt)
at Saxon.Api.XdmAtomicValue..ctor(DateTime dt)
<System.OverflowException: Value was either too large or too small for an unsigned byte.
at System.Convert.ThrowByteOverflowException()
at System.Convert.ToByte(UInt64 value)
at System.Convert.ToByte(Int64 value)
at Saxon.Api.XdmAtomicValue._initOffset(DateTimeOffset offset)
at Saxon.Api.XdmAtomicValue..ctor(DateTimeOffset offset)
Are these exceptions intended/expected? What is the right DateTime or DateTimeOffset range to pass in to XdmAtomicValue?
Replies (5)
Please register to reply
RE: Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception? - Added by Martin Honnen over 2 years ago
The Java API for the seventh argument expects an int for nanoseconds https://www.saxonica.com/html/documentation11/javadoc/net/sf/saxon/value/DateTimeValue.html#DateTimeValue-int-byte-byte-byte-byte-byte-int-int- yet the .NET code (https://saxonica.plan.io/projects/saxonmirrorhe/repository/he/revisions/saxon10/entry/src/main/csharp/api/Saxon.Api/Model.cs#L984) seems to try to compute a value but use Convert.ToByte
:
public XdmAtomicValue(DateTime dt)
{
if (dt.Kind == DateTimeKind.Local)
{
int offsetMinutes = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Minutes;
this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), offsetMinutes);
}
else if (dt.Kind == DateTimeKind.Utc)
{
this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), 0);
}
else if (dt.Kind == DateTimeKind.Unspecified)
{
int offsetMinutes = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Minutes;
this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), net.sf.saxon.value.CalendarValue.NO_TIMEZONE);
}
}
/// <summary>
/// Construct an atomic value of type <c>xs:dateTime</c> with a specific timezone offset from a DateTimeOffset object.
/// </summary>
/// <param name="offset">The DateTimeOffset value</param>
public XdmAtomicValue(DateTimeOffset offset)
{
int offsetMinutes = offset.Offset.Minutes;
DateTime dt = offset.DateTime;
this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), offsetMinutes);
}
RE: Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception? - Added by Martin Honnen over 2 years ago
Indeed only a DateTime with very small Ticks property can be passed in, in the following all but the first test fail:
using System;
using NUnit.Framework;
using Saxon.Api;
namespace SaxonCSXdmAtomicValueFromDateTime
{
public class Tests
{
private static Processor? processor;
[SetUp]
public void Setup()
{
processor = new Processor(true);
}
[Test(Description = "Test new XdmAtomicValue(new DateTime(1, 1, 1, 0, 0, 0, DateTimeKind.Utc))")]
public void TestXdmAtomicValueFromNewDateTime()
{
var dateTime = new DateTime(1, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var xdmDateTime = new XdmAtomicValue(dateTime);
Assert.IsInstanceOf<XdmAtomicValue>(xdmDateTime);
}
[Test(Description = "Test new XdmAtomicValue(DateTime.Parse)")]
public void XdmAtomicValueDateTimeParse() => Assert.DoesNotThrow(() => { var value = new XdmAtomicValue(DateTime.Parse("2022-05-05T00:00:00Z", null, System.Globalization.DateTimeStyles.RoundtripKind)); }, "new XdmAtomicValue(DateTime.Now) does not throw");
[Test(Description = "Test new XdmAtomicValue(new DateTime(2022, 5, 6))")]
public void XdmAtomicValueNewDateTime() => Assert.DoesNotThrow(() => { var value = new XdmAtomicValue(new DateTime(2022, 5, 6)); }, "new XdmAtomicValue(new DateTime()) does not throw");
[Test(Description = "Test new XdmAtomicValue(DateTime.Now)")]
public void XdmAtomicValueDateTimeNow() => Assert.DoesNotThrow(() => { var value = new XdmAtomicValue(DateTime.Now); } , "new XdmAtomicValue(DateTime.Now) does not throw");
[Test(Description = "Test new XdmAtomicValue(DateTimeOffset.Now)")]
public void XdmAtomicValueDateTimeOffsetNow() => Assert.DoesNotThrow(() => { var value = new XdmAtomicValue(DateTimeOffset.Now); }, "new XdmAtomicValue(DateTimeOffset.Now) does not throw");
}
}
RE: Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception? - Added by Martin Honnen over 2 years ago
But it kind of looks as if the attempt to use dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond
is not the right value for the nanoseconds part of the DateTime, that value is rather the whole time since 0001-01-01T00:00:00 in nanoseconds, I think.
RE: Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception? - Added by Martin Honnen over 2 years ago
I wonder whether that argument should be Convert.ToInt(dt.Ticks % TimeSpan.TicksPerSecond * 100)
.
RE: Should new XdmAtomicValue(DateTime.Now) or new XdmAtomicValue(DateTimeOffset.Now) work with Saxon .NET or SaxonCS or throw an exception? - Added by Michael Kay over 2 years ago
I have created a unit test that reproduces the failure.
Please register to reply