Skip to content

Commit

Permalink
Add YearWeekIso
Browse files Browse the repository at this point in the history
  • Loading branch information
geoperez committed Jan 8, 2024
1 parent a2fd600 commit 0ea0d30
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 21 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,5 @@ MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

.vscode/
4 changes: 2 additions & 2 deletions src/Unosquare.DateTimeExt/Date-Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static DateTime GetFirstBusinessDayOfMonth(this DateTime @this)
{
DayOfWeek.Sunday => firstDayOfCurrentMonth.AddDays(1),
DayOfWeek.Saturday => firstDayOfCurrentMonth.AddDays(2),
_ => firstDayOfCurrentMonth
_ => firstDayOfCurrentMonth,
};
}

Expand All @@ -80,7 +80,7 @@ public static DateTime GetLastBusinessDayOfMonth(this DateTime @this)
{
DayOfWeek.Sunday => lastDayOfCurrentMonth.AddDays(-2),
DayOfWeek.Saturday => lastDayOfCurrentMonth.AddDays(-1),
_ => lastDayOfCurrentMonth
_ => lastDayOfCurrentMonth,
};
}

Expand Down
23 changes: 5 additions & 18 deletions src/Unosquare.DateTimeExt/YearWeek.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

namespace Unosquare.DateTimeExt;

