From a6c0e36f6dea78949d3def7a1d5676e80bb3d6bf Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 27 Jun 2024 11:09:01 +1000 Subject: [PATCH] Add methods to increment / decrement GDMDate --- projects/GKCore/GDModel/GDMDate.cs | 112 ++++++++++++++++++++++- projects/GKTests/GDModel/GDMDateTests.cs | 40 +++++++- 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/projects/GKCore/GDModel/GDMDate.cs b/projects/GKCore/GDModel/GDMDate.cs index 248da1f24..198c77ac7 100644 --- a/projects/GKCore/GDModel/GDMDate.cs +++ b/projects/GKCore/GDModel/GDMDate.cs @@ -135,7 +135,7 @@ public override void Clear() } /// - /// This function is intended only for checking the completeness of parts of the date + /// This function is intended only for checking the completeness of parts of the date /// (year, month and day are defined, are not unknown). /// public bool IsValidDate() @@ -588,5 +588,115 @@ public override void GetDateRange(out GDMDate dateStart, out GDMDate dateEnd) dateStart = this; dateEnd = this; } + + public static GDMDate Increment(GDMDate date) + { + if (date.IsEmpty()) { + return Empty; + } + + var calendar = date.fCalendar; + var day = date.fDay; + var month = date.fMonth; + var year = date.fYear; + var yearBc = date.fYearBC; + + Increment(ref day, ref month, ref year, ref yearBc, calendar); + + var result = new GDMDate(); + result.SetRawData(date.fApproximated, calendar, year, yearBc, date.fYearModifier, month, day); + return result; + } + + private static void Increment(ref byte day, ref byte month, ref short year, ref bool yearBC, + GDMCalendar calendar) + { + if (day > 0) { + if (day < DaysInMonth(yearBC, year, month, calendar)) { + day++; + return; + } + + day = 1; + } + + if (month > 0) { + if (month < 12) { + month++; + return; + } + + month = 1; + } + + if (year == 1 && yearBC) { + yearBC = false; + } else { + year++; + } + } + + public static GDMDate Decrement(GDMDate date) + { + if (date.IsEmpty()) { + return Empty; + } + + var calendar = date.fCalendar; + var day = date.fDay; + var month = date.fMonth; + var year = date.fYear; + var yearBc = date.fYearBC; + + Decrement(ref yearBc, ref year, ref month, ref day, calendar); + + var result = new GDMDate(); + result.SetRawData(date.fApproximated, calendar, year, yearBc, date.fYearModifier, month, day); + return result; + } + + private static void Decrement(ref bool yearBc, ref short year, ref byte month, ref byte day, + GDMCalendar calendar) + { + if (day > 1) { + day--; + return; + } + + var monthDecremented = month > 1; + if (monthDecremented) { + month--; + } else if (month > 0) { + month = 12; + } + + if (day > 0) { + day = DaysInMonth(yearBc, year, month, calendar); + } + + if (monthDecremented) return; + + if (year == 1 && !yearBc) { + yearBc = true; + } else { + year--; + } + } + + private static byte DaysInMonth(bool yearBC, short year, byte month, GDMCalendar calendar) + { + if (yearBC) { + year -= 1; + if (year == 0) { + year = 4; // DateTime.DaysInMonth does not support year 0 + } + } + + if (calendar == GDMCalendar.dcJulian && month == 2 && year % 4 == 0) { + return 29; + } + + return (byte)DateTime.DaysInMonth(year, month); + } } } diff --git a/projects/GKTests/GDModel/GDMDateTests.cs b/projects/GKTests/GDModel/GDMDateTests.cs index 8ca597937..c6d60636d 100644 --- a/projects/GKTests/GDModel/GDMDateTests.cs +++ b/projects/GKTests/GDModel/GDMDateTests.cs @@ -737,8 +737,46 @@ public void Test_CreateByFormattedStr() Assert.AreEqual("20 DEC 1980", GDMDate.CreateByFormattedStr("20/12/1980", false).StringValue); Assert.AreEqual("DEC 1980", GDMDate.CreateByFormattedStr("__/12/1980", false).StringValue); Assert.AreEqual(null, GDMDate.CreateByFormattedStr("1980", false)); - + Assert.Throws(typeof(GDMDateException), () => { GDMDate.CreateByFormattedStr("1980", true); }); } + + [Test] + [TestCase("", "")] + [TestCase("2024", "2025")] + [TestCase("001B.C.", "001")] + [TestCase("OCT 2024", "NOV 2024")] + [TestCase("DEC 2024", "JAN 2025")] + [TestCase("01 OCT 2024", "02 OCT 2024")] + [TestCase("31 OCT 2024", "01 NOV 2024")] + [TestCase("31 DEC 2024", "01 JAN 2025")] + [TestCase("28 FEB 1900", "01 MAR 1900")] + [TestCase("28 FEB 2000", "29 FEB 2000")] + [TestCase("29 FEB 2000", "01 MAR 2000")] + [TestCase("28 FEB 2023", "01 MAR 2023")] + [TestCase("28 FEB 2024", "29 FEB 2024")] + [TestCase("29 FEB 2024", "01 MAR 2024")] + [TestCase("28 FEB 001B.C.", "29 FEB 001B.C.")] + [TestCase("29 FEB 001B.C.", "01 MAR 001B.C.")] + [TestCase("28 FEB 005B.C.", "29 FEB 005B.C.")] + [TestCase("29 FEB 005B.C.", "01 MAR 005B.C.")] + [TestCase("28 FEB 097B.C.", "29 FEB 097B.C.")] + [TestCase("29 FEB 097B.C.", "01 MAR 097B.C.")] + [TestCase("28 FEB 101B.C.", "01 MAR 101B.C.")] + [TestCase("@#DJULIAN@ 29 FEB 2024", "@#DJULIAN@ 01 MAR 2024")] + [TestCase("@#DJULIAN@ 28 FEB 1900", "@#DJULIAN@ 29 FEB 1900")] + [TestCase("@#DJULIAN@ 29 FEB 1900", "@#DJULIAN@ 01 MAR 1900")] + [TestCase("@#DJULIAN@ 28 FEB 2000", "@#DJULIAN@ 29 FEB 2000")] + [TestCase("@#DJULIAN@ 29 FEB 2000", "@#DJULIAN@ 01 MAR 2000")] + [TestCase("@#DJULIAN@ 28 FEB 2023", "@#DJULIAN@ 01 MAR 2023")] + [TestCase("@#DJULIAN@ 29 FEB 2024", "@#DJULIAN@ 01 MAR 2024")] + public void Test_Increment_Decrement(string value, string expected) + { + var d = new GDMDate(); + d.StringValue = value; + Assert.AreEqual(expected, GDMDate.Increment(d).StringValue); + d.StringValue = expected; + Assert.AreEqual(value, GDMDate.Decrement(d).StringValue); + } } }