Skip to content

Commit 0b9a1e8

Browse files
committed
General : Handle "year field as a date" informal convention (e.g. 19900812) [#322]
1 parent fc30cd8 commit 0b9a1e8

File tree

5 files changed

+159
-26
lines changed

5 files changed

+159
-26
lines changed

ATL.unit-test/IO/HighLevel.cs

+23
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,29 @@ public void TagIO_RW_AddRemoveTagRegularNotNullable()
534534
Assert.AreEqual(DateTime.MinValue.ToString(), theTrack.Date.ToString());
535535

536536

537+
// Use "year field as a date" informal convention
538+
539+
// OK case
540+
theTrack.Year = 19900812;
541+
Assert.IsTrue(theTrack.Save());
542+
theTrack = new Track(testFileLocation);
543+
544+
Assert.AreEqual(1990, theTrack.Year);
545+
Assert.IsTrue(theTrack.Date.HasValue);
546+
Assert.AreEqual(1990, theTrack.Date.Value.Year);
547+
Assert.AreEqual(08, theTrack.Date.Value.Month);
548+
Assert.AreEqual(12, theTrack.Date.Value.Day);
549+
550+
// KO case
551+
theTrack.Year = 19909912;
552+
Assert.IsTrue(theTrack.Save());
553+
theTrack = new Track(testFileLocation);
554+
555+
Assert.AreEqual(0, theTrack.Year);
556+
Assert.IsTrue(theTrack.Date.HasValue);
557+
Assert.AreEqual(DateTime.MinValue, theTrack.Date.Value);
558+
559+
537560
// Get rid of the working copy
538561
if (Settings.DeleteAfterSuccess) File.Delete(testFileLocation);
539562
}

ATL.unit-test/Misc/UtilsTest.cs

+39
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,45 @@ public void Utils_CheckTimeFormat()
8080
Assert.IsTrue(Utils.CheckTimeFormat("00:00:59"));
8181
}
8282

