diff --git a/README.md b/README.md
index cbd5df8..54e840f 100644
--- a/README.md
+++ b/README.md
@@ -23,3 +23,4 @@ These tests cover all cases for file/folder structures which contain files with
| M | datetime file with random start time | 00:00:00 | 01:00:00 | x |
| N | date folder, time file | 12:00:00 | 06:00:00 | |
| O | datetime file with random start time and interval exceeding end | 00:00:00 | 01:00:00 | x |
+| P | datetime file with file name offset | 00:00:00 | 00:10:00 | |
diff --git a/src/Nexus.Sources.StructuredFile/StructuredFileDataSource.cs b/src/Nexus.Sources.StructuredFile/StructuredFileDataSource.cs
index d5454d9..50b7e7c 100644
--- a/src/Nexus.Sources.StructuredFile/StructuredFileDataSource.cs
+++ b/src/Nexus.Sources.StructuredFile/StructuredFileDataSource.cs
@@ -582,7 +582,8 @@ protected abstract Task ReadAsync(
? DateTime.SpecifyKind(begin.Add(fileSource.UtcOffset), DateTimeKind.Local)
: throw new ArgumentException("The begin parameter must of kind UTC.");
- var localFileBegin = localBegin.RoundDown(fileSource.FilePeriod);
+ var localFileBegin = localBegin
+ .RoundDown(fileSource.FilePeriod);
var folderNames = fileSource
.PathSegments
@@ -652,6 +653,10 @@ protected abstract Task ReadAsync(
else
{
+ /* correct local file begin */
+ if (fileSource.FileNameOffset != TimeSpan.Zero)
+ localFileBegin = localFileBegin.Add(fileSource.FileNameOffset);
+
var folderPath = Path.Combine(folderNameArray);
var fileName = localFileBegin.ToString(fileSource.FileTemplate);
@@ -981,7 +986,7 @@ internal static bool TryGetFileBeginByPath(
CustomDateTimeOffset folderBegin = default)
{
var fileName = Path.GetFileName(filePath);
- bool isSuccess;
+ bool success;
if (TryGetFileBeginByName_AnyKind(fileName, fileSource, out fileBegin))
{
@@ -991,7 +996,7 @@ internal static bool TryGetFileBeginByPath(
// date+time: use file date/time
if (fileBegin.DateTime.Date != default)
{
- isSuccess = true;
+ success = true;
}
// time-only: use combined folder and file date/time
@@ -1004,7 +1009,7 @@ internal static bool TryGetFileBeginByPath(
new DateTime(folderBegin.DateTime.Date.Ticks + fileBegin.DateTime.TimeOfDay.Ticks),
fileBegin.Offset);
- isSuccess = true;
+ success = true;
}
// long way
@@ -1016,7 +1021,7 @@ internal static bool TryGetFileBeginByPath(
new DateTime(folderBegin.DateTime.Ticks + fileBegin.DateTime.TimeOfDay.Ticks),
fileBegin.Offset);
- isSuccess = folderBegin != default;
+ success = folderBegin != default;
}
}
@@ -1027,7 +1032,7 @@ internal static bool TryGetFileBeginByPath(
if (folderBegin != default)
{
fileBegin = folderBegin;
- isSuccess = true;
+ success = true;
}
// long way
@@ -1036,18 +1041,21 @@ internal static bool TryGetFileBeginByPath(
folderBegin = GetFolderBegin_AnyKind(filePath, fileSource);
fileBegin = folderBegin;
- isSuccess = folderBegin != default;
+ success = folderBegin != default;
}
}
+
+ if (success && fileSource.FileNameOffset != TimeSpan.Zero)
+ fileBegin = new CustomDateTimeOffset(fileBegin.DateTime - fileSource.FileNameOffset, fileBegin.Offset);
}
// no date + no time: failed
else
{
- isSuccess = false;
+ success = false;
}
- return isSuccess;
+ return success;
}
private static CustomDateTimeOffset GetFolderBegin_AnyKind(string filePath, FileSource fileSource)
diff --git a/src/Nexus.Sources.StructuredFile/StructuredFileDataSourceTypes.cs b/src/Nexus.Sources.StructuredFile/StructuredFileDataSourceTypes.cs
index fb7f819..c9181bd 100644
--- a/src/Nexus.Sources.StructuredFile/StructuredFileDataSourceTypes.cs
+++ b/src/Nexus.Sources.StructuredFile/StructuredFileDataSourceTypes.cs
@@ -13,6 +13,7 @@ namespace Nexus.Sources;
/// An optional regular expression to select only relevant parts of a file name (e.g. to select the date/time and a unqiue identifier in case there is more than one kind of file in the same folder). In case of a file named 20200101_13_my-id_1234.dat the preselector could be like "(.{11})_my-id". It is also required for file names containing an opaque string that changes for every file.
/// An optional date/time selector which is mandatory when the preselector is provided. In case of a file named like "20200101_13_my-id_1234.dat", and a preselector of "(.{11})_my-id", the selector should be like "yyyyMMdd_HH".
/// The period per file.
+/// The file name offset of the file data. This is useful for files that are named according to the end date of the data they contain.
/// The UTC offset of the file data.
/// The file time interval is irregular. I.e. the file end is not aligned to multiples of the file period.
/// Additional properties to be used by the data source implementation.
@@ -23,6 +24,7 @@ public record FileSource(
string? FileDateTimePreselector,
string? FileDateTimeSelector,
TimeSpan FilePeriod,
+ TimeSpan FileNameOffset,
TimeSpan UtcOffset,
bool IrregularTimeInterval,
JsonElement? AdditionalProperties
diff --git a/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/DATA/2020-01-01T00-10-00Z.dat b/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/DATA/2020-01-01T00-10-00Z.dat
new file mode 100644
index 0000000..e69de29
diff --git a/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/DATA/2020-01-01T00-20-00Z.dat b/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/DATA/2020-01-01T00-20-00Z.dat
new file mode 100644
index 0000000..e69de29
diff --git a/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/config.json b/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/config.json
new file mode 100644
index 0000000..7e7c43b
--- /dev/null
+++ b/tests/Nexus.Sources.StructuredFile.Tests/DATABASES/P/config.json
@@ -0,0 +1,15 @@
+{
+ "/A/B/C": {
+ "default": [
+ {
+ "PathSegments": [
+ "'DATA'"
+ ],
+ "FileTemplate": "yyyy-MM-ddTHH-mm-ssZ'.dat'",
+ "FilePeriod": "00:10:00",
+ "UtcOffset": "00:00:00",
+ "FileNameOffset": "00:10:00"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/Nexus.Sources.StructuredFile.Tests/StructuredFileDataSourceTests.cs b/tests/Nexus.Sources.StructuredFile.Tests/StructuredFileDataSourceTests.cs
index 859664e..42fe77a 100644
--- a/tests/Nexus.Sources.StructuredFile.Tests/StructuredFileDataSourceTests.cs
+++ b/tests/Nexus.Sources.StructuredFile.Tests/StructuredFileDataSourceTests.cs
@@ -115,6 +115,7 @@ public async Task CanProvideFirstFile()
[InlineData("DATABASES/M", "2020-01-01T01-35-23Z", "2020-01-01T05-00-00Z")]
[InlineData("DATABASES/N", "2019-12-31T12-00-00Z", "2020-01-03T12-00-00Z")]
[InlineData("DATABASES/O", "2020-01-01T00-35-23Z", "2020-01-01T01-00-10Z")]
+ [InlineData("DATABASES/P", "2020-01-01T00-00-00Z", "2020-01-01T00-20-00Z")]
public async Task CanProvideTimeRange(string root, string expectedBeginString, string expectedEndString)
{
var expectedBegin = DateTime.ParseExact(expectedBeginString, "yyyy-MM-ddTHH-mm-ssZ", null, DateTimeStyles.AdjustToUniversal);
@@ -152,6 +153,7 @@ public async Task CanProvideTimeRange(string root, string expectedBeginString, s
[InlineData("DATABASES/M", "2020-01-01T00-00-00Z", "2020-01-02T00-00-00Z", 4 / 24.0, 3)]
[InlineData("DATABASES/N", "2020-01-01T00-00-00Z", "2020-01-03T00-00-00Z", 7 / 8.0, 2)]
[InlineData("DATABASES/O", "2020-01-01T00-00-00Z", "2020-01-02T00-00-00Z", 3 / 288.0, 4)]
+ [InlineData("DATABASES/P", "2020-01-01T00-00-00Z", "2020-01-02T00-00-00Z", 2 / 144.0, 4)]
public async Task CanProvideAvailability(string root, string beginString, string endString, double expected, int precision)
{
// Arrange
@@ -297,6 +299,7 @@ await Assert.ThrowsAsync(() =>
[InlineData("M", "2020-01-01T00:00:00Z", "2020-01-02T00:00:00Z")]
[InlineData("N", "2020-01-01T00:00:00Z", "2020-01-04T00:00:00Z")]
[InlineData("O", "2020-01-01T00:00:00Z", "2020-01-02T00:00:00Z")]
+ [InlineData("P", "2020-01-01T00:00:00Z", "2020-01-02T00:00:00Z")]
public async Task CanRead_ReadInfos(string database, string beginString, string endString)
{
// Arrange
diff --git a/tests/Nexus.Sources.StructuredFile.Tests/expected/P.json b/tests/Nexus.Sources.StructuredFile.Tests/expected/P.json
new file mode 100644
index 0000000..af8390d
--- /dev/null
+++ b/tests/Nexus.Sources.StructuredFile.Tests/expected/P.json
@@ -0,0 +1,20 @@
+[
+ {
+ "BufferOffset": 0,
+ "FilePath": "/debug/DATABASES/P/DATA/2020-01-01T00-10-00Z.dat",
+ "FileSource": null,
+ "RegularFileBegin": "2020-01-01T00:00:00Z",
+ "FileOffset": 0,
+ "FileBlock": 600,
+ "FileLength": 600
+ },
+ {
+ "BufferOffset": 600,
+ "FilePath": "/debug/DATABASES/P/DATA/2020-01-01T00-20-00Z.dat",
+ "FileSource": null,
+ "RegularFileBegin": "2020-01-01T00:10:00Z",
+ "FileOffset": 0,
+ "FileBlock": 600,
+ "FileLength": 600
+ }
+]
\ No newline at end of file