public sealed class YearWeek : DateRange, IYearWeekDateRange, IComparable<YearWeek>
public sealed class YearWeek : YearWeekBase, IComparable<YearWeek>
{
private const int WeekDays = 7;

public YearWeek(int? week = null, int? year = null)
: base(GetStartDate(week, year), GetStartDate(week, year).AddDays(6))
{
Expand All @@ -29,11 +27,8 @@ public YearWeek(DateTime? dateTime)

public static YearWeek Current => new();

public int Week { get; }
public int Year => StartDate.Year;

public YearEntity BoWYearEntity => new(StartDate.Year);
public YearEntity EoWYearEntity => new(EndDate.Year);
public override int Week { get; }
public override int Year => StartDate.Year;

public YearWeek Next => new(StartDate.AddDays(WeekDays));

Expand All @@ -50,16 +45,6 @@ private static DateTime GetStartDate(int? week = null, int? year = null) =>

public YearWeek ToWeek(int? week) => new(week, Year);

public new YearWeekRecord ToRecord() => new() { Year = Year, Week = Week };

public void Deconstruct(out int year, out int week)
{
year = Year;
week = Week;
}

public override string ToString() => $"{Year}-W{Week}";

public int CompareTo(YearWeek? other)
{
if (ReferenceEquals(this, other))
Expand All @@ -78,7 +63,9 @@ public static bool TryParse(string? value, out YearWeek result)
var parts = value.Split('-', 'W');

Check warning on line 63 in src/Unosquare.DateTimeExt/YearWeek.cs

View workflow job for this annotation

GitHub Actions / Build

Review this call, which partially matches an overload without 'params'. The partial match is 'string[] string.Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None)'. (https://rules.sonarsource.com/csharp/RSPEC-3220)

if (parts.Length != 3 || !int.TryParse(parts[0], out var year) || !int.TryParse(parts[2], out var week))
{
return false;
}

result = new(week, year);
return true;
Expand Down
25 changes: 25 additions & 0 deletions src/Unosquare.DateTimeExt/YearWeekBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Unosquare.DateTimeExt.Interfaces;

namespace Unosquare.DateTimeExt;

public abstract class YearWeekBase(DateTime startDate, DateTime endDate)
: DateRange(startDate, endDate), IYearWeekDateRange
{
protected const int WeekDays = 7;

public abstract int Year { get; }
public abstract int Week { get; }

public YearEntity BoWYearEntity => new(StartDate.Year);
public YearEntity EoWYearEntity => new(EndDate.Year);

public new YearWeekRecord ToRecord() => new() { Year = Year, Week = Week };

public void Deconstruct(out int year, out int week)
{
year = Year;
week = Week;
}

public override string ToString() => $"{Year}-W{Week}";
}
69 changes: 69 additions & 0 deletions src/Unosquare.DateTimeExt/YearWeekIso.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Unosquare.DateTimeExt.Interfaces;

namespace Unosquare.DateTimeExt;

public sealed class YearWeekIso : YearWeekBase, IComparable<YearWeekIso>
{
public YearWeekIso(int week, int year)
: base(ISOWeek.ToDateTime(year, week, DayOfWeek.Monday), ISOWeek.ToDateTime(year, week, DayOfWeek.Sunday))
{
}

public YearWeekIso(IYearWeek yearWeek)
: this(yearWeek.Week, yearWeek.Year)
{
}

public YearWeekIso(IHasReadOnlyWeek readOnlyWeek, IHasReadOnlyYear readOnlyYear)
: this(readOnlyWeek.Week, readOnlyYear.Year)
{
}

public YearWeekIso(DateTime? dateTime = null)
: this(ISOWeek.GetWeekOfYear(dateTime ?? DateTime.UtcNow), ISOWeek.GetYear(dateTime ?? DateTime.UtcNow))
{
}

public static YearWeekIso Current => new();

public override int Week => ISOWeek.GetWeekOfYear(StartDate);
public override int Year => ISOWeek.GetYear(StartDate);

public YearWeekIso Next => new(StartDate.AddDays(WeekDays));

public YearWeekIso Previous => new(StartDate.AddDays(-WeekDays));

public bool IsCurrent => IsCurrentYear && Week == ISOWeek.GetWeekOfYear(DateTime.UtcNow);

public bool IsCurrentYear => Year == ISOWeek.GetYear(DateTime.UtcNow);

public YearWeekIso AddWeeks(int count) => new(StartDate.AddDays(WeekDays * count));

public YearWeekIso ToWeek(int week) => new(week, Year);

public int CompareTo(YearWeekIso? other)
{
if (ReferenceEquals(this, other))
return 0;

return other is null ? 1 : base.CompareTo(other);
}

public static bool TryParse(string? value, out YearWeekIso result)
{
result = default!;

if (string.IsNullOrWhiteSpace(value))
return false;

var parts = value.Split('-', 'W');

Check warning on line 59 in src/Unosquare.DateTimeExt/YearWeekIso.cs

View workflow job for this annotation

GitHub Actions / Build

Review this call, which partially matches an overload without 'params'. The partial match is 'string[] string.Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None)'. (https://rules.sonarsource.com/csharp/RSPEC-3220)

if (parts.Length != 3 || !int.TryParse(parts[0], out var year) || !int.TryParse(parts[2], out var week))
{
return false;
}

result = new(week, year);
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void WithDate_GetWeekOfTheYear()
[Fact]
public void WithYearAndWeek_GetFirstDateOfWeek()
{
Assert.Equal(new(2022, 1, 2), DateExtensions.FirstDateOfWeek(2022, 1));
Assert.Equal(new(2024, 1, 7), DateExtensions.FirstDateOfWeek(2024, 1));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
namespace Unosquare.DateTimeExt.Test;

public class YearWeekIsoTests
{
[Fact]
public void WithWeek_Deconstruct()
{
var yearMonth = new YearWeekIso(1, 2022);
yearMonth.Deconstruct(out DateTime startDate, out var endDate);

Assert.Equal(new(2022, 1, 3), startDate);
Assert.Equal(new(2022, 1, 9), endDate);
}

[Fact]
public void WithWeek_FromDateTime()
{
var yearMonth = new YearWeekIso(new DateTime(2022, 1, 2));

Assert.Equal(52, yearMonth.Week);
Assert.Equal(2021, yearMonth.Year);
}

[Fact]
public void WithWeek_DateRange()
{
var yearMonth = new YearWeekIso(1, 2022);

Assert.Equal(new(2022, 1, 3), yearMonth.StartDate);
Assert.Equal(new(2022, 1, 9), yearMonth.EndDate);
}

[Fact]
public void WithWeek_AddWeeksNegative()
{
var yearMonth = new YearWeekIso(2, 2022);

Assert.Equal(new(2022, 1, 3), yearMonth.AddWeeks(-1).StartDate);
}

[Fact]
public void WithWeek_AddWeeksPositive()
{
var yearMonth = new YearWeekIso(1, 2022);

Assert.Equal(new(2022, 1, 10), yearMonth.AddWeeks(1).StartDate);
}

[Fact]
public void WithWeek_Previous()
{
var yearMonth = new YearWeekIso(2, 2022);

Assert.Equal(new(2022, 1, 3), yearMonth.Previous.StartDate);
}

[Fact]
public void WithWeek_Next()
{
var yearMonth = new YearWeekIso(1, 2022);

Assert.Equal(new(2022, 1, 10), yearMonth.Next.StartDate);
}

[Fact]
public void WithWeek_IsCurrent()
{
var yearMonth = new YearWeekIso();

Assert.True(yearMonth.IsCurrent);
}

[Fact]
public void WithWeek_DeconstructYearMonth()
{
var yearMonth = new YearWeekIso(1, 2022);
yearMonth.Deconstruct(out int year, out int week);

Assert.Equal(1, week);
Assert.Equal(2022, year);
}

[Fact]
public void TryParse_Valid_WeekYearString_ReturnsTrue()
{
// Arrange
const string input = "2022-W01";
YearWeekIso expected = new(1, 2022);

// Act
bool result = YearWeekIso.TryParse(input, out var actual);

// Assert
Assert.True(result);
Assert.Equal(expected, actual);
}

[Fact]
public void TryParse_Invalid_WeekYearString_ReturnsFalse()
{
// Arrange
const string input = "not a valid input string";

// Act
bool result = YearWeekIso.TryParse(input, out var actual);

// Assert
Assert.False(result);
Assert.Null(actual);
}

[Fact]
public void YearWeekIso_Current()
{
var yearWeek = YearWeekIso.Current;

Assert.Equal(DateTime.UtcNow.Month == 1 && DateTime.UtcNow.GetWeekOfYear() > 5
? DateTime.UtcNow.Year - 1
: DateTime.UtcNow.Year, yearWeek.Year);
}

[Fact]
public void YearWeekIso_BoWYearEntity()
{
var yearWeek = new YearWeekIso(1, 2022);
var yearWeekBoW = yearWeek.BoWYearEntity;

Assert.Equal(yearWeek.Year, yearWeekBoW.Year);
Assert.Equal(yearWeek.StartDate.Month, yearWeekBoW.StartDate.Month);
Assert.Equal(1, yearWeekBoW.StartDate.Day);
}

[Fact]
public void YearWeekIso_EoWYearEntity()
{
var yearWeek = new YearWeekIso(1, 2022);
var yearWeekBoW = yearWeek.EoWYearEntity;

Assert.Equal(yearWeek.Year, yearWeekBoW.Year);
Assert.Equal(yearWeek.StartDate.Month, yearWeekBoW.StartDate.Month);
Assert.Equal(1, yearWeekBoW.StartDate.Day);
}

[Fact]
public void YearWeekIso_ToRecord()
{
var yearWeek = new YearWeekIso(1, 2022);
var record = yearWeek.ToRecord();

Assert.Equal(yearWeek.Year, record.Year);
Assert.Equal(yearWeek.StartDate.Month, record.Week);
}

[Fact]
public void YearWeekIso_Equals()
{
var yearWeek1 = new YearWeekIso(1, 2022);
var yearWeek2 = new YearWeekIso(1, 2022);
var yearWeek3 = new YearWeekIso(2, 2022);

Assert.True(yearWeek1.Equals(yearWeek2));
Assert.False(yearWeek1.Equals(yearWeek3));
}

[Fact]
public void YearWeekIso_CompareTo()
{
var yearWeek1 = new YearWeekIso(1, 2022);
var yearWeek2 = new YearWeekIso(1, 2022);
var yearWeek3 = new YearWeekIso(2, 2022);

Assert.Equal(0, yearWeek1.CompareTo(yearWeek2));
Assert.Equal(-1, yearWeek1.CompareTo(yearWeek3));
Assert.Equal(1, yearWeek3.CompareTo(yearWeek1));
}
}

0 comments on commit 0ea0d30

Please sign in to comment.