Runtime: Deconstruct for DateTime / TimeSpan / DateTimeOffset

Created on 7 Jan 2018  路  13Comments  路  Source: dotnet/runtime

_From @panost on January 7, 2018 13:42_

For example method https://github.com/dotnet/coreclr/blob/0efe34efa69dea7f9b94ddc8251810e0a264671c/src/mscorlib/shared/System/DateTime.cs#L847

could be made public and renamed to Deconstruct, so we can write

var (year,month,day) = DateTime.Now;

The same pattern can be applied to DateTimeOffset and TimeSpan

_Copied from original issue: dotnet/coreclr#15776_

api-suggestion area-System.Runtime

All 13 comments

I would be happy to get a year , month , day at the same time but won't it make confusion between (hour, minute, second) ? Isn't enough to set GetDatePart public?

@aobatact You can have Deconstuct overloads for example you can add

Deconstuct(out int year, out int month, out int day, out int hour, out int minute, out int second, out int milliSecond);
Deconstuct(out int year, out int month, out int day, out int hour, out int minute, out second);

but if you only care for the TimeOfDay parts then an additional method is needed such as

public static void GetTimeOfDayParts( this DateTime dt, out int hour, out int minute, out int second, out int milliSecond ) {
    const int MilliSecondsInSecond = 1000;
    const int MilliSecondsInMinute = 60 * MilliSecondsInSecond;
    const int MilliSecondsInHour = 60 * MilliSecondsInMinute;

    milliSecond = (int)( ( dt.Ticks % TimeSpan.TicksPerDay ) / TimeSpan.TicksPerMillisecond );
    hour = milliSecond / MilliSecondsInHour;
    milliSecond -= hour * MilliSecondsInHour;
    minute = milliSecond / MilliSecondsInMinute;
    milliSecond -= minute * MilliSecondsInMinute;
    second = milliSecond / MilliSecondsInSecond;
    milliSecond -= second * MilliSecondsInSecond;
}

// tuple overload
public static (int hour, int minute, int second, int milliSecond) GetTimeOfDayParts( this DateTime dt ) {
    (int hour, int minute, int second, int milliSecond) tuple;

    GetTimeOfDayParts( dt, out tuple.hour, out tuple.minute, out tuple.second, out tuple.milliSecond );
    return tuple;
}

and use it as

var (hour, minute, second, _) = DateTime.Now.GetTimeOfDayParts();

I know that I can have ovreloads to it. My question is how the user know what values are deconstructed. As for other types that can Deconstruct like ValueTuple, Tuple, KeyValuePair, etc... , it is obvious which and what order they are deconsructed (they are deconstructing all the fields), but why can we say that deconstruct with three values means deconstruct to year, month, day ? Why not hour, minute, second ?

4
If the description of what values are deconstructed are shown in IDE it might be OK but currently I can't find a way for users to know.

Because you do know that DateTime doesn't have a constructor with 3 arguments that are hour,minute,seconds but only one that is year,month,day. The Deconstructor overloads should follow the signature of a public constructor if that's possible

Well , that's right. I wonder why I didn't come up with a constructor.

I just did this on my own in my project, I'd like to point out that this also helps with perf:

BenchmarkDotNet=v0.10.12, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=2742186 Hz, Resolution=364.6726 ns, Timer=TSC
.NET Core SDK=2.1.4
[Host] : .NET Core 2.0.5 (Framework 4.6.26020.03), 64bit RyuJIT
DefaultJob : .NET Core 2.0.5 (Framework 4.6.26020.03), 64bit RyuJIT

| Method | Mean | Error | StdDev | Scaled | ScaledSD |
|-------------- |----------:|----------:|----------:|-------:|---------:|
| BaseLine | 29.104 ns | 0.2917 ns | 0.2728 ns | 1.00 | 0.00 |
| Deconstructed | 9.834 ns | 0.2300 ns | 0.5978 ns | 0.34 | 0.02 |

I was actually about to open an issue about adding deconstruct in this form when I saw that it's already here...

Also, in my personal view, the DateTime deconstructor should be limited to (y, m d), where users wanting to deconstruct the time elements can use .TimeOfDay and deconstruct that in a separate call.

There would be very little performance impact for users only needing the (h, m, s) etc. elements in doing that, as it should be apparent from looking into the code...

Naturally DateTime can also provide the 6+ element deconstructor, but IMO it just looks unfriendly...

Could you please share code for your microbenchmark?

The results of the benchmark are expected, since the BaseLine calls the GetDatePart
three times (once for each Year,Month and Date). So BaseLine time =~ 3 * Deconstruct time

Also, in my personal view, the DateTime deconstructor should be limited to (y, m d), where users wanting to deconstruct the time elements can use .TimeOfDay and deconstruct that in a separate call.

If we were limited to only one I'd say the opposite, that we should have the fuller deconstruction since callers can choose to ignore what they don't need and it's the more flexible.

Luckily, we're not limited to only one.

@jkotas: https://github.com/damageboy/datetime-deconstruct

@panost right...

I also have a #if INSANE for doing magic number multiplication which for some reason works faster than what the JIT does in a consistent yet irrelevant way...

Moving this to 6.0 as it's not going to meet the deadline for 5.0. @panost are you still interested in this issue?

I just moved the issue to the right repo two years ago. I am not attached to this issue otherwise.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yahorsi picture yahorsi  路  3Comments

jzabroski picture jzabroski  路  3Comments

iCodeWebApps picture iCodeWebApps  路  3Comments

chunseoklee picture chunseoklee  路  3Comments

btecu picture btecu  路  3Comments