Інструмент в UNIX для віднімання дат


22

Чи є в Solaris UNIX якийсь інструмент (тому інструмент GNU не доступний) для віднімання дат? Я знаю, що в Linux ми gawkможемо відняти одну дату від іншої. Але в Solaris максимум, який ми маємо, - це nawk(покращений awk), який не може виконувати обчислення дати. Також я не можу використовувати perl.

Чи є спосіб зробити такі розрахунки дати 20100909 - 20001010?

ОНОВЛЕННЯ: Чи bcможна виконати розрахунки дат?


Відповіді:


10

Ось сценарій awk, який я щойно написав, повинен працювати з POSIX awk. Вам доведеться спробувати версію 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);
}
{}

Пропустіть рядок дати YYYYmmdd, і він буде перетворений на кількість секунд після епохи (з невеликою кількістю подання за те, що знаходиться на денних межах). Тоді ви зможете відняти два.

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

Я перевірив вашу логіку з Oracle. Для деяких дат це нормально, однак для нього створюється число з плаваючою точкою. Боюся, що мені доведеться скоротити ціле число, чи не так?
jyz

Десяткова частина є часткою секунди і не обов'язково потрібна.
Арседж

Епоха закінчується 20380119. Чому б не використати юліанський день року? Dupe ... unix.stackexchange.com/questions/302266/…
jas-

13

На жаль, жодна з утиліт командного рядка POSIX не забезпечує арифметику за датами. date -dі date +%sце шлях, якщо у вас є, але вони є розширеннями GNU.

Існує незграбний злом з touchподібними роботами для перевірки того, що побачення минуло хоча б п днів:

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

(Зверніть увагу, що цей код може бути відключений одним, якщо DST запустився або зупинився в інтервалі, а сценарій працює до 1 години ночі.)

Кілька людей закінчили впроваджувати бібліотеки маніпуляції з датами в Bourne або POSIX. Є кілька прикладів та посилань у поширених питаннях 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"

Як зробити конверсію, ймовірно, буде інакше, якщо у вас немає баш. Найбільш портативним способом може бути користування expr(сторінка expr's posix man ).


так, це не відповідає на моє запитання, тому що це Solaris ... але дякую за ідею та публікацію :)
jyz

8

Для запису, datautils - це моя спроба забезпечити набір портативних інструментів, що охоплюють арифметику дати. Ваш приклад зводиться до

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

-iВизначає формат вхідного сигналу.


2
Цей пакет є приголомшливим, і він існує у бібліотеках всесвіту Ubuntu (принаймні для Trusty). В іншій системі я міг би це легко скласти з нуля. Настійно рекомендується. Велике спасибі!
Роберт Мюїл

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


3

Дата WN GNU на Solaris:

Я кажу це ще раз:

Занадто багато Solaris SysAdmins пишаються тим, що навмисно не встановлюють офіційні пакети від Sun (зараз Oracle), які роблять систему Solaris "сумісною з GNU", коли вони налаштовують новий хост. Мене б'є чому.

Дата GNU відмінна і повинна бути доступна за замовчуванням на будь-якому хості Solaris, IMHO.

На Solaris 10

Встановіть пакет SFWcoreu з компакт-диска Solaris. Після встановлення ви знайдете дату GNU в/opt/sfw/bin/date

На Солярісі 11

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

Зробіть це, якщо його не встановлено:

встановити pkg // 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". Гаук має арифметику дати.


Я цього не зробив. Хтось редагував мій пост і
позначав

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.