Ответы:
Вы можете получить текущую метку времени 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"
Следующие методы делают ненужным вызывать 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
printf
или, sed
а также то, что «ненужный» cat
vs <файл действительно имеет существенное различие во время выполнения. при зацикливании, как в моем примере «в 500 раз медленнее». Поэтому кажется, что использование оболочки везде, где это возможно, и разрешение программы, например, date
для пакетной обработки, это то, что я имею в виду ... например. Gilles 'Left-Pad-0 пример, против printf
Вот способ работы с датами в оболочке. Сначала вызовите, 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}"
Может быть, это уже не имеет значения, но вы можете попробовать мои собственные dateutils . Округление (вниз) до минут выполняется с dround
отрицательным аргументом:
dround now /-15m
=>
2012-07-11T13:00:00
Или придерживаться вашего формата:
dround now /-15m -f '%Y.%m.%d %H:%M'
=>
2012.07.11 13:00
dateutils.dround '2018-11-12 13:55' -15m
производит . 2018-11-12T13:15:00
2018-11-12T13:45:00
/-15m
т.е. округлите до следующего кратного 15 минутам в час. Эта функция получила более громоздкий синтаксис, потому что она принимает меньше значений, / -13m, например, невозможно, потому что 13 не является делителем 60 (минут в час)
Некоторые оболочки могут выполнять эту работу без вызова внешней 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
может дать аналогичные результаты:
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'
Если вы можете прожить с датой звонка два раза, это работает в bash на Solaris:
date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"
Отредактировано от имени комментария:
date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'
Не уверен насчет вашего точного требования. Однако если вы хотите сгенерировать время через 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