83+
[TestMethod]
84+
public void Utils_TryExtractDateTimeFromDigits()
85+
{
86+
DateTime? date = null;
87+
Assert.IsTrue(Utils.TryExtractDateTimeFromDigits("1930", out date));
88+
Assert.IsTrue(date.HasValue);
89+
Assert.AreEqual(date.Value.Year, 1930);
90+
Assert.AreEqual(date.Value.Month, 1);
91+
Assert.AreEqual(date.Value.Day, 1);
92+
93+
date = null;
94+
Assert.IsTrue(Utils.TryExtractDateTimeFromDigits("193008", out date));
95+
Assert.IsTrue(date.HasValue);
96+
Assert.AreEqual(date.Value.Year, 1930);
97+
Assert.AreEqual(date.Value.Month, 8);
98+
Assert.AreEqual(date.Value.Day, 1);
99+
100+
date = null;
101+
Assert.IsTrue(Utils.TryExtractDateTimeFromDigits("19300812", out date));
102+
Assert.IsTrue(date.HasValue);
103+
Assert.AreEqual(date.Value.Year, 1930);
104+
Assert.AreEqual(date.Value.Month, 8);
105+
Assert.AreEqual(date.Value.Day, 12);
106+
107+
// KO cases
108+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("sds", out date));
109+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("12sds12", out date));
110+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("123456789", out date));
111+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("123", out date));
112+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("12345", out date));
113+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("-320", out date));
114+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("19.0", out date));
115+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("0000", out date));
116+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("193088", out date));
117+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("000012", out date));
118+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("19300140", out date));
119+
Assert.IsFalse(Utils.TryExtractDateTimeFromDigits("00000101", out date));
120+
}
121+
83122
[TestMethod]
84123
public void Utils_StrictLengthString()
85124
{

ATL/Entities/MetadataHolder.cs

+26-19
Original file line numberDiff line numberDiff line change
@@ -176,27 +176,27 @@ public DateTime Date
176176
// Year only
177177
if (!success)
178178
{
179-
// ...then try with RecordingDate
180-
foreach (var dateValue in dateValues)
179+
DateTime? dateTimeFromYear = null;
180+
if (!Utils.TryExtractDateTimeFromDigits(year, out dateTimeFromYear))
181181
{
182-
if (4 == year.Length) break;
183-
year = Utils.ProtectValue(dateValue);
182+
// ...then try with RecordingDate
183+
foreach (var dateValue in dateValues)
184+
{
185+
if (Utils.TryExtractDateTimeFromDigits(dateValue, out dateTimeFromYear)) break;
186+
}
184187
}
185188

186-
// We have a year !
187-
if (4 == year.Length)
189+
// We have a valid value !
190+
if (dateTimeFromYear.HasValue)
188191
{
189-
StringBuilder dateTimeBuilder = new StringBuilder();
190-
dateTimeBuilder.Append(year).Append("-01-01");
192+
result = dateTimeFromYear.Value;
191193
string time = Utils.ProtectValue(tagData[Field.RECORDING_TIME]); // Try to add time if available
192-
if (time.Length >= 4)
194+
if (time.Length >= 4 && Utils.IsNumeric(time))
193195
{
194-
dateTimeBuilder.Append('T');
195-
dateTimeBuilder.Append(time[..2]).Append(':');
196-
dateTimeBuilder.Append(time.AsSpan(2, 2)).Append(':');
197-
dateTimeBuilder.Append(6 == time.Length ? time.Substring(4, 2) : "00");
196+
result.AddHours(int.Parse(time[..2]));
197+
result.AddMinutes(int.Parse(time.AsSpan(2, 2)));
198+
if (6 == time.Length) result.AddSeconds(int.Parse(time.Substring(4, 2)));
198199
}
199-
DateTime.TryParse(dateTimeBuilder.ToString(), out result);
200200
}
201201
}
202202
}
@@ -231,12 +231,19 @@ public DateTime OriginalReleaseDate
231231
{
232232
bool success = false;
233233
string year = Utils.ProtectValue(tagData[Field.ORIG_RELEASE_YEAR]);
234-
if (year.Length != 4) year = Utils.ProtectValue(tagData[Field.ORIG_RELEASE_DATE]); // ...then with OriginalReleaseDate
235-
if (4 == year.Length) // We have a year !
234+
235+
DateTime? dateTimeFromYear = null;
236+
// ...then with OriginalReleaseDate
237+
if (!Utils.TryExtractDateTimeFromDigits(year, out dateTimeFromYear))
236238
{
237-
StringBuilder dateTimeBuilder = new StringBuilder();
238-
dateTimeBuilder.Append(year).Append("-01-01");
239-
success = DateTime.TryParse(dateTimeBuilder.ToString(), out result);
239+
year = Utils.ProtectValue(tagData[Field.ORIG_RELEASE_DATE]);
240+
Utils.TryExtractDateTimeFromDigits(year, out dateTimeFromYear);
241+
}
242+
// We have a valid value !
243+
if (dateTimeFromYear.HasValue)
244+
{
245+
result = dateTimeFromYear.Value;
246+
success = true;
240247
}
241248
if (!success) result = DateTime.MinValue;
242249
}

ATL/Entities/Track.cs

+20-4
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,18 @@ public int? Year
238238
}
239239
set
240240
{
241-
if (canUseValue(value) && value.Value > DateTime.MinValue.Year) Date = new DateTime(value.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
241+
if (canUseValue(value))
242+
{
243+
DateTime? tmpDate = null;
244+
if (Utils.TryExtractDateTimeFromDigits(value.ToString(), out tmpDate))
245+
{
246+
Date = tmpDate.Value;
247+
isYearExplicit = 1 == Date.Value.Day && 1 == Date.Value.Month;
248+
}
249+
else Date = DateTime.MinValue;
250+
}
242251
else if (Settings.NullAbsentValues) Date = null;
243252
else Date = DateTime.MinValue;
244-
isYearExplicit = true;
245253
}
246254
}
247255
/// <summary>
@@ -269,10 +277,18 @@ public int? OriginalReleaseYear
269277
}
270278
set
271279
{
272-
if (canUseValue(value) && value.Value > DateTime.MinValue.Year) OriginalReleaseDate = new DateTime(value.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
280+
if (canUseValue(value))
281+
{
282+
DateTime? tmpDate = null;
283+
if (Utils.TryExtractDateTimeFromDigits(value.ToString(), out tmpDate))
284+
{
285+
OriginalReleaseDate = tmpDate.Value;
286+
isORYearExplicit = 1 == OriginalReleaseDate.Value.Day && 1 == OriginalReleaseDate.Value.Month;
287+
}
288+
else OriginalReleaseDate = DateTime.MinValue;
289+
}
273290
else if (Settings.NullAbsentValues) OriginalReleaseDate = null;
274291
else OriginalReleaseDate = DateTime.MinValue;
275-
isORYearExplicit = true;
276292
}
277293
}
278294
/// <summary>

