Skip to content

Commit f696b4a

Browse files
ADD : Period & ITimeBlock depuis Lucca
Récupération de ITimeBlock de Lucca, avec une approche légèrement différente. Plutôt que d'avoir toutes les propriétés de Period en get;set; on passe par des méthodes explicites pour changer les propriétés. Ceci permet à une classe de mettre de la logique métier dans ces méthodes, plus élégant je trouve que de mettre ça dans les setters. Ca permet aussi à une classe qui refuse qu'on lui change ses valeurs (immutabilité) de lancer des exceptions (ailleurs que dans le setter du coup) Implémentation de l'égalité entre 2 Periods. Quelques règles : - une Period ne peut pas être négative (end strictement plus petit que start), ça pète des tests sur le monolithe qui autorisait cette situation - la Duration peut ne pas être égale à end-start, notamment dans le cas d'UD avec une période correspond à une journée et une duration plus longue Remplacement de TimeInitials par une Culture, et reprise des traductions des initiales d'après ce qui est dans le monolithe PS : PR à suivre sur Lucca pour intégrer tout ça
1 parent 6a7bf8c commit f696b4a

File tree

7 files changed

+219
-20
lines changed

7 files changed

+219
-20
lines changed

NExtends.Tests/Primitives/DateTimes/PeriodTests.cs

+69-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using NExtends.Primitives.DateTimes;
22
using System;
3-
using System.Collections.Generic;
4-
using System.Text;
53
using Xunit;
64

75
namespace NExtends.Tests.Primitives.DateTimes
@@ -31,5 +29,74 @@ public void PeriodShouldWorkOnDateTimes()
3129
Assert.Equal(startsAt, period.Start);
3230
Assert.Equal(endsAt, period.End);
3331
}
32+
33+
[Fact]
34+
public void PeriodCannotBeNegative()
35+
{
36+
Assert.Throws<NegativeDurationException>(() =>
37+
{
38+
var period = new Period(new DateTime(2018, 10, 30), new DateTime(2018, 10, 28));
39+
});
40+
}
41+
42+
[Fact]
43+
public void PeriodCanBeZeroSize()
44+
{
45+
var startAndEnd = new DateTime(2018, 10, 30);
46+
47+
var period = new Period(startAndEnd, startAndEnd);
48+
}
49+
50+
[Fact]
51+
public void ITimeBlockEndCannotBeModifiedToBeNegative()
52+
{
53+
var startAndEnd = new DateTime(2018, 10, 30);
54+
55+
ITimeBlock period = new Period(startAndEnd, startAndEnd);
56+
57+
Assert.Throws<NegativeDurationException>(() =>
58+
{
59+
period.ChangeEndsAt(new DateTime(2018, 10, 28));
60+
});
61+
}
62+
63+
[Fact]
64+
public void ITimeBlockStartCannotBeModifiedToBeNegative()
65+
{
66+
var startAndEnd = new DateTime(2018, 10, 28);
67+
68+
ITimeBlock period = new Period(startAndEnd, startAndEnd);
69+
70+
Assert.Throws<NegativeDurationException>(() =>
71+
{
72+
period.ChangeStartsAt(new DateTime(2018, 10, 30));
73+
});
74+
}
75+
76+
[Fact]
77+
public void ITimeBlockDurationCannotBeModifiedToBeNegative()
78+
{
79+
var startAndEnd = new DateTime(2018, 10, 28);
80+
81+
ITimeBlock period = new Period(startAndEnd, startAndEnd);
82+
83+
Assert.Throws<NegativeDurationException>(() =>
84+
{
85+
period.ChangeDuration(TimeSpan.FromSeconds(-1));
86+
});
87+
}
88+
89+
[Fact]
90+
public void ITimeBlockDurationCanBeDifferentFromEndMinusStart()
91+
{
92+
var startAndEnd = new DateTime(2018, 10, 28);
93+
94+
ITimeBlock period = new Period(startAndEnd, startAndEnd);
95+
96+
period.ChangeDuration(TimeSpan.FromSeconds(1));
97+
98+
Assert.Equal(TimeSpan.FromSeconds(1), period.Duration);
99+
Assert.Equal(TimeSpan.FromSeconds(0), period.EndsAt - period.StartsAt);
100+
}
34101
}
35102
}

NExtends.Tests/Primitives/TimeSpans/TimeSpan.extensions.tests.cs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using NExtends.Primitives.TimeSpans;
22
using System;
3+
using System.Globalization;
34
using Xunit;
45

56
namespace NExtends.Tests.Primitives.TimeSpans
@@ -20,10 +21,10 @@ public void TimespanMultiply()
2021
[Theory]
2122
[InlineData(0, true, "-")]
2223
[InlineData(0, false, "-")]
23-
[InlineData(9, true, "+09mn")]
24-
[InlineData(9, false, "09mn")]
25-
[InlineData(-9, true, "-09mn")]
26-
[InlineData(-9, false, "-09mn")]
24+
[InlineData(9, true, "+09m")]
25+
[InlineData(9, false, "09m")]
26+
[InlineData(-9, true, "-09m")]
27+
[InlineData(-9, false, "-09m")]
2728
[InlineData(69, true, "+1h09")]
2829
[InlineData(69, false, "1h09")]
2930
[InlineData(-69, true, "-1h09")]
@@ -32,8 +33,8 @@ public void TimespanMultiply()
3233
public void TimeSpanToHoursShouldWork(int timeInMinutes, bool showSign, string expected)
3334
{
3435
var timespan = TimeSpan.FromMinutes(timeInMinutes);
35-
var initials = new TimeInitials("mn", "h", "j");
36-
var result = TimeSpanExtensions.ToHours(timespan, initials, showSign);
36+
var culture = CultureInfo.GetCultureInfo("fr-FR");
37+
var result = TimeSpanExtensions.ToHours(timespan, culture, showSign);
3738

3839
Assert.Equal(expected, result);
3940
}
@@ -53,8 +54,8 @@ public void TimeSpanToHoursShouldWork(int timeInMinutes, bool showSign, string e
5354
public void TimeSpanToDaysShouldWork(int timeInMinutes, bool showSign, string expected)
5455
{
5556
var timespan = TimeSpan.FromMinutes(timeInMinutes);
56-
var initials = new TimeInitials("mn", "h", "j");
57-
var result = TimeSpanExtensions.ToDays(timespan, initials, showSign);
57+
var culture = CultureInfo.GetCultureInfo("fr-FR");
58+
var result = TimeSpanExtensions.ToDays(timespan, culture, showSign);
5859

5960
Assert.Equal(expected, result);
6061
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace NExtends.Primitives.DateTimes
4+
{
5+
public interface ITimeBlock
6+
{
7+
DateTime StartsAt { get; }
8+
DateTime EndsAt { get; }
9+
TimeSpan Duration { get; }
10+
11+
void ChangeStartsAt(DateTime startsAt);
12+
void ChangeEndsAt(DateTime endsAt);
13+
void ChangeDuration(TimeSpan duration);
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NExtends.Primitives.DateTimes
4+
{
5+
public class NegativeDurationException : ArgumentException
6+
{
7+
public NegativeDurationException(string paramName)
8+
: base("You cannot create or update a period to a negative duration", paramName) { }
9+
}
10+
}

NExtends/Primitives/DateTimes/Period.cs

+70-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,82 @@
22

33
namespace NExtends.Primitives.DateTimes
44
{
5-
public struct Period
5+
public class Period : ITimeBlock, IEquatable<Period>
66
{
7-
public DateTime Start { get; }
8-
public DateTime End { get; }
9-
public TimeSpan Duration { get { return End - Start; } }
7+
public DateTime Start { get; private set; }
8+
public DateTime End { get; private set; }
9+
public TimeSpan Duration { get; private set; }
10+
11+
public DateTime StartsAt => Start;
12+
public DateTime EndsAt => End;
13+
14+
void ITimeBlock.ChangeStartsAt(DateTime startsAt)
15+
{
16+
if (startsAt > End)
17+
{
18+
throw new NegativeDurationException(nameof(startsAt));
19+
}
20+
21+
Start = startsAt;
22+
}
23+
void ITimeBlock.ChangeEndsAt(DateTime endsAt)
24+
{
25+
if (endsAt < Start)
26+
{
27+
throw new NegativeDurationException(nameof(endsAt));
28+
}
29+
30+
End = endsAt;
31+
}
32+
void ITimeBlock.ChangeDuration(TimeSpan duration)
33+
{
34+
if (duration < TimeSpan.Zero)
35+
{
36+
throw new NegativeDurationException(nameof(duration));
37+
}
38+
39+
Duration = duration;
40+
}
1041

1142
public Period(DateTime start, DateTime end)
1243
{
1344
Start = start;
1445
End = end;
46+
Duration = end - start;
47+
48+
if (Duration < TimeSpan.Zero)
49+
{
50+
throw new NegativeDurationException(nameof(end));
51+
}
52+
}
53+
54+
public bool Equals(Period other)
55+
{
56+
if (other == null) { return false; }
57+
58+
return Start == other.Start &&
59+
End == other.End &&
60+
Duration == other.Duration;
61+
}
62+
public override bool Equals(object obj)
63+
{
64+
if (ReferenceEquals(null, obj)) { return false; }
65+
if (ReferenceEquals(this, obj)) { return true; }
66+
if (obj.GetType() != GetType()) { return false; }
67+
68+
return Equals(obj as Period);
69+
}
70+
public override int GetHashCode()
71+
{
72+
//cf http://www.aaronstannard.com/overriding-equality-in-dotnet/
73+
unchecked
74+
{
75+
var hashCode = 13;
76+
hashCode = (hashCode * 397) ^ Start.GetHashCode();
77+
hashCode = (hashCode * 397) ^ End.GetHashCode();
78+
hashCode = (hashCode * 397) ^ Duration.GetHashCode();
79+
return hashCode;
80+
}
1581
}
1682
}
1783
}

NExtends/Primitives/TimeSpans/TimeInitials.cs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
namespace NExtends.Primitives.TimeSpans
1+
using System.Globalization;
2+
3+
namespace NExtends.Primitives.TimeSpans
24
{
35
public class TimeInitials
46
{
7+
private static readonly TimeInitials _french = new TimeInitials("m", "h", "j");
8+
private static readonly TimeInitials _german = new TimeInitials("M", "St", "T");
9+
private static readonly TimeInitials _english = new TimeInitials("m", "h", "d");
10+
511
public string MinutesInitial { get; }
612
public string HoursInitial { get; }
713
public string DaysInitial { get; }
@@ -12,5 +18,18 @@ public TimeInitials(string minutesInitial, string hoursInitial, string daysIniti
1218
HoursInitial = hoursInitial;
1319
DaysInitial = daysInitial;
1420
}
21+
22+
public static TimeInitials FromCulture(CultureInfo culture)
23+
{
24+
switch(culture.Name)
25+
{
26+
case "fr-FR":
27+
return _french;
28+
case "de-DE":
29+
return _german;
30+
default:
31+
return _english;
32+
}
33+
}
1534
}
1635
}

NExtends/Primitives/TimeSpans/TimeSpan.extensions.cs

+26-5
Original file line numberDiff line numberDiff line change
@@ -46,29 +46,39 @@ public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSour
4646
public static bool IsNegativeOrZero(this TimeSpan t1) { return t1.Ticks <= 0; }
4747
public static bool IsNegative(this TimeSpan t1) { return t1.Ticks < 0; }
4848

49-
public static string Humanize(this TimeSpan timeSpan, TimeUnit timeUnit, TimeInitials initials, bool showSign = false)
49+
public static string Humanize(this TimeSpan timeSpan, TimeUnit timeUnit, bool showSign = false)
50+
{
51+
return Humanize(timeSpan, timeUnit, CultureInfo.CurrentCulture, showSign);
52+
}
53+
public static string Humanize(this TimeSpan timeSpan, TimeUnit timeUnit, CultureInfo culture, bool showSign = false)
5054
{
5155
switch (timeUnit)
5256
{
5357
case TimeUnit.Day:
54-
return ToDays(timeSpan, initials, showSign);
58+
return ToDays(timeSpan, culture, showSign);
5559
case TimeUnit.Duration:
5660
case TimeUnit.Time:
57-
return ToHours(timeSpan, initials, showSign);
61+
return ToHours(timeSpan, culture, showSign);
5862
case TimeUnit.NotApplicable:
5963
default:
6064
throw new InvalidEnumArgumentException(nameof(timeUnit));
6165
}
6266
}
6367

64-
public static string ToHours(this TimeSpan timeSpan, TimeInitials initials, bool showSign = false)
68+
public static string ToHours(this TimeSpan timeSpan, bool showSign = false)
69+
{
70+
return ToHours(timeSpan, CultureInfo.CurrentCulture, showSign);
71+
}
72+
public static string ToHours(this TimeSpan timeSpan, CultureInfo culture, bool showSign = false)
6573
{
6674
if (timeSpan == TimeSpan.Zero)
6775
{
6876
return "-";
6977
}
78+
7079
var absSpan = new TimeSpan(Math.Abs(timeSpan.Ticks));
7180
var totalHours = Math.Floor(absSpan.TotalHours);
81+
var initials = TimeInitials.FromCulture(culture);
7282

7383
var sb = new StringBuilder();
7484
if (showSign && timeSpan > TimeSpan.Zero)
@@ -91,17 +101,26 @@ public static string ToHours(this TimeSpan timeSpan, TimeInitials initials, bool
91101
{
92102
sb.Append(initials.MinutesInitial);
93103
}
104+
94105
return sb.ToString();
95106
}
96107

97-
public static string ToDays(this TimeSpan span, TimeInitials initials, bool showSign = false)
108+
public static string ToDays(this TimeSpan span, bool showSign = false)
109+
{
110+
return ToDays(span, CultureInfo.CurrentCulture, showSign);
111+
}
112+
113+
public static string ToDays(this TimeSpan span, CultureInfo culture, bool showSign = false)
98114
{
99115
if (span == TimeSpan.Zero)
100116
{
101117
return "-";
102118
}
119+
103120
var absSpan = new TimeSpan(Math.Abs(span.Ticks));
104121
var sb = new StringBuilder();
122+
var initials = TimeInitials.FromCulture(culture);
123+
105124
if (showSign && span > TimeSpan.Zero)
106125
{
107126
sb.Append("+");
@@ -110,7 +129,9 @@ public static string ToDays(this TimeSpan span, TimeInitials initials, bool show
110129
{
111130
sb.Append("-");
112131
}
132+
113133
sb.AppendFormat(CultureInfo.InvariantCulture, "{0} " + initials.DaysInitial, absSpan.TotalDays.RealRound(5));
134+
114135
return sb.ToString();
115136
}
116137
}

0 commit comments

Comments
 (0)