[ 
https://issues.apache.org/jira/browse/ARROW-8581?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

ASF GitHub Bot updated ARROW-8581:
----------------------------------
    Labels: pull-request-available  (was: )

> [C#] Date32/64Array.Builder should accept DateTime, not DateTimeOffset
> ----------------------------------------------------------------------
>
>                 Key: ARROW-8581
>                 URL: https://issues.apache.org/jira/browse/ARROW-8581
>             Project: Apache Arrow
>          Issue Type: Improvement
>          Components: C#
>    Affects Versions: 0.17.0
>            Reporter: Adam Szmigin
>            Priority: Major
>              Labels: pull-request-available
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> h1. Summary Proposal
> The {{Date32Array.Builder}} and {{Date64.Builder}} classes both accept values 
> of type {{DateTimeOffset}}, but this makes it very easy for the user to 
> introduce subtle bugs when they work with the {{DateTime}} type in their own 
> code.  This class of bugs could be avoided if these builders were instead 
> typed on {{DateTime}} rather than {{DateTimeOffset}}.
> h1. Details
> The danger is introduced by the implicit widening conversion provided by the 
> _DateTimeOffset.Implicit(DateTime to DateTimeOffset)_ operator:
>  
> [https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset.op_implicit?view=netcore-3.1]
> The important part is this text:
> {quote}The offset of the resulting DateTimeOffset object depends on the value 
> of the DateTime.Kind property of the dateTime parameter:
>  * If the value of the DateTime.Kind property is DateTimeKind.Local or 
> DateTimeKind.Unspecified, the date and time of the DateTimeOffset object is 
> set equal to dateTime, and its Offset property *is set equal to the offset of 
> the local system's current time zone*.{quote}
>  (Emphasis mine)
>  If the user is operating in an environment with a positive GMT offset, it is 
> very easy to write the wrong date to the builder:
> {code:c#}
> Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow)); // Bug 
> triggers if > 00:00:00
> var builder = new Date32Array.Builder();
> builder.Append(new DateTime(2020, 4, 24)); // Kind == DateTimeKind.Unspecified
> var allocator = new NativeMemoryAllocator();
> Console.WriteLine(builder.Build(allocator).GetDate(0)); // Prints 2020-04-23!
> {code}
> Assume that the user is in the UK (as I am), where the GMT offset on the 
> above date is 1 hour ahead.  This means that the conversion to 
> {{DateTimeOffset}} will actually result in a value of 
> {{2020-04-23T23:00:00+01:00}} being passed to the {{Append()}} method.  Arrow 
> then calls {{ToUnixTimeMilliseconds()}}, which [only considers the date 
> portion|https://referencesource.microsoft.com/#mscorlib/system/datetimeoffset.cs,8f33340c07c4787e]
>  of its object, not the time portion or offset.  This means that the number 
> of days gets calculated based on 2020-04-23, not 2020-04-24 as the user 
> thought they were specifying.
> If the user chooses to use NodaTime as a "better" date and time-handling 
> library, they will still likely run into the bug if they do the obvious thing:
> {code:c#}
> Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow)); // Bug 
> triggers if > 00:00:00
> var builder = new Date32Array.Builder();
> var ld = new NodaTime.LocalDate(2020, 4, 24);
> builder.Append(ld.ToDateTimeUnspecified()); // Kind == 
> DateTimeKind.Unspecified
> var allocator = new NativeMemoryAllocator();
> Console.WriteLine(builder.Build(allocator).GetDate(0)); // Prints 2020-04-23!
> {code}
> h1. Suggested Improvement
>  * Change {{Date32Array.Builder}} and {{Date64Array.Builder}} to specify a 
> {{TFrom}} parameter of {{DateTime}}, not {{DateTimeOffset}} (breaking change).
>  * Change {{Date32Array.GetDate()}} and {{Date64Array.GetDate()}} to return a 
> {{DateTime}}, not {{DateTimeOffset}} (also a breaking change).
>  
> The conversion method for a {{Date32Array}} would then look a bit like this:
> {code:c#}
> private static readonly DateTime Epoch = new DateTime(1970, 1, 1);
> protected override int ConvertTo(DateTime value)
> {
>     return (int)(value - Epoch).TotalDays;
> } {code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to