ATL/Utils/Utils.cs

+51-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static string ProtectValue(string value)
6161
public static string EncodeTimecode_ms(long milliseconds, bool useMmSsFormat = false)
6262
{
6363
long seconds = Convert.ToInt64(Math.Floor(milliseconds / 1000.00));
64-
64+
6565
var encodedString = useMmSsFormat ? EncodeMmSsTimecode_s(seconds) : EncodeTimecode_s(seconds);
6666

6767
return encodedString + "." + (milliseconds - seconds * 1000);
@@ -98,7 +98,7 @@ public static string EncodeTimecode_s(long seconds)
9898
if (h > 0) return hStr + ":" + mStr + ":" + sStr;
9999
return mStr + ":" + sStr;
100100
}
101-
101+
102102
/// <summary>
103103
/// Format the given duration using the following format
104104
/// MM:SS
@@ -118,7 +118,7 @@ public static string EncodeMmSsTimecode_s(long seconds)
118118
if (1 == mStr.Length) mStr = "0" + mStr;
119119
var sStr = s.ToString();
120120
if (1 == sStr.Length) sStr = "0" + sStr;
121-
121+
122122
return mStr + ":" + sStr;
123123
}
124124

@@ -233,6 +233,54 @@ public static bool CheckTimeFormat(string timeStr)
233233
return intVal >= 0 && intVal <= 59;
234234
}
235235

236+
/// <summary>
237+
/// Try to extract a DateTime from a digits-only string
238+
/// Accepted values :
239+
/// YYYY
240+
/// YYYYMM
241+
/// YYYYMMDD
242+
/// </summary>
243+
/// <param name="str">String to extract the date from</param>
244+
/// <param name="date">DateTime to populate</param>
245+
/// <returns>True if a valid DateTime has been found inside str (date will be valued); false instead (date will be null)</returns>
246+
public static bool TryExtractDateTimeFromDigits(string str, out DateTime? date)
247+
{
248+
date = null;
249+
if (!IsNumeric(str, true, false)) return false;
250+
251+
switch (str.Length)
252+
{
253+
case 4:
254+
int year = int.Parse(str);
255+
if (year >= DateTime.MinValue.Year && year <= DateTime.MaxValue.Year)
256+
{
257+
date = new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc);
258+
return true;
259+
}
260+
break;
261+
case 6:
262+
year = int.Parse(str.Substring(0, 4));
263+
int month = int.Parse(str.Substring(4, 2));
264+
if (year >= DateTime.MinValue.Year && year <= DateTime.MaxValue.Year && month <= DateTime.MaxValue.Month)
265+
{
266+
date = new DateTime(year, month, 1, 0, 0, 0, DateTimeKind.Utc);
267+
return true;
268+
}
269+
break;
270+
case 8:
271+
year = int.Parse(str.Substring(0, 4));
272+
month = int.Parse(str.Substring(4, 2));
273+
int day = int.Parse(str.Substring(6, 2));
274+
if (year >= DateTime.MinValue.Year && year <= DateTime.MaxValue.Year && month <= DateTime.MaxValue.Month && day <= DateTime.MaxValue.Day)
275+
{
276+
date = new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
277+
return true;
278+
}
279+
break;
280+
}
281+
return false;
282+
}
283+
236284
/// <summary>
237285
/// Strip the given string from all ending null '\0' characters
238286
/// </summary>

0 commit comments

Comments
 (0)