From a213c27fbf4223ec9d74c67c811b29757448f900 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Mon, 24 Jun 2024 17:05:04 +0500 Subject: [PATCH] Fix telemetryDataDateRange timezone offset --- .../Repositories/ITelemetryDataCache.cs | 4 +- .../Services/SAUB/TelemetryDataBaseService.cs | 37 +- .../Services/SAUB/TelemetryDataCache.cs | 629 +++++++++--------- .../Services/SAUB/TelemetryService.cs | 2 +- 4 files changed, 338 insertions(+), 334 deletions(-) diff --git a/AsbCloudApp/Repositories/ITelemetryDataCache.cs b/AsbCloudApp/Repositories/ITelemetryDataCache.cs index 851fce0b..f2fa41b0 100644 --- a/AsbCloudApp/Repositories/ITelemetryDataCache.cs +++ b/AsbCloudApp/Repositories/ITelemetryDataCache.cs @@ -49,7 +49,7 @@ namespace AsbCloudApp.Repositories /// /// /// - DatesRangeDto? GetOrDefaultCachedDateRange(int idTelemetry); + DatesRangeDto? GetOrDefaultCachedDataDateRange(int idTelemetry); /// /// Получить диапазон дат телеметрии. @@ -57,7 +57,7 @@ namespace AsbCloudApp.Repositories /// /// /// - DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry); + DatesRangeDto? GetOrDefaultWellDataDateRange(int idTelemetry); /// /// Получение первой и последней записи телеметрии. diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 0e07ee09..f5fd2d8b 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Requests; +using Mapster; namespace AsbCloudInfrastructure.Services.SAUB { @@ -67,10 +68,10 @@ namespace AsbCloudInfrastructure.Services.SAUB }); var stopwatch = Stopwatch.StartNew(); - var dbset = db.Set(); + var dbSet = db.Set(); try { - return await db.Database.ExecInsertOrUpdateAsync(dbset, entities, token).ConfigureAwait(false); + return await db.Database.ExecInsertOrUpdateAsync(dbSet, entities, token).ConfigureAwait(false); } catch (Exception ex) { @@ -101,7 +102,7 @@ namespace AsbCloudInfrastructure.Services.SAUB DateTimeOffset dateBeginUtc; if (dateBegin == default) { - var dateRange = telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id); + var dateRange = telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); dateBeginUtc = (dateRange?.To.ToUniversalTime() ?? DateTimeOffset.UtcNow) .AddSeconds(-intervalSec); } @@ -226,17 +227,17 @@ namespace AsbCloudInfrastructure.Services.SAUB if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12)) { - // пробуем обойтись кешем - var cechedRange = telemetryDataCache.GetOrDefaultCachedDateRange(telemetry.Id); - if (cechedRange?.From <= geDate) + // пробуем обойтись кэшем + var cachedRange = telemetryDataCache.GetOrDefaultCachedDataDateRange(telemetry.Id); + if (cachedRange is not null) { - var datesRange = new DatesRangeDto - { - From = geDate.DateTime, - To = cechedRange.To - }; - if (leDate.HasValue && leDate > geDate) - datesRange.To = leDate.Value.Date; + var datesRange = new DatesRangeDto {From = cachedRange.From, To = cachedRange.To }; + if (geDate >= cachedRange.From) + datesRange.From = geDate.ToOffset(cachedRange.From.Offset); + + if (leDate.HasValue && leDate <= cachedRange.To) + datesRange.To = leDate.Value.ToOffset(cachedRange.To.Offset); + return datesRange; } } @@ -248,7 +249,7 @@ namespace AsbCloudInfrastructure.Services.SAUB if(leDate.HasValue) query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime()); - var gquery = query + var groupQuery = query .GroupBy(entity => entity.IdTelemetry) .Select(group => new { @@ -256,14 +257,14 @@ namespace AsbCloudInfrastructure.Services.SAUB MaxDate = group.Max(entity => entity.DateTime), }); - var result = await gquery.FirstOrDefaultAsync(token); + var result = await groupQuery.FirstOrDefaultAsync(token); if (result is null) return null; var range = new DatesRangeDto { - From = result.MinDate.ToOffset(TimeSpan.FromHours(telemetry.TimeZone!.Hours)).DateTime, - To = result.MaxDate.ToOffset(TimeSpan.FromHours(telemetry.TimeZone!.Hours)).DateTime, + From = result.MinDate.ToOffset(telemetry.TimeZone!.Offset), + To = result.MaxDate.ToOffset(telemetry.TimeZone!.Offset), }; return range; } @@ -274,7 +275,7 @@ namespace AsbCloudInfrastructure.Services.SAUB if (telemetry is null) return default; - return telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id); + return telemetryDataCache.GetOrDefaultWellDataDateRange(telemetry.Id); } protected abstract TDto Convert(TEntity src, double timezoneOffset); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 9d99c700..3b9f7166 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -13,347 +13,350 @@ using AsbCloudApp.Data; using AsbCloudApp.Requests; using AsbCloudApp.Repositories; -namespace AsbCloudInfrastructure.Services.SAUB +namespace AsbCloudInfrastructure.Services.SAUB; + +public class TelemetryDataCache : ITelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData { - public class TelemetryDataCache : ITelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData + class TelemetryDataCacheItem { - class TelemetryDataCacheItem + public TDto FirstByDate { get; init; } = default!; + public CyclicArray LastData { get; init; } = null!; + public double TimezoneHours { get; init; } = 5; + public TimeSpan TimezoneOffset => TimeSpan.FromHours(TimezoneHours); + } + + private const int activeWellCapacity = 12 * 60 * 60; + private const int doneWellCapacity = 65 * 60; + + // key == idTelemetry + private readonly ConcurrentDictionary caches; + private bool isLoading = false; + + private TelemetryDataCache() + { + caches = new(); + } + + private static TelemetryDataCache? instance; + + public static TelemetryDataCache GetInstance(IServiceProvider provider) + where TEntity : class, AsbCloudDb.Model.ITelemetryData + { + if (instance is null) { - public TDto FirstByDate { get; init; } = default!; - public CyclicArray LastData { get; init; } = null!; - public double TimezoneHours { get; init; } = 5; + instance = new TelemetryDataCache(); + var worker = provider.GetRequiredService(); + var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; + var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => + { + var db = provider.GetRequiredService(); + await instance.InitializeCacheFromDBAsync(db, onProgress, token); + }); + work.Timeout = TimeSpan.FromMinutes(15); + worker.Enqueue(work); + } + return instance; + } + + /// + /// Добавить новые элементы в кеш + /// + /// + /// + public void AddRange(int idTelemetry, IEnumerable range) + { + if (!range.Any()) + return; + + range = range.OrderBy(x => x.DateTime); + + foreach (var item in range) + item.IdTelemetry = idTelemetry; + + TelemetryDataCacheItem cacheItem; + if (isLoading) + { + if (caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? localCacheItem)) + cacheItem = localCacheItem; + else + return; + } + else + { + cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() + { + FirstByDate = range.ElementAt(0), + LastData = new CyclicArray(activeWellCapacity) + }); } - private const int activeWellCapacity = 12 * 60 * 60; - private const int doneWellCapacity = 65 * 60; + cacheItem.LastData.AddRange(range); + } - // key == idTelemetry - private readonly ConcurrentDictionary caches; - private bool isLoading = false; + /// + /// Получить данные из кеша.
+ /// Если dateBegin меньше минимального элемента в кеше, то вернется null. + /// Даже если intervalSec частично перекрыт данными из кеша. + ///
+ /// + /// + /// + /// кол-во элементов до которых эти данные прореживаются + /// + public IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; - private TelemetryDataCache() + var cacheLastData = cacheItem.LastData; + + if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin) + return null; + + var dateEnd = dateBegin.AddSeconds(intervalSec); + var items = cacheLastData + .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); + + var ratio = items.Count() / approxPointsCount; + if (ratio > 1) + items = items + .Where((_, index) => index % ratio == 0); + + return items; + } + + public IEnumerable GetStat() + { + var result = caches.Select(cacheItem => new TelemetryDataStatDto { - caches = new(); - } + IdTelemetry = cacheItem.Key, + DateFirst = cacheItem.Value.FirstByDate.DateTime, + DateLast = cacheItem.Value.LastData[^1].DateTime, + TimezoneOffsetHours = cacheItem.Value.TimezoneHours, + }); + return result; + } - private static TelemetryDataCache? instance; + public virtual TDto? GetLastOrDefault(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return default; - public static TelemetryDataCache GetInstance(IServiceProvider provider) - where TEntity : class, AsbCloudDb.Model.ITelemetryData - { - if (instance is null) - { - instance = new TelemetryDataCache(); - var worker = provider.GetRequiredService(); - var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; - var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => - { - var db = provider.GetRequiredService(); - await instance.InitializeCacheFromDBAsync(db, onProgress, token); - }); - work.Timeout = TimeSpan.FromMinutes(15); - worker.Enqueue(work); - } - return instance; - } + return cacheItem.LastData.LastOrDefault(); + } - /// - /// Добавить новые элементы в кеш - /// - /// - /// - public void AddRange(int idTelemetry, IEnumerable range) - { - if (!range.Any()) - return; + public DatesRangeDto? GetOrDefaultWellDataDateRange(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; + + if (!cacheItem.LastData.Any()) + return null; - range = range.OrderBy(x => x.DateTime); + var to = FromDate(cacheItem.FirstByDate.DateTime, cacheItem.TimezoneOffset); + var from = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset); - foreach (var item in range) - item.IdTelemetry = idTelemetry; + return new DatesRangeDto { From = from, To = to }; + } - TelemetryDataCacheItem cacheItem; - if (isLoading) - { - if (caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? localCacheItem)) - cacheItem = localCacheItem; - else - return; - } - else - { - cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() - { - FirstByDate = range.ElementAt(0), - LastData = new CyclicArray(activeWellCapacity) - }); - } - - cacheItem.LastData.AddRange(range); - } + public DatesRangeDto? GetOrDefaultCachedDataDateRange(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; - /// - /// Получить данные из кеша.
- /// Если dateBegin меньше минимального элемента в кеше, то вернется null. - /// Даже если intervalSec частично перекрыт данными из кеша. - ///
- /// - /// - /// - /// кол-во элементов до которых эти данные прореживаются - /// - public IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) - { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return null; + if (cacheItem.LastData.Count < 2) + return null; - var cacheLastData = cacheItem.LastData; + var to = FromDate(cacheItem.LastData[^1].DateTime, cacheItem.TimezoneOffset); + var from = FromDate(cacheItem.LastData[0].DateTime, cacheItem.TimezoneOffset); - if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin) - return null; + return new DatesRangeDto { From = from, To = to }; + } - var dateEnd = dateBegin.AddSeconds(intervalSec); - var items = cacheLastData - .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); + public (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; - var ratio = items.Count() / approxPointsCount; - if (ratio > 1) - items = items - .Where((_, index) => index % ratio == 0); + if (!cacheItem.LastData.Any()) + return null; - return items; - } + var last = cacheItem.LastData[^1]; + var first = cacheItem.FirstByDate; + return (first, last); + } - public IEnumerable GetStat() - { - var result = caches.Select(cacheItem => new TelemetryDataStatDto - { - IdTelemetry = cacheItem.Key, - DateFirst = cacheItem.Value.FirstByDate.DateTime, - DateLast = cacheItem.Value.LastData[^1].DateTime, - TimezoneOffsetHours = cacheItem.Value.TimezoneHours, - }); - return result; - } + private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) + where TEntity : class, AsbCloudDb.Model.ITelemetryData + { + var defaultTimeout = db.Database.GetCommandTimeout(); + db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - public virtual TDto? GetLastOrDefault(int idTelemetry) - { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return default; + if (isLoading) + throw new Exception("Multiple cache loading detected."); - return cacheItem.LastData.LastOrDefault(); - } - - public DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry) - { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return null; - - if (!cacheItem.LastData.Any()) - return null; - - var from = DateTime.SpecifyKind(cacheItem.FirstByDate.DateTime, DateTimeKind.Unspecified); - var to = DateTime.SpecifyKind(cacheItem.LastData[^1].DateTime, DateTimeKind.Unspecified); - - return new DatesRangeDto - { - From = new DateTimeOffset(from, TimeSpan.FromHours(cacheItem.TimezoneHours)), - To = new DateTimeOffset(to, TimeSpan.FromHours(cacheItem.TimezoneHours)) - }; - } - - public DatesRangeDto? GetOrDefaultCachedDateRange(int idTelemetry) - { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return null; - - if (cacheItem.LastData.Count < 2) - return null; - - var to = cacheItem.LastData[^1].DateTime; - var from = cacheItem.LastData[0].DateTime; - - return new DatesRangeDto { From = from, To = to }; - } - - public (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry) - { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return null; - - if (!cacheItem.LastData.Any()) - return null; - - var last = cacheItem.LastData[^1]; - var first = cacheItem.FirstByDate; - return (first, last); - } - - private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) - where TEntity : class, AsbCloudDb.Model.ITelemetryData - { - var defaultTimeout = db.Database.GetCommandTimeout(); - db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - - if (isLoading) - throw new Exception("Multiple cache loading detected."); - - try - { - isLoading = true; - - Well[] wells = await db.Set() - .Include(well => well.Telemetry) - .Include(well => well.Cluster) - .Where(well => well.IdTelemetry != null) - .ToArrayAsync(token); - - var count = wells.Length; - var i = 0d; - foreach (Well well in wells) - { - var capacity = well.IdState == 1 - ? activeWellCapacity - : doneWellCapacity; - - var idTelemetry = well.IdTelemetry!.Value; - var hoursOffset = well.Timezone.Hours; - - onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); - var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); - if (cacheItem is not null) - caches.TryAdd(idTelemetry, cacheItem); - } - } - finally - { - isLoading = false; - db.Database.SetCommandTimeout(defaultTimeout); - } - } - - private static async Task GetOrDefaultCacheDataFromDbAsync(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token) - where TEntity : class, AsbCloudDb.Model.ITelemetryData - { - var query = db.Set() - .Where(i => i.IdTelemetry == idTelemetry); - - var firstDbEntity = await query - .OrderBy(i => i.DateTime) - .FirstOrDefaultAsync(token); - - if (firstDbEntity is null) - return default; - - var first = firstDbEntity.Adapt(); - first.DateTime = firstDbEntity.DateTime.ToRemoteDateTime(hoursOffset); - - var entities = await query - .OrderByDescending(i => i.DateTime) - .Take(capacity) + try + { + isLoading = true; + + Well[] wells = await db.Set() + .Include(well => well.Telemetry) + .Include(well => well.Cluster) + .Where(well => well.IdTelemetry != null) .ToArrayAsync(token); - var dtos = entities - .AsEnumerable() - .Reverse() - .Select(entity => - { - var dto = entity.Adapt(); - dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); - return dto; - }); - - var cacheItem = new CyclicArray(capacity); - cacheItem.AddRange(dtos); - - var item = new TelemetryDataCacheItem + var count = wells.Length; + var i = 0d; + foreach (Well well in wells) { - FirstByDate = first, - LastData = cacheItem, - TimezoneHours = hoursOffset, - }; - return item; + var capacity = well.IdState == 1 + ? activeWellCapacity + : doneWellCapacity; + + var idTelemetry = well.IdTelemetry!.Value; + var hoursOffset = well.Timezone.Hours; + + onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); + var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); + if (cacheItem is not null) + caches.TryAdd(idTelemetry, cacheItem); + } } - - public IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request) + finally { - if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - return null; - - IEnumerable data = cacheItem.LastData; - - if (!data.Any()) - return null; - - if (request.GeDate.HasValue) - { - var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); - if (data.First().DateTime > geDate) - return null; - - data = data.Where(d => d.DateTime >= geDate); - } - else - { - if (request.Order == 0) - return null; - } - - if (request.LeDate.HasValue) - { - var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); - data = data.Where(d => d.DateTime <= request.LeDate); - } - - if (request.Divider > 1) - data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); - - switch (request.Order) - { - case 1: // Поздние вперед - data = data - .OrderByDescending(d => d.DateTime) - .Skip(request.Skip) - .Take(request.Take) - .OrderBy(d => d.DateTime); - break; - default: // Ранние вперед - data = data - .OrderBy(d => d.DateTime) - .Skip(request.Skip) - .Take(request.Take); - break; - } - - return data; - } - - public IEnumerable GetIds(TelemetryDataRequest request) - { - var data = caches.Where(i => i.Value.LastData.Count > 0); - - if (request.GeDate.HasValue) - { - data = data - .Where(item => { - var lastItem = item.Value.LastData.Last(); - var geDate = request.GeDate.Value.ToOffset(TimeSpan.FromHours(item.Value.TimezoneHours)); - return lastItem.DateTime >= geDate; - }); - } - - if (request.LeDate.HasValue) - { - data = data - .Where(item => { - var firstItem = item.Value.LastData.First(); - var leDate = request.LeDate.Value.ToOffset(TimeSpan.FromHours(item.Value.TimezoneHours)); - return firstItem.DateTime <= leDate; - }); - } - - var telemetryIds = data.Select(item => item.Key); - return telemetryIds; + isLoading = false; + db.Database.SetCommandTimeout(defaultTimeout); } } + + private static async Task GetOrDefaultCacheDataFromDbAsync(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token) + where TEntity : class, AsbCloudDb.Model.ITelemetryData + { + var query = db.Set() + .Where(i => i.IdTelemetry == idTelemetry); + + var firstDbEntity = await query + .OrderBy(i => i.DateTime) + .FirstOrDefaultAsync(token); + + if (firstDbEntity is null) + return default; + + var first = firstDbEntity.Adapt(); + first.DateTime = firstDbEntity.DateTime.ToRemoteDateTime(hoursOffset); + + var entities = await query + .OrderByDescending(i => i.DateTime) + .Take(capacity) + .ToArrayAsync(token); + + var dtos = entities + .AsEnumerable() + .Reverse() + .Select(entity => + { + var dto = entity.Adapt(); + dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); + return dto; + }); + + var cacheItem = new CyclicArray(capacity); + cacheItem.AddRange(dtos); + + var item = new TelemetryDataCacheItem + { + FirstByDate = first, + LastData = cacheItem, + TimezoneHours = hoursOffset, + }; + return item; + } + + public IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; + + IEnumerable data = cacheItem.LastData; + + if (!data.Any()) + return null; + + if (request.GeDate.HasValue) + { + var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); + if (data.First().DateTime > geDate) + return null; + + data = data.Where(d => d.DateTime >= geDate); + } + else + { + if (request.Order == 0) + return null; + } + + if (request.LeDate.HasValue) + { + var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); + data = data.Where(d => d.DateTime <= request.LeDate); + } + + if (request.Divider > 1) + data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); + + switch (request.Order) + { + case 1: // Поздние вперед + data = data + .OrderByDescending(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take) + .OrderBy(d => d.DateTime); + break; + default: // Ранние вперед + data = data + .OrderBy(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take); + break; + } + + return data; + } + + public IEnumerable GetIds(TelemetryDataRequest request) + { + var data = caches.Where(i => i.Value.LastData.Count > 0); + + if (request.GeDate.HasValue) + { + data = data + .Where(item => { + var lastItem = item.Value.LastData.Last(); + var geDate = request.GeDate.Value.ToOffset(TimeSpan.FromHours(item.Value.TimezoneHours)); + return lastItem.DateTime >= geDate; + }); + } + + if (request.LeDate.HasValue) + { + data = data + .Where(item => { + var firstItem = item.Value.LastData.First(); + var leDate = request.LeDate.Value.ToOffset(TimeSpan.FromHours(item.Value.TimezoneHours)); + return firstItem.DateTime <= leDate; + }); + } + + var telemetryIds = data.Select(item => item.Key); + return telemetryIds; + } + + private static DateTimeOffset FromDate(DateTime dateTime, TimeSpan timezoneOffset) + { + var dateTimeNoKind = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified); + var dateTimeOffset = new DateTimeOffset(dateTimeNoKind, timezoneOffset); + return dateTimeOffset; + } } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs index c0675221..7977b1ab 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs @@ -51,7 +51,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public DatesRangeDto GetDatesRange(int idTelemetry) { - var cacheDataRange = dataSaubCache.GetOrDefaultDataDateRange(idTelemetry) + var cacheDataRange = dataSaubCache.GetOrDefaultWellDataDateRange(idTelemetry) ?? new (); return cacheDataRange; }