TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #3038 2.8K
День 2526. #ЗаметкиНаПолях
Task.Delay Выдаёт Ошибку при Ожидании Дольше 49,7 Дней

В последний рабочий день года немного (бес)полезной информации.

Метод Task.Delay завершается с ошибкой, если вы ждёте дольше 49,7 дней. Т.е.
await Task.Delay(TimeSpan.FromDays(50));

завершится ошибкой.
System.ArgumentOutOfRangeException: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0, or a positive integer less than or equal to the maximum allowed timer duration. (Значение должно в миллисекундах соответствовать -1 (что означает бесконечный таймаут), 0 или положительному целому числу, меньшему или равному максимально допустимой длительности таймера.)

При этом TimeSpan.FromDays(49) работает. Почему так происходит, мы же используем положительное число. И стоит ли об этом беспокоиться?

«Под капотом» Task.Delay в качестве базовой единицы измерения использует uint и выполняет такую проверку:
internal static uint 
ValidateTimeout(
TimeSpan timeout,
ExceptionArgument argument)
{
long totalMilliseconds = (long)timeout.TotalMilliseconds;
if (totalMilliseconds < -1L
|| totalMilliseconds > 4294967294L)
ThrowHelper.ThrowArgumentOutOfRangeException(
argument,
ExceptionResource.Task_InvalidTimerTimeSpan);
return (uint)totalMilliseconds;
}

Поэтому максимальное значение равно uint.MaxValue-1, что равно "4294967294U". Это в миллисекундах, либо: 4294967294мс / 1000 (секунд) / 60 (минут) / 60 (часов) / 24 (дней) = 49,7103 дня.

Стоит ли об этом беспокоиться?
Скорее всего, нет. Только если вы не пишете какую-нибудь фоновую логику, которая должна отложить выполнение работы на очень далёкое будущее. Например, свой планировщик заданий, где пользователь может ввести любую нотацию CRON, и это должно работать. Так что, если пользователь хочет, чтобы задание выполнялось, скажем, только раз в год, конечно, это должно быть доступно. Что делать? Можно вызывать Task.Delay в цикле, пока всё время не истечёт:
internal static class TaskExtensions
{
public static async Task LongDelaySafe(
TimeSpan targetTimeSpan,
TimeProvider timeProvider,
CancellationToken token)
{
ArgumentOutOfRangeException
.ThrowIfLessThanOrEqual(
targetTimeSpan,
TimeSpan.Zero);

var remaining = targetTimeSpan;
while (remaining > TimeSpan.Zero)
{
var delay =
TimeSpan.FromMilliseconds(
Math.Min(
remaining.TotalMilliseconds,
uint.MaxValue-1)
);

await Task.Delay(delay, timeProvider, ct)
.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
remaining -= delay;
}
}
}


Источник: https://steven-giesel.com/blogPost/c3bdad0d-f9eb-4dcf-b650-98ec0f5dd4d4/taskdelay-fails-if-you-wait-longer-than-497-days
  • 👍 9
More from @netdeveloperdiary
  1. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  2. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  3. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  4. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  5. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  6. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →