Инструмент в UNIX для вычитания дат


22

Есть ли в Solaris UNIX какой-либо инструмент (поэтому нет инструмента GNU) для вычитания дат? Я знаю, что в Linux у нас есть gawkчто может вычесть одну дату из другой. Но в солярисе максимум у нас есть nawk(улучшенныйawk ), который не может выполнять вычисления даты. Также я не могу использовать Perl.

Есть ли способ сделать вычисление даты, как 20100909 - 20001010?

ОБНОВЛЕНИЕ: bcУмеет ли выполнять расчеты дат?


Ответы:


10

Вот сценарий awk, который я только что написал, должен работать с awk для POSIX. Вам придется попробовать версию Solaris; помните, что на Solaris также есть две версии Awk, одна в / bin и одна в / usr / xpg4 / bin / awk (я думаю, это nawk).

BEGIN {
    daysofmonth["01"] = 0; daysofmonth["02"] = 31; daysofmonth["03"] = 59;
    daysofmonth["04"] = 90; daysofmonth["05"] = 120; daysofmonth["06"] = 151;
    daysofmonth["07"] = 181; daysofmonth["08"] = 212; daysofmonth["09"] = 243;
    daysofmonth["10"] = 273; daysofmonth["11"] = 304; daysofmonth["12"] = 334;
    fullday = 86400;
}
/[12][09][0-9][0-9][01][0-9][0123][0-9]/ {
    year = substr($0, 1, 4); month = substr($0, 5, 2); day = substr($0, 7, 2);
    date = ((year - 1970) * 365.25) + daysofmonth[month] + day - 1;
    if ((year % 4) == 0 && month > 2) { date = date + 1; }
    print date * fullday - (25200);
}
{}

