Skip to content

Commit

Permalink
ARROW-16660: [C#] Add support for Time32Array and Time64Array (apache…
Browse files Browse the repository at this point in the history
…#13279)

Implemented support without using TImespan in C# as it cannot hold values that have the resolution in microseconds & nanoseconds as specified on the Jira.

Lead-authored-by: Rishabh Rana <[email protected]>
Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: ranarish <[email protected]>
Signed-off-by: Eric Erhardt <[email protected]>
  • Loading branch information
3 people authored Jun 14, 2022
1 parent 5b859fd commit 6a936c4
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 11 deletions.
6 changes: 4 additions & 2 deletions csharp/src/Apache.Arrow/Arrays/ArrowArrayBuilderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ internal static IArrowArrayBuilder<IArrowArray, IArrowArrayBuilder<IArrowArray>>
return new Date64Array.Builder();
case ArrowTypeId.Date32:
return new Date32Array.Builder();
case ArrowTypeId.Time32:
return new Time32Array.Builder(dataType as Time32Type);
case ArrowTypeId.Time64:
return new Time64Array.Builder(dataType as Time64Type);
case ArrowTypeId.List:
return new ListArray.Builder(dataType as ListType);
case ArrowTypeId.Decimal128:
Expand All @@ -69,8 +73,6 @@ internal static IArrowArrayBuilder<IArrowArray, IArrowArrayBuilder<IArrowArray>>
case ArrowTypeId.HalfFloat:
case ArrowTypeId.Interval:
case ArrowTypeId.Map:
case ArrowTypeId.Time32:
case ArrowTypeId.Time64:
default:
throw new NotSupportedException($"An ArrowArrayBuilder cannot be built for type {dataType.TypeId}.");
}
Expand Down
6 changes: 4 additions & 2 deletions csharp/src/Apache.Arrow/Arrays/ArrowArrayFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public static IArrowArray BuildArray(ArrayData data)
return new Date64Array(data);
case ArrowTypeId.Date32:
return new Date32Array(data);
case ArrowTypeId.Time32:
return new Time32Array(data);
case ArrowTypeId.Time64:
return new Time64Array(data);
case ArrowTypeId.Decimal128:
return new Decimal128Array(data);
case ArrowTypeId.Decimal256:
Expand All @@ -74,8 +78,6 @@ public static IArrowArray BuildArray(ArrayData data)
case ArrowTypeId.HalfFloat:
case ArrowTypeId.Interval:
case ArrowTypeId.Map:
case ArrowTypeId.Time32:
case ArrowTypeId.Time64:
default:
throw new NotSupportedException($"An ArrowArray cannot be built for type {data.DataType.TypeId}.");
}
Expand Down
117 changes: 117 additions & 0 deletions csharp/src/Apache.Arrow/Arrays/Time32Array.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Licensed to the Apache Software Foundation (ASF) under one or moreDate32Array
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Apache.Arrow.Types;
using System.IO;

namespace Apache.Arrow
{
/// <summary>
/// The <see cref="Time32Array"/> class holds an array of <see cref="Int32" />, where each value is
/// stored as the number of seconds/ milliseconds (depending on the Time32Type) since midnight.
/// </summary>
public class Time32Array : PrimitiveArray<int>
{
/// <summary>
/// The <see cref="Builder"/> class can be used to fluently build <see cref="Time32Array"/> objects.
/// </summary>
public class Builder : PrimitiveArrayBuilder<int, Time32Array, Builder>
{
protected override Time32Array Build(
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset) =>
new Time32Array(DataType, valueBuffer, nullBitmapBuffer, length, nullCount, offset);

protected Time32Type DataType { get; }

public Builder()
: this(Time32Type.Default) { }

public Builder(TimeUnit unit)
: this(new Time32Type(unit)) { }

/// <summary>
/// Construct a new instance of the <see cref="Builder"/> class.
/// </summary>
public Builder(Time32Type type)
: base()
{
DataType = type;
}
}

public Time32Array(
Time32Type type,
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset)
: this(new ArrayData(type, length, nullCount, offset,
new[] { nullBitmapBuffer, valueBuffer }))
{ }

public Time32Array(ArrayData data)
: base(data)
{
data.EnsureDataType(ArrowTypeId.Time32);
}

public override void Accept(IArrowArrayVisitor visitor) => Accept(this, visitor);

/// <summary>
/// Get the time at the specified index as seconds
/// </summary>
/// <param name="index">Index at which to get the time.</param>
/// <returns>Returns an <see cref="Int32" />, or <c>null</c> if there is no object at that index.
/// </returns>
public int? GetSeconds(int index)
{
int? value = GetValue(index);
if (value == null)
{
return null;
}

var unit = ((Time32Type) Data.DataType).Unit;
return unit switch
{
TimeUnit.Second => value,
TimeUnit.Millisecond => value / 1_000,
_ => throw new InvalidDataException($"Unsupported time unit for Time32Type: {unit}")
};
}

/// <summary>
/// Get the time at the specified index as milliseconds
/// </summary>
/// <param name="index">Index at which to get the time.</param>
/// <returns>Returns an <see cref="Int32" />, or <c>null</c> if there is no object at that index.
/// </returns>
public int? GetMilliSeconds(int index)
{
int? value = GetValue(index);
if (value == null)
{
return null;
}

var unit = ((Time32Type)Data.DataType).Unit;
return unit switch
{
TimeUnit.Second => value * 1_000,
TimeUnit.Millisecond => value,
_ => throw new InvalidDataException($"Unsupported time unit for Time32Type: {unit}")
};
}
}
}
117 changes: 117 additions & 0 deletions csharp/src/Apache.Arrow/Arrays/Time64Array.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Licensed to the Apache Software Foundation (ASF) under one or moreDate32Array
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Apache.Arrow.Types;
using System.IO;

