Получение миллисекунд до следующего полудня


Мне нужно, чтобы получить общее миллисекунд до следующего полудня (12:00:00) для сигнала таймер, который будет выполняться раз в день.

Предполагая, что приложение может быть закрыли и начали в любое время, это код, чтобы получить миллисекунд осталось до полудня (используется для установки таймера) правильно? (Он не должен быть точным; он может быть выключен на несколько секунд.)

TimeSpan now = DateTime.Now.TimeOfDay;
TimeSpan target = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 12, 0, 0).TimeOfDay;

double r = target.TotalMilliseconds - now.TotalMilliseconds;

if (r > 0) // It's before noon
    ;
else // It's after noon
    r = TimeSpan.FromTicks(TimeSpan.TicksPerDay).TotalMilliseconds + r;

t = new Timer(DoWork, null, r, TimeSpan.FromTicks(TimeSpan.TicksPerDay));

Это может быть сделано более эффективно и за меньшее количество строк кода?



6595
10
задан 18 апреля 2011 в 08:04 Источник Поделиться
Комментарии
6 ответов

С точки зрения эффективности, вы не должны беспокоиться об этом. Но я думаю, что вы могли бы сделать это немного более читабельным / пояснений и чуть менее сложным, чем это / выглядит.

/// <summary>
/// Returns the period of time left before the specified hour is due to elapse
/// </summary>
/// <param name="hour">And integer representing an hour,
/// where 0 is midnight, 12 is midday, 23 is eleven et cetera</param>
/// <returns>A TimeSpan representing the calculated time period</returns>
public static TimeSpan GetTimeUntilNextHour(int hour)
{
var currentTime = DateTime.Now;
var desiredTime = new DateTime(DateTime.Now.Year,
DateTime.Now.Month, DateTime.Now.Day, hour, 0, 0);
var timeDifference = (currentTime - desiredTime);
var timePeriod = currentTime.Hour >= hour ?
(desiredTime.AddDays(1) - currentTime) :
-timeDifference;
return timePeriod;
}

Оглядываясь назад и во многом из-за моего внимания на комментарии, это может быть короче, опуская timeDifference переменные и расчете в он-лайн, кроме того, мы не должны обесценивать либо; и также мы можем вернуть , а не назначить промежуток времени:

var currentTime = DateTime.Now;
var desiredTime = new DateTime(DateTime.Now.Year,
DateTime.Now.Month, DateTime.Now.Day, hour, 0, 0);
return currentTime.Hour >= hour ?
(desiredTime.AddDays(1) - currentTime) :
desiredTime - currentTime;

Здесь несколько заметок, чтобы претендовать на мое заявление...


  • Линии не очень дорогие, но если вы должны иметь это на восемь строк, можно еще сделать так - я нарочно уронил desiredTime , чтобы покрыть две линии, а не строго, чтобы остаться на безопасной стороне от истории (хотя это помогает), а просто для поддержания потока, где линии окончаний являются относительными, а не единичные, думаю, что в мягкой обложке книга.

  • Я бы порекомендовал называть вещи метко, что иногда люди не обязательно нужно рассматривать как код делает то, что он делает, что позволяет им: а) отсканировать и найти, что они ищут или Б) выяснить это без того, чтобы удивляться, что переживала , что ребята, с головой.

  • Использования неявно типизированных переменных (ВАР), они доступны из C# 3.0 года; эта особенность дает нам возможность не указывать конкретный тип имя полностью при присвоении значения / ссылка в объявлении - просто быть уверены, чтобы использовать это мудро, чистота должна поддерживаться для читателя. Вы не указали, какой языковой вариант вы используете, так что это не может быть доступна для вас, но имейте это в виду на будущее.

  • Датавремя предоставляет операторам , что позволит нам работать с ними непосредственно в этом экземпляре, так что не надо заморачиваться с FromTicks, TotalMilliseconds, TotalTicks, TimeOfDay и так далее.

  • Как окончательное Примечание: пустой оператор (;) генерирует предупреждение компилятора, они не должны быть проигнорированы, и в любом месте я знаю, вы, по крайней мере, чтобы объясниться, если кто-то сталкивался с этим; оно может также произвести-Ошибка времени компиляции, в зависимости от окружающей среды, что и в предыдущем состоянии не только излишним в данном случае, но ни они указывают на что-нибудь, настолько, что даже вы считали своим долгом оставить комментарий.

