дата: получить текущий 15-минутный интервал


15

Можно ли каким-то образом узнать текущий 15-минутный интервал с помощью команды date или аналогичной?

например, что-то вроде даты %Y.%m.%d %H:%M даст мне 2011.02.22 10:19, мне нужно что-то, что дает 2011.02.22 10:15в промежуток времени от 10:15до 10:29.

Ответы:


17

Вы можете получить текущую метку времени Unix date "+%s", найти текущую четверть часа с помощью простой математики (мой пример bash) и распечатать ее в лучшем формате с помощью date:

curdate=`date "+%s"`
curquarter=$(($curdate - ($curdate % (15 * 60))))
date -d"@$curquarter"

@Синтаксис для установки текущей даты и времени с отметки времени является GNU продлением на сегодняшний день, если она не работает на вашей операционной системе, вы можете сделать то же самое , как это (не забудьте указать UTC, в противном случае, он выиграл» т работа):

date -d"1970-01-01 $curquarter seconds UTC"

5

Следующие методы делают ненужным вызывать dateдважды.
Затраты на системный вызов могут сделать «простую» команду в 100 раз медленнее, чем bash, которая делает то же самое в своей локальной среде.

ОБНОВЛЕНИЕ Просто краткое упоминание моего комментария: «в 100 раз медленнее». Теперь он может читать "в 500 раз медленнее" ... Я недавно (не ходил вслепую) в эту самую проблему. вот ссылка: Быстрый способ создания тестового файла

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
[[ "$M" < "15" ]] && M=00 # cater for octal clash
M=$(((M/15)*15))
((M==0)) && M=00 # the math returns 0, so make it 00  
echo $Y.$m.$d $H:$M  

или

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
if   [[ "$M" < "15" ]] ; then M=00
elif [[ "$M" < "30" ]] ; then M=15
elif [[ "$M" < "45" ]] ; then M=30
else M=45
fi
echo $Y.$m.$d $H:$M

Вернутся только обе версии

2011.02.23 01:00
2011.02.23 01:15
2011.02.23 01:30
2011.02.23 01:45   

Вот первый с циклом TEST для всех 60 значений {00..59}

for X in {00..59} ;                         ###### TEST
do                                          ###### TEST 
  eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
  M=$X                                      ###### TEST 
  [[ "$M" < "15" ]] && M=00 # cater for octal clash
  M=$(((M/15)*15))
  ((M==0)) && M=00 # the math returns 0, so make it 00  
  echo $Y.$m.$d $H:$M 
done                                        ###### TEST 

1
Просто для пояснения - под «системным вызовом» вы подразумеваете «fork / exec / wait, как вызов system ()», а не системный вызов в целом. (Я упоминаю об этом, потому что выполнение системных вызовов также связано с накладными расходами в программе из-за переключателя пользователь / ядро. Здесь это не особая проблема.)
mattdm

mattdm ... Спасибо .. Я работаю только с 6-месячным опытом работы с Linux, так что я, скорее всего, использовал неправильную фразу, но я продолжаю читать о накладных расходах, вызванных ненужными вызовами, и на своем собственном опыте тестирования своего собственного сценариев, я видел много примеров, когда вызов printfили, sedа также то, что «ненужный» catvs <файл действительно имеет существенное различие во время выполнения. при зацикливании, как в моем примере «в 500 раз медленнее». Поэтому кажется, что использование оболочки везде, где это возможно, и разрешение программы, например, dateдля пакетной обработки, это то, что я имею в виду ... например. Gilles 'Left-Pad-0 пример, против printf
Peter.O

3

Вот способ работы с датами в оболочке. Сначала вызовите, dateчтобы получить компоненты, и заполните позиционные параметры ( $1и $2т. Д.) Компонентами (обратите внимание, что это один из тех редких случаев, когда вы хотите использовать $(…)за пределами двойных кавычек, чтобы разбить строку на слова). Затем выполните арифметику, тесты или все, что вам нужно сделать с компонентами. Наконец собрать компоненты.

Арифметическая часть может быть немного хитрой, потому что оболочки воспринимаются 0как восьмеричный префикс; например, здесь $(($5/15))произойдет сбой в 8 или 9 минут после часа. Поскольку существует не более одного ведущего 0, ${5#0}безопасно для арифметики. Добавление 100 и последующее удаление 1- это способ получить фиксированное количество цифр в выводе.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"

"Уловки торговли" ... хороший. :)
Peter.O

2

Может быть, это уже не имеет значения, но вы можете попробовать мои собственные dateutils . Округление (вниз) до минут выполняется с droundотрицательным аргументом:

dround now /-15m
=>
  2012-07-11T13:00:00

Или придерживаться вашего формата:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00

Это на самом деле, как ваши утилиты работают больше? используя -15m, я получаю перемотку ввода с точностью до 15 минут за час: не dateutils.dround '2018-11-12 13:55' -15mпроизводит . 2018-11-12T13:15:002018-11-12T13:45:00

1
@JackDouglas Инструменты эволюционировали, то, что вы хотите сейчас: /-15mт.е. округлите до следующего кратного 15 минутам в час. Эта функция получила более громоздкий синтаксис, потому что она принимает меньше значений, / -13m, например, невозможно, потому что 13 не является делителем 60 (минут в час)
hroptatyr

хорошо, я получаю то, что мне нужно сейчас dateutils.dround '2018-11-12 12:52:31' /450s /-15m, спасибо!

2

Некоторые оболочки могут выполнять эту работу без вызова внешней dateкоманды:

a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zmodload zsh/datetime; a=$EPOCHSECONDS; strftime '%Y-%m-%d %H:%M' $((a-a%(15*60)))

Три приведенных выше обеспечивают местное (не UTC) время. Используйте ведущий TZ = UTC0, если это необходимо.

Синтаксис ksh и bash практически идентичен (за исключением обязательного #в ksh). Для zsh требуется загрузить модуль (входит в дистрибутив zsh).

Это также возможно сделать с помощью (GNU) awk:

awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'

Это обеспечивает результат UTC (измените последний 1на 0), если требуется local. Но загрузка внешнего awk или внешнего zsh-модуля может быть такой же медленной, как и сама дата вызова:

a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Маленький исполняемый файл like busyboxможет дать аналогичные результаты:

a=$(busybox date +%s);busybox date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Обратите внимание, что начальное слово busybox может быть опущено, если busybox связан с этими именами в каталоге PATH.

Оба dateи busybox dateвыше будет печатать время UTC. Удалить -uопцию для местного времени.


Если ваша ОС имеет более ограниченную версию даты (и это то, что вы должны использовать), попробуйте:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -d"1970-01-01 $a seconds UTC" +'%Y.%m.%d %H:%M'

Или, если во FreeBSD, попробуйте:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'

1

Если вы можете прожить с датой звонка два раза, это работает в bash на Solaris:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"

Отредактировано от имени комментария:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'

1
В первом квартале часа это приведет к выводу минут только с одним 0 вместо 00
Peter.O

Исправлено, это просто sed после оригинальной команды.
ddeimeke

Еще одна ошибка: она не работает между H: 08 и H: 10. Смотрите мой ответ, почему и исправить.
Жиль "ТАК - прекрати быть злым"

-1

Не уверен насчет вашего точного требования. Однако если вы хотите сгенерировать время через 15 минут, то вы можете использовать что-то вроде date -d '+15 min'. Вывод показан ниже:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011

1
Вы неправильно поняли вопрос. Дело в том, чтобы округлить дату (вниз) с кратностью 15 минут.
Жиль "ТАК - прекрати быть злым"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.