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

22

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

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

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

jyz
источник
1
См. Также Быстрый расчет разницы дат , когда доступна дата GNU.
Жиль "ТАК - перестань быть злым"

Ответы:

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`
Arcege
источник
Я проверил вашу логику с 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Определяет формат входного сигнала.

hroptatyr
источник
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
peterh
источник
Спасибо за совет. Можете ли вы дать мне пример, как его использовать? Поэтому я могу попросить 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:~$ 
Sabrina
источник
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
OlivierOR
источник
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
Стивен Пенни
источник