-
Notifications
You must be signed in to change notification settings - Fork 0
/
DateTimeRange.cs
130 lines (116 loc) · 4.84 KB
/
DateTimeRange.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System;
using System.Text;
namespace CK.Core;
/// <summary>
/// Models an absolute time range. This can only be obtained by <see cref="WeakTimeSpan.GetDateTimeRange(DateTime)"/>
/// or by <see cref="WeakTimeSpan.GetDateTimeRange(long, DateTimeKind)"/> when the <see cref="WeakTimeSpan.IsEraligned"/> is true.
/// <para>
/// This is a 128 bits value type that contains the <see cref="Start"/> and the <see cref="Span"/>.
/// <see cref="Index"/> and <see cref="End"/> are computed properties.
/// </para>
/// <para>
/// A <c>default</c> value of this type is the only invalid value of this type.
/// </para>
/// </summary>
public readonly struct DateTimeRange
{
readonly DateTime _start;
readonly WeakTimeSpan _span;
internal DateTimeRange( DateTime start, WeakTimeSpan span )
{
_start = start;
_span = span;
}
/// <summary>
/// Gets whether this is a valid range.
/// Only the <c>default</c> value is invalid.
/// </summary>
public bool IsValid => _span.IsValid;
/// <summary>
/// Gets the start of this range.
/// </summary>
public DateTime Start => _start;
/// <summary>
/// Gets the description of this range.
/// </summary>
public WeakTimeSpan Span => _span;
/// <summary>
/// Gets the end of this range. This end is excluded (it is the start of the next range).
/// <para>
/// This property is not stored, it is recomputed from the <see cref="Span"/> and <see cref="Start"/>.
/// </para>
/// </summary>
public DateTime End => _span.Unit.GetStart( _start, _span.Count );
/// <summary>
/// Gets whether a <paramref name="dateTime"/> is in this range.
/// </summary>
/// <param name="dateTime">The DateTime.</param>
/// <returns>Whether the DateTime is contained in this range.</returns>
public bool Contains( DateTime dateTime ) => Start <= dateTime && dateTime < End;
/// <summary>
/// Gets whether another range is the same or is contained in this range.
/// </summary>
/// <param name="other">The DateTime.</param>
/// <returns>Whether the DateTime is contained in this range.</returns>
public bool Contains( DateTimeRange other ) => Start <= other.Start && other.End <= End;
/// <summary>
/// Gets the index of this <see cref="DateTimeRange"/>.
/// <para>
/// This property is not stored, it is recomputed from the <see cref="Span"/> and <see cref="Start"/>.
/// </para>
/// </summary>
public long Index
{
get
{
var (u, c) = _span;
return u switch
{
TimeSpanUnit.Year => (_start.Year - 1) / c,
// For Semester and Quarter, c == 1 (normalized to Semester or Year).
TimeSpanUnit.Semester => ((_start.Year - 1) << 1) + (_start.Month > 6 ? 1 : 0),
TimeSpanUnit.Quarter => ((_start.Year - 1) << 2) + (_start.Month - 1) / 3,
TimeSpanUnit.Month => ((_start.Year - 1) * 12 + _start.Month - 1) / c,
TimeSpanUnit.Day => (_start.Ticks / TimeSpan.TicksPerDay) / c,
TimeSpanUnit.Hour => (_start.Ticks / TimeSpan.TicksPerHour) / c,
TimeSpanUnit.Minute => (_start.Ticks / TimeSpan.TicksPerMinute) / c,
TimeSpanUnit.Second => (_start.Ticks / TimeSpan.TicksPerSecond) / c,
TimeSpanUnit.Millisecond => (_start.Ticks / TimeSpan.TicksPerMillisecond) / c,
_ => Throw.CKException<long>( "Unreachable" )
};
}
}
/// <summary>
/// Overridden to return the "[start,end[".
/// </summary>
/// <returns>A readable string.</returns>
public override string ToString() => ToString( _span.Unit, _start, End );
/// <summary>
/// Helper that writes a date range "[start,end[".
/// </summary>
/// <param name="unit">The precision to use.</param>
/// <param name="start">The start of the range.</param>
/// <param name="end">The end of the range.</param>
/// <returns>A readable string.</returns>
public static string ToString( TimeSpanUnit unit, DateTime start, DateTime end )
{
return WriteRange( new StringBuilder(), unit, start, end ).ToString();
}
/// <summary>
/// Helper that writes a date range "[start,end[".
/// </summary>
/// <param name="b">The builder to use.</param>
/// <param name="unit">The precision to use.</param>
/// <param name="start">The start of the range.</param>
/// <param name="end">The end of the range.</param>
/// <returns>The builder.</returns>
public static StringBuilder WriteRange( StringBuilder b, TimeSpanUnit unit, DateTime start, DateTime end )
{
b.Append( '[' );
TimeSpanUnitPathPart.None.WritePath( b, start, unit );
b.Append( ',' );
TimeSpanUnitPathPart.None.WritePath( b, end, unit );
b.Append( '[' );
return b;
}
}