Введение
Здесь довольно много решений, и я начал задумываться об их эффективности (эффективность, вероятно, не самый важный аспект в этой проблеме). Я взял немного отсюда и добавил пару своих. (Нет, хотя ОП спрашивал о округлении до ближайших 15 минут, я сделал мои сравнения и выборки всего за 1 минуту / 60 с ради более простых выборок).
Настройка
Benchmark.bmbm do |x|
x.report("to_f, /, floor, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).floor * 60) } }
x.report("to_i, /, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_i / 60) * 60) } }
x.report("to_i, %, - and Time.at") { 1_000_000.times { t = Time.now.to_i; Time.at(t - (t % 60)) } }
x.report("to_i, %, seconds and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60).seconds } }
x.report("to_i, % and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60) } }
end
Результаты
Rehearsal -----------------------------------------------------------------
to_f, /, floor, * and Time.at 4.380000 0.010000 4.390000 ( 4.393235)
to_i, /, * and Time.at 3.270000 0.010000 3.280000 ( 3.277615)
to_i, %, - and Time.at 3.220000 0.020000 3.240000 ( 3.233176)
to_i, %, seconds and - 10.860000 0.020000 10.880000 ( 10.893103)
to_i, % and - 4.450000 0.010000 4.460000 ( 4.460001)
------------------------------------------------------- total: 26.250000sec
user system total real
to_f, /, floor, * and Time.at 4.400000 0.020000 4.420000 ( 4.419075)
to_i, /, * and Time.at 3.220000 0.000000 3.220000 ( 3.226546)
to_i, %, - and Time.at 3.270000 0.020000 3.290000 ( 3.275769)
to_i, %, seconds and - 10.910000 0.010000 10.920000 ( 10.924287)
to_i, % and - 4.500000 0.010000 4.510000 ( 4.513809)
Анализ результатов
Что с этим делать? Ну, на вашем оборудовании все может работать быстрее или медленнее, так что не верьте мне на слово. Как вы можете видеть, другая вещь заключается в том, что, если мы не будем выполнять эти операции в масштабе миллионов операций, не будет иметь большого значения, какой метод вы используете в отношении вычислительной мощности (хотя, обратите внимание, что, например, большинство решений облачных вычислений обеспечивает очень небольшую вычислительную мощность, и, следовательно, в таких средах миллионы могут составлять сотни или десятки тысяч).
Самое медленное, но, вероятно, самое читаемое решение
В этом смысле использование явно самого медленного из них t = Time.now; t - (t.to_i % 60).seconds
может быть оправдано только потому, что .seconds там так круто.
Не такое медленное и почти читаемое решение
Однако, поскольку он на самом деле совсем не нужен и делает операцию более чем в два раза дороже, чем без нее, я должен сказать, что мой выбор - t = Time.now; t - (t.to_i % 60)
. На мой взгляд, это достаточно быстро и в миллион раз более читабельно, чем любое другое решение, представленное здесь. Вот почему я считаю, что это лучшее решение для ваших повседневных нужд, хотя оно значительно медленнее, чем три других.
неудобно и не особенно медленно или быстро
Самое популярное решение на этой странице Time.at((Time.now.to_f / 60).floor * 60)
- самое медленное из всех решений на этой странице (до этого ответа) и значительно медленнее, чем два верхних решения. Использование поплавков только для того, чтобы уложить десятичные дроби, также кажется очень нелогичным. Для части округления это было бы нормально, но округление для меня звучит как "настил". Во всяком случае, аналогом для этого может быть округление вверх или «потолок», что-то вроде t = Time.now; t - (60 - t.to_i % 60) % 60
или Time.at((Time.now.to_f / 60).ceil * 60)
. Двойное значение по модулю, в котором нуждается решение to_i, выглядит немного неприятно, поэтому, хотя оно и значительно быстрее, здесь я бы предпочел метод ceil. (Тесты добавлены в самом конце этого поста)
Для нуждающихся в скорости
Связанные (различия настолько незначительны, что вы не можете в действительности объявить победителя) два лучших исполнителя в тесте, где два варианта to_i, использующие несколько различную комбинацию операций, а затем преобразуют целое число обратно в объект Time. Если вы спешите, вот те, которые вы должны использовать:
Time.at((Time.now.to_i / 60) * 60)
t = Time.now.to_i; Time.at(t - (t % 60))
Установка для округления / потолка
Benchmark.bmbm do |x|
x.report("to_f, /, ceil, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).ceil * 60) } }
x.report("to_i, %, -, %, + and Time.at") { 1_000_000.times { t = Time.now; t + (60 - t.to_i % 60) % 60 } }
end
Результаты округления вверх / потолок.
Rehearsal ----------------------------------------------------------------
to_f, /, ceil, * and Time.at 4.410000 0.040000 4.450000 ( 4.446320)
to_i, %, -, %, + and Time.at 3.910000 0.020000 3.930000 ( 3.939048)
------------------------------------------------------- total: 8.380000sec
user system total real
to_f, /, ceil, * and Time.at 4.420000 0.030000 4.450000 ( 4.454173)
to_i, %, -, %, + and Time.at 3.860000 0.010000 3.870000 ( 3.884866)