4
ответ дан 19 апреля 2011 в 12:04 Источник Поделиться

if (r > 0) // It's before noon
;
else // It's after noon
r = TimeSpan.FromTicks(TimeSpan.TicksPerDay).TotalMilliseconds + r;

Изменение:

if (r <= 0) // It's after noon
r = TimeSpan.FromTicks(TimeSpan.TicksPerDay).TotalMilliseconds + r;

Не надо , если это ничего не делает.

8
ответ дан 18 апреля 2011 в 08:04 Источник Поделиться


  1. Потому что мне это нравится (по крайней мере, одно, что я не совсем потерянный в):

    long now = DateTime.Now.Ticks;
    const long noon = TimeSpan.TicksPerHour*12;
    long r = ((noon - now + TimeSpan.TicksPerDay) % TimeSpan.TicksPerDay)
    / TimeSpan.TicksPerMillisecond;

    Нет филиалов, минимальный преобразования, а не с плавающей точкой. Не слишком много "магии", если вы знаете, почему модуль работает и почему добавлено TicksPerDay необходимо.


  2. Замечу, что этот вопрос кажется форма преждевременной (и ошибочной) оптимизация, если это чисто теоретическое упражнение (форма гольф-код?) - наверное, лучше оставить его в форме, вы понимаете, особенно если этот код выполняется только один раз (или один раз в день). Если ты делаешь это один миллион раз, то вы создаете миллион таймерС.

8
ответ дан 19 апреля 2011 в 02:04 Источник Поделиться

Я бы оставил ваш код в основном как есть, по крайней мере логика, но ИМО есть некоторые проблемы читабельности:


  • пустой , если заявление. Как уже упоминалось, есть и другие способы показать, что вы сделали оба сценария были учтены.

  • Р переменной? Что-то более вразумительное, может быть здесь. millisecondsToTarget?

  • Я бы тоже заменить промежутка времени.FromTicks(Промежутка Времени.TicksPerDay) с промежутка времени.FromDays(1) , но это очень субъективно, я вижу смысл в вашем варианте тоже.

4
ответ дан 19 апреля 2011 в 07:04 Источник Поделиться

В обычный день есть 43,200,000 МС. от полуночи до полудня. Сколько там от полуночи до полудня в дни перехода на летнее время начинается / заканчивается, иными словами, есть проблема, используя разность двух datetime-значений в эти дни?

Если вы собираетесь использовать разница между двумя datetime-значений, то используйте версию мирового из них.

3
ответ дан 19 апреля 2011 в 12:04 Источник Поделиться


  1. Мне не нравится, как вы чередовать вызовы времени.Теперь с расчетом. Делает его трудно проверить.

    Я рекомендую отделять логику от внешнего состояния, такие как часы. Я предпочитаю писать логику в функциональном стиле: простые входы, которые производят выходной, ничего не трогая.


  2. Называть Даты.Теперь несколько раз могут давать разные результаты каждый раз в принципе, но это маловероятно на практике.

  3. Предполагая, что вы используете систему.Резьбонарезной.Таймер, вы не нуждаетесь в миллисекундах, так как таймер принимает значение типа TimeSpan.

    Аналогичным образом, обращаясь к клещей бесполезны. Просто использовать стили.FromDays(1) или период.FromHours(12).


Так что я бы создать одну функцию, содержащий логику:

private static TimeSpan TimeUntilMidday(DateTime current)
{
DateTime target = current.Date.AddHours(12);// today's midday
if(target < current)
target = target.AddDays(1); // tomorrow's midday
return target - current;
}

И затем использовать его с:

new Timer(DoWork, null, TimeUntilMidday(DateTime.Now), TimeSpan.FromDays(1))

Это делает его легко добавить тест-кейсов для случаев:

Assert(TimeUntilMidday(new DateTime(2000, 1, 1, 12, 0, 0)) == TimeSpan.Zero)

Такого теста можно четко документировать свои намерения в такой особый случай. Без этого непонятно, что вы хотите сделать, если это в настоящее время ровно полдень - бежать сразу или подождать полный день.

2
ответ дан 4 февраля 2013 в 04:02 Источник Поделиться