namespace Apache.Arrow
{
/// <summary>
/// The <see cref="Time64Array"/> class holds an array of <see cref="Int64" />, where each value is
/// stored as the number of microseconds/nanoseconds (depending on the Time64Type) since midnight.
/// </summary>
public class Time64Array : PrimitiveArray<long>
{
/// <summary>
/// The <see cref="Builder"/> class can be used to fluently build <see cref="Time64Array"/> objects.
/// </summary>
public class Builder : PrimitiveArrayBuilder<long, Time64Array, Builder>
{
protected override Time64Array Build(
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset) =>
new Time64Array(DataType, valueBuffer, nullBitmapBuffer, length, nullCount, offset);

protected Time64Type DataType { get; }

public Builder()
: this(Time64Type.Default) { }

public Builder(TimeUnit unit)
: this(new Time64Type(unit)) { }

/// <summary>
/// Construct a new instance of the <see cref="Builder"/> class.
/// </summary>
public Builder(Time64Type type)
: base()
{
DataType = type;
}
}

public Time64Array(
Time64Type type,
ArrowBuffer valueBuffer, ArrowBuffer nullBitmapBuffer,
int length, int nullCount, int offset)
: this(new ArrayData(type, length, nullCount, offset,
new[] { nullBitmapBuffer, valueBuffer }))
{ }

public Time64Array(ArrayData data)
: base(data)
{
data.EnsureDataType(ArrowTypeId.Time64);
}

public override void Accept(IArrowArrayVisitor visitor) => Accept(this, visitor);

/// <summary>
/// Get the time at the specified index as microseconds
/// </summary>
/// <param name="index">Index at which to get the time.</param>
/// <returns>Returns a <see cref="Int64" />, or <c>null</c> if there is no object at that index.
/// </returns>
public long? GetMicroSeconds(int index)
{
long? value = GetValue(index);
if (value == null)
{
return null;
}

var unit = ((Time64Type)Data.DataType).Unit;
return unit switch
{
TimeUnit.Microsecond => value,
TimeUnit.Nanosecond => value / 1_000,
_ => throw new InvalidDataException($"Unsupported time unit for Time64Type: {unit}")
};
}

/// <summary>
/// Get the time at the specified index as nanoseconds
/// </summary>
/// <param name="index">Index at which to get the time.</param>
/// <returns>Returns a <see cref="Int64" />, or <c>null</c> if there is no object at that index.
/// </returns>
public long? GetNanoSeconds(int index)
{
long? value = GetValue(index);
if (value == null)
{
return null;
}

var unit = ((Time64Type)Data.DataType).Unit;
return unit switch
{
TimeUnit.Microsecond => value * 1_000,
TimeUnit.Nanosecond => value,
_ => throw new InvalidDataException($"Unsupported time unit for Time64Type: {unit}")
};
}
}
}
4 changes: 4 additions & 0 deletions csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ internal class ArrowRecordBatchFlatBufferBuilder :
IArrowArrayVisitor<TimestampArray>,
IArrowArrayVisitor<Date32Array>,
IArrowArrayVisitor<Date64Array>,
IArrowArrayVisitor<Time32Array>,
IArrowArrayVisitor<Time64Array>,
IArrowArrayVisitor<ListArray>,
IArrowArrayVisitor<StringArray>,
IArrowArrayVisitor<BinaryArray>,
Expand Down Expand Up @@ -91,6 +93,8 @@ public ArrowRecordBatchFlatBufferBuilder()
public void Visit(BooleanArray array) => CreateBuffers(array);
public void Visit(Date32Array array) => CreateBuffers(array);
public void Visit(Date64Array array) => CreateBuffers(array);
public void Visit(Time32Array array) => CreateBuffers(array);
public void Visit(Time64Array array) => CreateBuffers(array);

public void Visit(ListArray array)
{
Expand Down
8 changes: 8 additions & 0 deletions csharp/src/Apache.Arrow/RecordBatch.Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public Decimal256Array Decimal256(Decimal256Type type, Action<Decimal256Array.Bu
new Decimal256Array.Builder(type), action);
public Date32Array Date32(Action<Date32Array.Builder> action) => Build<Date32Array, Date32Array.Builder>(new Date32Array.Builder(), action);
public Date64Array Date64(Action<Date64Array.Builder> action) => Build<Date64Array, Date64Array.Builder>(new Date64Array.Builder(), action);
public Time32Array Time32(Action<Time32Array.Builder> action) => Build<Time32Array, Time32Array.Builder>(new Time32Array.Builder(), action);
public Time32Array Time32(Time32Type type, Action<Time32Array.Builder> action) =>
Build<Time32Array, Time32Array.Builder>(
new Time32Array.Builder(type), action);
public Time64Array Time64(Action<Time64Array.Builder> action) => Build<Time64Array, Time64Array.Builder>(new Time64Array.Builder(), action);
public Time64Array Time64(Time64Type type, Action<Time64Array.Builder> action) =>
Build<Time64Array, Time64Array.Builder>(
new Time64Array.Builder(type), action);
public BinaryArray Binary(Action<BinaryArray.Builder> action) => Build<BinaryArray, BinaryArray.Builder>(new BinaryArray.Builder(), action);
public StringArray String(Action<StringArray.Builder> action) => Build<StringArray, StringArray.Builder>(new StringArray.Builder(), action);
public TimestampArray Timestamp(Action<TimestampArray.Builder> action) => Build<TimestampArray, TimestampArray.Builder>(new TimestampArray.Builder(), action);
Expand Down
20 changes: 19 additions & 1 deletion csharp/test/Apache.Arrow.IntegrationTest/IntegrationCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ private class ArrayCreator :
IArrowTypeVisitor<Decimal256Type>,
IArrowTypeVisitor<Date32Type>,
IArrowTypeVisitor<Date64Type>,
IArrowTypeVisitor<Time32Type>,
IArrowTypeVisitor<Time64Type>,
IArrowTypeVisitor<TimestampType>,
IArrowTypeVisitor<StringType>,
IArrowTypeVisitor<BinaryType>,
Expand Down Expand Up @@ -310,6 +312,8 @@ public void Visit(BooleanType type)
public void Visit(UInt64Type type) => GenerateLongArray<ulong, UInt64Array>((v, n, c, nc, o) => new UInt64Array(v, n, c, nc, o), s => ulong.Parse(s));
public void Visit(FloatType type) => GenerateArray<float, FloatArray>((v, n, c, nc, o) => new FloatArray(v, n, c, nc, o));
public void Visit(DoubleType type) => GenerateArray<double, DoubleArray>((v, n, c, nc, o) => new DoubleArray(v, n, c, nc, o));
public void Visit(Time32Type type) => GenerateArray<int, Time32Array>((v, n, c, nc, o) => new Time32Array(type, v, n, c, nc, o));
public void Visit(Time64Type type) => GenerateLongArray<long, Time64Array>((v, n, c, nc, o) => new Time64Array(type, v, n, c, nc, o), s => long.Parse(s));

public void Visit(Decimal128Type type)
{
Expand Down Expand Up @@ -393,7 +397,21 @@ public void Visit(Date64Type type)

public void Visit(TimestampType type)
{
throw new NotImplementedException();
ArrowBuffer validityBuffer = GetValidityBuffer(out int nullCount);

ArrowBuffer.Builder<long> valueBuilder = new ArrowBuffer.Builder<long>(JsonFieldData.Count);
var json = JsonFieldData.Data.GetRawText();
string[] values = JsonSerializer.Deserialize<string[]>(json, s_options);

foreach (string value in values)
{
valueBuilder.Append(long.Parse(value));
}
ArrowBuffer valueBuffer = valueBuilder.Build();

Array = new TimestampArray(
type, valueBuffer, validityBuffer,
JsonFieldData.Count, nullCount, 0);
}

public void Visit(StringType type)
Expand Down
Loading

0 comments on commit 6a936c4

Please sign in to comment.