Передайте строку даты в формате ГГГГммдд, и она будет преобразована в количество секунд с начала эпохи (с небольшим количеством отданных за то, чтобы быть на границах дня). Тогда вы сможете вычесть два.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`

Я проверил вашу логику с Oracle. Для некоторых дат это нормально, однако для него генерируется число с плавающей точкой. Боюсь, мне нужно усечь целое число, не так ли?
Jyz

Десятичная дробь - это доля секунды, которая не обязательно нужна.
Arcege

Эпоха истекает 20380119. Почему бы не использовать юлианский день года? Дупе
jas- 18.02-18

13

К сожалению, ни одна из утилит командной строки POSIX не обеспечивает арифметику дат. date -dа такжеdate +%s есть способ, если у вас есть, но они являются расширениями GNU.

Существует такая неуклюжая попытка touchпроверить, что дата не менее n дней в прошлом:

touch -t 201009090000 stamp
if [ -n "$(find stamp -mtime +42)" ]; then ...

(Обратите внимание, что этот код может быть отключен на единицу, если DST запущен или остановлен в интервале, и сценарий выполняется до 1:00.)

Несколько человек в итоге реализовали библиотеки манипулирования датами в Bourne или POSIX. В FAQ по comp.unix.shell есть несколько примеров и ссылок .

Установка инструментов GNU может быть способом наименьшей боли.


11

Я бы попробовал использовать dateкоманду, которая является частью POSIX, так что она почти везде. ОБНОВЛЕНИЕ: К сожалению, кажется, что -d не является частью даты POSIX и, вероятно, не в Solaris. Таким образом, это, вероятно, не ответит на вопрос ОП.

d1=`date -d 20100909 +%s`
d2=`date -d 20001010 +%s`

Теперь d1и d2являются целыми числами, которые соответствуют секундам с эпохи Unix. Таким образом, чтобы получить разницу между ними, мы вычитаем ( $((d1-d2))в bash) и скрываем все, что хотим. Дни самые простые:

echo "$(((d1-d2)/86400)) days"

Как сделать преобразование, скорее всего, будет другим, если у вас нет bash. Наиболее переносимым способом может быть использование expr( страница руководства expix posix ).


да, это не отвечает на мой вопрос, потому что это Солярис ... но спасибо за идею и размещение :)
jyz

8

Для справки , dateutils - моя попытка предоставить набор портативных инструментов, которые охватывают арифметику дат. Ваш пример сводится к

ddiff -i '%Y%m%d' 20001010 20100909
=>
  3621

-iОпределяет формат входного сигнала.


2
Этот пакет великолепен и существует в библиотеках юниверса Ubuntu (по крайней мере, для Trusty). В другой системе я мог бы легко скомпилировать его. Настоятельно рекомендуется. Большое спасибо!
Роберт Мюил

Также упаковано в Fedora и EPEL для экосистемы RH.
17

4

Вероятно, Perl будет установлен, и достаточно просто получить модули из CPAN , установить их в свой домашний каталог и сослаться на них в своей программе. В этом случае в модуле Date :: Calc есть Delta_Daysподпрограмма, которая поможет.


3

Дата выпуска GNU на Solaris:

Я говорю это снова:

Слишком много Solaris SysAdmins гордятся тем, что намеренно не устанавливают официальные пакеты от Sun (теперь Oracle), которые делают систему Solaris «GNU-совместимой» при настройке нового хоста. Бьет меня почему.

Дата GNU превосходна и должна быть доступна по умолчанию на любом хосте Solaris, IMHO.

На Солярисе 10

Установите пакет SFWcoreu с компакт-диска Solaris Companion. После установки вы найдете дату GNU в/opt/sfw/bin/date

На Солярисе 11

Возможно, он уже есть, так как я считаю, что он является частью стандартной установки. Однако он вызывается gdateдля того, чтобы отличить его от версии даты Солнца.

Сделайте это, если не установлено:

pkg install // solaris / file / gnu-coreutils

Спасибо за совет. Можете ли вы дать мне пример, как его использовать? Поэтому я могу попросить sysadmin установить его ...
jyz

В Solaris 11, он будет установлен , как и /usr/bin/gdateи /usr/gnu/bin/dateпоэтому вы можете использовать его либо по имени , либо $ настройки PATH.
alanc

2

Если у вас есть Python:

from time import *
date1 = strptime("20100909","%Y%m%d")
date2 = strptime("20001010","%Y%m%d")
diff = mktime(date1) - mktime(date2)
print repr(d/86400) + " days"

Вы отметили свой вопрос "gawk", но вы говорите "нет инструментов GNU". У Гоука есть своя арифметика.


Я не Кто-то отредактировал мой пост и отметил "gawk" ...
jyz

2

питон:

 from datetime import datetime as dt
 a = dt(2010, 9, 9)
 b = dt(2000, 10, 10)
 print (a - b).days

1

1. Определите дату1 и %jдату2 в формате дня года (001..366)

user@linux:~$ date1=`date -d 20100909 +%j` 
user@linux:~$ date2=`date -d 20001010 +%j`

2. Рассчитайте разницу с expr

user@linux:~$ datediff=`expr $date2 - $date1`

3. Итак, ответ 32 дня

user@linux:~$ echo $datediff days
32 days
user@linux:~$ 

... или однострочное решение

user@linux:~$ echo $(( $(date -d 20001010 +%j) - $(date -d 20100909 +%j) )) days
32 days
user@linux:~$ 

или

user@linux:~$ expr $(date -d 20001010 +%j) - $(date -d 20100909 +%j)
32
user@linux:~$

или

user@linux:~$ expr `date -d 20001010 +%j` - `date -d 20100909 +%j`
32
user@linux:~$ 

0

С датой BSD для macOS:

echo "Quelle est la date de début ?"
read DATE_DE_DEBUT
echo "Quelle est la date de fin ?"
read DATE_DE_FIN
ANNEE=$(($(echo $DATE_DE_FIN | awk -F "/" '{print $3}')-$(echo $DATE_DE_DEBUT  | awk -F "/" '{print $3}')))

echo " "

if [[ $ANNEE > 0 ]]; then

for((annee=$ANNEE-1 ; $ANNEE ; annee++))

  do
  #echo $annee  
  for((mois=0 ; 13 - $mois ; mois++))
      do
  #   echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
 #             echo année:$annee mois:$mois jour:$jour
           TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
           if [[ $TEST = $DATE_DE_FIN ]]; then
                  echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                  echo "est de :";
                  echo "$annee année(s) $mois mois $jour jour(s)";
             exit 0;
            fi


          done 
  done
  done

 else 
 annee=0
 for((mois=0 ; 13 - $mois ; mois++))
      do
#      echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
              #echo année:$annee mois:$mois jour:$jour
              TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
              if [[ $TEST = $DATE_DE_FIN ]]; then 
                      echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                     echo "est de :";
                     echo "$annee année(s) $mois mois $jour jour(s)";
              exit 0;
              fi
              done
      done

fi

0

Вы можете использовать библиотеку awk Velor, чтобы вернуть разницу в секундах:

$ velour -n 'print t_utc(2010, 9, 9) - t_utc(2000, 10, 10)'
312854400

Или дни:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.