2023-06-30 15:49:30 +05:00
|
|
|
|
// Ignore Spelling: Linq
|
|
|
|
|
|
|
|
|
|
using System;
|
2021-12-30 17:05:44 +05:00
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure
|
|
|
|
|
{
|
2023-06-30 15:49:30 +05:00
|
|
|
|
public static class DateTimeExtensions
|
2021-12-30 17:05:44 +05:00
|
|
|
|
{
|
2023-01-11 16:00:11 +05:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Приветсти к UTC из времени куста
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="date"></param>
|
|
|
|
|
/// <param name="remoteTimezoneOffsetHours"></param>
|
|
|
|
|
/// <returns></returns>
|
2021-12-30 17:05:44 +05:00
|
|
|
|
public static DateTimeOffset ToUtcDateTimeOffset(this DateTime date, double remoteTimezoneOffsetHours)
|
|
|
|
|
{
|
|
|
|
|
if (date == default)
|
|
|
|
|
return new DateTimeOffset();
|
|
|
|
|
|
|
|
|
|
var dateUtc = date.Kind switch
|
|
|
|
|
{
|
|
|
|
|
DateTimeKind.Local => date.ToUniversalTime(),
|
2022-01-05 17:50:45 +05:00
|
|
|
|
DateTimeKind.Unspecified => DateTime.SpecifyKind(date.AddHours(-remoteTimezoneOffsetHours), DateTimeKind.Utc),
|
2021-12-30 17:05:44 +05:00
|
|
|
|
_ => date,
|
|
|
|
|
};
|
2022-04-11 18:00:34 +05:00
|
|
|
|
return new DateTimeOffset(dateUtc);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 16:00:11 +05:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Привести ко времени куста из utc
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="date"></param>
|
|
|
|
|
/// <param name="remoteTimezoneOffsetHours"></param>
|
|
|
|
|
/// <returns></returns>
|
2021-12-30 17:05:44 +05:00
|
|
|
|
public static DateTime ToRemoteDateTime(this DateTimeOffset date, double remoteTimezoneOffsetHours)
|
|
|
|
|
{
|
|
|
|
|
if (date == default)
|
|
|
|
|
return new DateTime(0, DateTimeKind.Unspecified);
|
|
|
|
|
var dateTz = date.ToOffset(TimeSpan.FromHours(remoteTimezoneOffsetHours));
|
|
|
|
|
return dateTz.DateTime;
|
|
|
|
|
}
|
2023-04-05 13:35:54 +05:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Поиск индекса близкого к value значения в span.
|
|
|
|
|
/// Элементы в span должны быть отсортированы по возрастанию по полю propertyGetter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
/// <typeparam name="TProp"></typeparam>
|
|
|
|
|
/// <param name="span"></param>
|
|
|
|
|
/// <param name="propertyGetter">метод получения свойства из объекта класса T</param>
|
|
|
|
|
/// <param name="value">искомое значение</param>
|
|
|
|
|
/// <param name="maxIterations">максимальное кол-во итераций. Прим.:
|
|
|
|
|
/// в span из 4000 записей достаточно 9-ти итераций
|
|
|
|
|
/// 8_000 => 10 итераций;
|
|
|
|
|
/// 16_000 => 11;
|
|
|
|
|
/// ...
|
|
|
|
|
/// 256_000 => 15;
|
|
|
|
|
/// При недостаточном кол-ве итераций индекс может оказаться близко, но это будет не ближайшее значение
|
|
|
|
|
/// </param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static int BinarySearch<T, TProp>(this Span<T> span, Func<T, TProp> propertyGetter, TProp value, int maxIterations = 16)
|
|
|
|
|
where TProp : IComparable
|
|
|
|
|
{
|
|
|
|
|
if (span.Length < 2 || --maxIterations < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
var indexOfMiddle = span.Length >> 1;
|
|
|
|
|
|
|
|
|
|
var comparison = value.CompareTo(propertyGetter(span[indexOfMiddle]));
|
|
|
|
|
|
|
|
|
|
if (comparison > 0)
|
|
|
|
|
{
|
|
|
|
|
var index = indexOfMiddle + 1 + BinarySearch(span[(indexOfMiddle + 1)..], propertyGetter, value, maxIterations);
|
|
|
|
|
return index < span.Length ? index : span.Length - 1;
|
|
|
|
|
}
|
|
|
|
|
else if (comparison < 0)
|
|
|
|
|
return BinarySearch(span[..(indexOfMiddle)], propertyGetter, value, maxIterations);
|
|
|
|
|
else //if (comparison == 0)
|
|
|
|
|
return indexOfMiddle;
|
|
|
|
|
}
|
2021-12-30 17:05:44 +05:00
|
|
|
|
}
|
|
|
|
|
}
|