Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace DvInt* with .NET standard data types. WIP #683

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
9ba4dab
trigger build.
GalOshri Aug 7, 2018
baf0696
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 14, 2018
f7a0fff
Datakinds, ColumnTypes and NAHandle.
codemzs Aug 14, 2018
1fdfe0d
Change metadata for categorical indices from DvInt4 to Int32.
codemzs Aug 15, 2018
734540f
Conversions class.
codemzs Aug 15, 2018
10d753c
peak, poke, codecs, transforms, evaluators.
codemzs Aug 16, 2018
46299b8
test.
codemzs Aug 16, 2018
a99831b
undo DvBool.
codemzs Aug 16, 2018
a0ceabb
undo DvBool.
codemzs Aug 16, 2018
f30dd7e
Replace DvInt* with .NET standard types and remove missing value supp…
codemzs Aug 16, 2018
a6e5c75
PR feedback.
codemzs Aug 16, 2018
c4bae95
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 16, 2018
9aea10b
clean up.
codemzs Aug 16, 2018
db2da0b
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 17, 2018
5d14c0a
PR feedback.
codemzs Aug 21, 2018
9051ef9
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 21, 2018
789182a
merge master and fix tests.
codemzs Aug 21, 2018
4e70eb4
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 21, 2018
ef54c60
merge master and fix tests.
codemzs Aug 21, 2018
83dec91
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 23, 2018
b3ba06d
PR feedback.
codemzs Aug 23, 2018
fb9f792
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 23, 2018
25d1a52
PR feedback.
codemzs Aug 23, 2018
1853471
PR feedback.
codemzs Aug 23, 2018
66fa9be
PR feedback.
codemzs Aug 23, 2018
f17b7b0
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 24, 2018
0c8fb8c
Tests.
codemzs Aug 26, 2018
f16b0a9
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 26, 2018
9c128a3
cleanup.
codemzs Aug 26, 2018
9c4eebf
cleanup.
codemzs Aug 26, 2018
d7ba332
Add IDV test for backward compatiblity with DvTypes.
codemzs Aug 27, 2018
63e45e7
baseline and idv file.
codemzs Aug 27, 2018
39f150b
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 27, 2018
11be480
Merge branch 'idvtest' of https://github.com/codemzs/machinelearning …
codemzs Aug 27, 2018
681b3ef
PR feedback.
codemzs Aug 27, 2018
1a38dfe
Merge branch 'idvtest' of https://github.com/codemzs/machinelearning …
codemzs Aug 27, 2018
7580513
disable test for Linux.
codemzs Aug 28, 2018
3c5ce8e
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 28, 2018
8f8e544
PR feedback.
codemzs Aug 28, 2018
3fb1cc2
add more tests.
codemzs Aug 28, 2018
c844b4e
PR feedback.
codemzs Aug 28, 2018
53b4e57
add test for parquet loader.
codemzs Aug 28, 2018
f1d1da6
Merge branch 'parquettest' of https://github.com/codemzs/machinelearn…
codemzs Aug 28, 2018
f05e2f1
Update parquet tests.
codemzs Aug 28, 2018
33b7150
PR feedback.
codemzs Aug 28, 2018
d028702
fix build.
codemzs Aug 28, 2018
9a4f192
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 29, 2018
a7cd3d8
PR feedback.
codemzs Aug 30, 2018
40c01fc
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 30, 2018
ad37fb5
cleanup.
codemzs Aug 30, 2018
b9edc92
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 31, 2018
078cd8c
resolve merge conflict.
codemzs Aug 31, 2018
be3d177
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Sep 3, 2018
cd7de9f
PR feedback.
codemzs Sep 4, 2018
7e80e50
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Sep 7, 2018
9d4f4d6
merge master.
codemzs Sep 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/Microsoft.ML.Api/ApiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ private static OpCode GetAssignmentOpCode(Type t)
{
// REVIEW: This should be a Dictionary<Type, OpCode> based solution.
// DvTypes, strings, arrays, all nullable types, VBuffers and UInt128.
if (t == typeof(DvInt8) || t == typeof(DvInt4) || t == typeof(DvInt2) || t == typeof(DvInt1) ||
t == typeof(DvBool) || t == typeof(DvText) || t == typeof(string) || t.IsArray ||
if (t == typeof(DvText) || t == typeof(DvBool) || t == typeof(string) || t.IsArray ||
(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(VBuffer<>)) ||
(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) ||
t == typeof(DvDateTime) || t == typeof(DvDateTimeZone) || t == typeof(DvTimeSpan) || t == typeof(UInt128))
Expand Down
68 changes: 12 additions & 56 deletions src/Microsoft.ML.Api/DataViewConstructionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,42 +134,22 @@ private Delegate CreateGetter(int index)
else if (outputType.GetElementType() == typeof(int))
{
Ch.Assert(colType.ItemType == NumberType.I4);
return CreateConvertingArrayGetterDelegate<int, DvInt4>(index, x => x);
}
else if (outputType.GetElementType() == typeof(int?))
{
Ch.Assert(colType.ItemType == NumberType.I4);
return CreateConvertingArrayGetterDelegate<int?, DvInt4>(index, x => x ?? DvInt4.NA);
return CreateConvertingArrayGetterDelegate<int, int>(index, x => x);
Copy link
Member

@eerhardt eerhardt Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a "converting" delegate here to return the same value? #Resolved

}
else if (outputType.GetElementType() == typeof(long))
{
Ch.Assert(colType.ItemType == NumberType.I8);
return CreateConvertingArrayGetterDelegate<long, DvInt8>(index, x => x);
}
else if (outputType.GetElementType() == typeof(long?))
{
Ch.Assert(colType.ItemType == NumberType.I8);
return CreateConvertingArrayGetterDelegate<long?, DvInt8>(index, x => x ?? DvInt8.NA);
return CreateConvertingArrayGetterDelegate<long, long>(index, x => x);
}
else if (outputType.GetElementType() == typeof(short))
{
Ch.Assert(colType.ItemType == NumberType.I2);
return CreateConvertingArrayGetterDelegate<short, DvInt2>(index, x => x);
}
else if (outputType.GetElementType() == typeof(short?))
{
Ch.Assert(colType.ItemType == NumberType.I2);
return CreateConvertingArrayGetterDelegate<short?, DvInt2>(index, x => x ?? DvInt2.NA);
return CreateConvertingArrayGetterDelegate<short, short>(index, x => x);
}
else if (outputType.GetElementType() == typeof(sbyte))
{
Ch.Assert(colType.ItemType == NumberType.I1);
return CreateConvertingArrayGetterDelegate<sbyte, DvInt1>(index, x => x);
}
else if (outputType.GetElementType() == typeof(sbyte?))
{
Ch.Assert(colType.ItemType == NumberType.I1);
return CreateConvertingArrayGetterDelegate<sbyte?, DvInt1>(index, x => x ?? DvInt1.NA);
return CreateConvertingArrayGetterDelegate<sbyte, sbyte>(index, x => x);
}
else if (outputType.GetElementType() == typeof(bool))
{
Expand Down Expand Up @@ -222,51 +202,27 @@ private Delegate CreateGetter(int index)
}
else if (outputType == typeof(int))
{
// int -> DvInt4
// int -> int
Ch.Assert(colType == NumberType.I4);
return CreateConvertingGetterDelegate<int, DvInt4>(index, x => x);
}
else if (outputType == typeof(int?))
{
// int? -> DvInt4
Ch.Assert(colType == NumberType.I4);
return CreateConvertingGetterDelegate<int?, DvInt4>(index, x => x ?? DvInt4.NA);
return CreateConvertingGetterDelegate<int, int>(index, x => x);
}
else if (outputType == typeof(short))
{
// short -> DvInt2
Ch.Assert(colType == NumberType.I2);
return CreateConvertingGetterDelegate<short, DvInt2>(index, x => x);
}
else if (outputType == typeof(short?))
{
// short? -> DvInt2
// short -> short
Ch.Assert(colType == NumberType.I2);
return CreateConvertingGetterDelegate<short?, DvInt2>(index, x => x ?? DvInt2.NA);
return CreateConvertingGetterDelegate<short, short>(index, x => x);
}
else if (outputType == typeof(long))
{
// long -> DvInt8
// long -> long
Ch.Assert(colType == NumberType.I8);
return CreateConvertingGetterDelegate<long, DvInt8>(index, x => x);
}
else if (outputType == typeof(long?))
{
// long? -> DvInt8
Ch.Assert(colType == NumberType.I8);
return CreateConvertingGetterDelegate<long?, DvInt8>(index, x => x ?? DvInt8.NA);
return CreateConvertingGetterDelegate<long, long>(index, x => x);
}
else if (outputType == typeof(sbyte))
{
// sbyte -> DvInt1
Ch.Assert(colType == NumberType.I1);
return CreateConvertingGetterDelegate<sbyte, DvInt1>(index, x => x);
}
else if (outputType == typeof(sbyte?))
{
// sbyte? -> DvInt1
// sbyte -> sbyte
Ch.Assert(colType == NumberType.I1);
return CreateConvertingGetterDelegate<sbyte?, DvInt1>(index, x => x ?? DvInt1.NA);
return CreateConvertingGetterDelegate<sbyte, sbyte>(index, x => x);
}
// T -> T
if (outputType.IsGenericType && outputType.GetGenericTypeDefinition() == typeof(Nullable<>))
Expand Down
60 changes: 8 additions & 52 deletions src/Microsoft.ML.Api/TypedCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,42 +292,22 @@ private Action<TRow> GenerateSetter(IRow input, int index, InternalSchemaDefinit
else if (fieldType.GetElementType() == typeof(int))
{
Ch.Assert(colType.ItemType == NumberType.I4);
return CreateConvertingVBufferSetter<DvInt4, int>(input, index, poke, peek, x => (int)x);
}
else if (fieldType.GetElementType() == typeof(int?))
{
Ch.Assert(colType.ItemType == NumberType.I4);
return CreateConvertingVBufferSetter<DvInt4, int?>(input, index, poke, peek, x => (int?)x);
return CreateConvertingVBufferSetter<int, int>(input, index, poke, peek, x => (int)x);
Copy link
Contributor

@TomFinley TomFinley Aug 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return CreateConvertingVBufferSetter<int, int>(input, index, poke, peek, x => (int)x); [](start = 24, length = 86)

These were previously necessary when the types are different. Why are they necessary now? For example I definitely do not see things for float or double in this list. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, this was a miss. No need for this conversion.


In reply to: 212031778 [](ancestors = 212031778)

}
else if (fieldType.GetElementType() == typeof(short))
{
Ch.Assert(colType.ItemType == NumberType.I2);
return CreateConvertingVBufferSetter<DvInt2, short>(input, index, poke, peek, x => (short)x);
}
else if (fieldType.GetElementType() == typeof(short?))
{
Ch.Assert(colType.ItemType == NumberType.I2);
return CreateConvertingVBufferSetter<DvInt2, short?>(input, index, poke, peek, x => (short?)x);
return CreateConvertingVBufferSetter<short, short>(input, index, poke, peek, x => x);
}
else if (fieldType.GetElementType() == typeof(long))
{
Ch.Assert(colType.ItemType == NumberType.I8);
return CreateConvertingVBufferSetter<DvInt8, long>(input, index, poke, peek, x => (long)x);
}
else if (fieldType.GetElementType() == typeof(long?))
{
Ch.Assert(colType.ItemType == NumberType.I8);
return CreateConvertingVBufferSetter<DvInt8, long?>(input, index, poke, peek, x => (long?)x);
return CreateConvertingVBufferSetter<long, long>(input, index, poke, peek, x => x);
}
else if (fieldType.GetElementType() == typeof(sbyte))
{
Ch.Assert(colType.ItemType == NumberType.I1);
return CreateConvertingVBufferSetter<DvInt1, sbyte>(input, index, poke, peek, x => (sbyte)x);
}
else if (fieldType.GetElementType() == typeof(sbyte?))
{
Ch.Assert(colType.ItemType == NumberType.I1);
return CreateConvertingVBufferSetter<DvInt1, sbyte?>(input, index, poke, peek, x => (sbyte?)x);
return CreateConvertingVBufferSetter<sbyte, sbyte>(input, index, poke, peek, x => x);
}

// VBuffer<T> -> T[]
Expand Down Expand Up @@ -373,49 +353,25 @@ private Action<TRow> GenerateSetter(IRow input, int index, InternalSchemaDefinit
{
Ch.Assert(colType == NumberType.I4);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt4, int>(input, index, poke, x => (int)x);
}
else if (fieldType == typeof(int?))
{
Ch.Assert(colType == NumberType.I4);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt4, int?>(input, index, poke, x => (int?)x);
return CreateConvertingActionSetter<int, int>(input, index, poke, x => x);
}
else if (fieldType == typeof(short))
{
Ch.Assert(colType == NumberType.I2);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt2, short>(input, index, poke, x => (short)x);
}
else if (fieldType == typeof(short?))
{
Ch.Assert(colType == NumberType.I2);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt2, short?>(input, index, poke, x => (short?)x);
return CreateConvertingActionSetter<short, short>(input, index, poke, x => x);
}
else if (fieldType == typeof(long))
{
Ch.Assert(colType == NumberType.I8);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt8, long>(input, index, poke, x => (long)x);
}
else if (fieldType == typeof(long?))
{
Ch.Assert(colType == NumberType.I8);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt8, long?>(input, index, poke, x => (long?)x);
return CreateConvertingActionSetter<long, long>(input, index, poke, x => x);
}
else if (fieldType == typeof(sbyte))
{
Ch.Assert(colType == NumberType.I1);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt1, sbyte>(input, index, poke, x => (sbyte)x);
}
else if (fieldType == typeof(sbyte?))
{
Ch.Assert(colType == NumberType.I1);
Ch.Assert(peek == null);
return CreateConvertingActionSetter<DvInt1, sbyte?>(input, index, poke, x => (sbyte?)x);
return CreateConvertingActionSetter<sbyte, sbyte>(input, index, poke, x => x);
}
// T -> T
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
Expand Down
14 changes: 7 additions & 7 deletions src/Microsoft.ML.Core/CommandLine/CmdParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,23 +517,23 @@ public static int GetConsoleWindowWidth()

private struct Coord
{
internal Int16 X;
internal Int16 Y;
internal short X;
internal short Y;
}

private struct SmallRect
{
internal Int16 Left;
internal Int16 Top;
internal Int16 Right;
internal Int16 Bottom;
internal short Left;
internal short Top;
internal short Right;
internal short Bottom;
}

private struct ConsoleScreenBufferInfo
{
internal Coord DwSize;
internal Coord DwCursorPosition;
internal Int16 WAttributes;
internal short WAttributes;
internal SmallRect SrWindow;
internal Coord DwMaximumWindowSize;
}
Expand Down
12 changes: 8 additions & 4 deletions src/Microsoft.ML.Core/Data/ColumnType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -567,14 +567,18 @@ public static BoolType Instance
get
{
if (_instance == null)
Interlocked.CompareExchange(ref _instance, new BoolType(), null);
Interlocked.CompareExchange(ref _instance, new BoolType(DataKind.BL, "Bool"), null);
return _instance;
}
}

private BoolType()
: base(typeof(DvBool), DataKind.BL)
private readonly string _name;

Copy link
Contributor

@TomFinley TomFinley Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm. What's this for? Is it still relevant? #Closed

private BoolType(DataKind kind, string name)
: base(kind.ToType(), kind)
{
Contracts.AssertNonEmpty(name);
_name = name;
}

public override bool Equals(ColumnType other)
Expand All @@ -587,7 +591,7 @@ public override bool Equals(ColumnType other)

public override string ToString()
{
return "Bool";
return _name;
}
}

Expand Down
28 changes: 14 additions & 14 deletions src/Microsoft.ML.Core/Data/DataKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public enum DataKind : byte
public static class DataKindExtensions
{
public const DataKind KindMin = DataKind.I1;
public const DataKind KindLim = DataKind.UG + 1;
public const DataKind KindLim = DataKind.U16 + 1;
public const int KindCount = KindLim - KindMin;

/// <summary>
Expand Down Expand Up @@ -141,19 +141,19 @@ public static Type ToType(this DataKind kind)
switch (kind)
{
case DataKind.I1:
return typeof(DvInt1);
return typeof(sbyte);
case DataKind.U1:
return typeof(byte);
case DataKind.I2:
return typeof(DvInt2);
return typeof(short);
case DataKind.U2:
return typeof(ushort);
case DataKind.I4:
return typeof(DvInt4);
return typeof(int);
case DataKind.U4:
return typeof(uint);
case DataKind.I8:
return typeof(DvInt8);
return typeof(long);
case DataKind.U8:
return typeof(ulong);
case DataKind.R4:
Expand Down Expand Up @@ -185,25 +185,25 @@ public static bool TryGetDataKind(this Type type, out DataKind kind)
Contracts.CheckValueOrNull(type);

// REVIEW: Make this more efficient. Should we have a global dictionary?
if (type == typeof(DvInt1) || type == typeof(sbyte) || type == typeof(sbyte?))
if (type == typeof(sbyte))
kind = DataKind.I1;
else if (type == typeof(byte) || type == typeof(byte?))
Copy link
Member

@eerhardt eerhardt Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

byte? should be removed here as well, to follow the rest of the changes. #Resolved

Copy link
Member Author

@codemzs codemzs Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is "byte?" mapped to a U1? I thought U1 just mapped to a byte and did not support nullables ....this needs to go away anyways


In reply to: 210963225 [](ancestors = 210963225)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone made a mistake somewhere, didn't realize this was supposed to be inverse to above function. Who knows who, but we ought to correct now.


In reply to: 210965477 [](ancestors = 210965477,210963225)

kind = DataKind.U1;
else if (type == typeof(DvInt2)|| type== typeof(short) || type == typeof(short?))
else if (type == typeof(short))
kind = DataKind.I2;
else if (type == typeof(ushort)|| type == typeof(ushort?))
else if (type == typeof(ushort) || type == typeof(ushort?))
kind = DataKind.U2;
else if (type == typeof(DvInt4) || type == typeof(int)|| type == typeof(int?))
else if (type == typeof(int))
kind = DataKind.I4;
else if (type == typeof(uint)|| type == typeof(uint?))
else if (type == typeof(uint) || type == typeof(uint?))
kind = DataKind.U4;
else if (type == typeof(DvInt8) || type==typeof(long)|| type == typeof(long?))
else if (type == typeof(long))
kind = DataKind.I8;
else if (type == typeof(ulong)|| type == typeof(ulong?))
else if (type == typeof(ulong) || type == typeof(ulong?))
Copy link
Contributor

@TomFinley TomFinley Aug 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|| type == typeof(ulong?)) [](start = 42, length = 27)

The use of nulltable types for the unsigned types seems wrong. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this entire function is wrong. This is meant to be an inverse to the function above. Didn't we already talk about this in a prior PR months ago?


In reply to: 211039836 [](ancestors = 211039836)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So: please remove all mentions of any types (whether nullable or not) that do not appear in the earlier function. However probably there's some code somewhere that relied on that change, try to figure out what it was, and fix it to use its own utility function.


In reply to: 211040069 [](ancestors = 211040069,211039836)

Copy link
Member Author

@codemzs codemzs Aug 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TomFinley, I believe this was added by @Ivanidzo4ka in #555 and you also approved that PR. I agree nullables here is wrong and I will remove them all. #Resolved

Copy link
Contributor

@TomFinley TomFinley Aug 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://getyarn.io/yarn-clip/fc2be4a1-ca56-450b-8cbb-f771207b3df1

Anyway good. Not just the nullables but all but the single correct type. 😄 #Closed

kind = DataKind.U8;
else if (type == typeof(Single)|| type == typeof(Single?))
else if (type == typeof(Single) || type == typeof(Single?))
kind = DataKind.R4;
else if (type == typeof(Double)|| type == typeof(Double?))
else if (type == typeof(Double) || type == typeof(Double?))
kind = DataKind.R8;
else if (type == typeof(DvText))
kind = DataKind.TX;
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.ML.Core/Data/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ private static DvDateTime ValidateDate(DvDateTime dateTime, ref DvInt2 offset)
Contracts.Assert(MinMinutesOffset <= offset.RawValue && offset.RawValue <= MaxMinutesOffset);
var offsetTicks = offset.RawValue * TicksPerMinute;
// This operation cannot overflow because offset should have already been validated to be within
// 14 hours and the DateTime instance is more than that distance from the boundaries of Int64.
// 14 hours and the DateTime instance is more than that distance from the boundaries of long.
long utcTicks = dateTime.Ticks.RawValue - offsetTicks;
var dvdt = new DvDateTime(utcTicks);
if (dvdt.IsNA)
Expand Down
Loading