0

It's 14.08.2019, there is a text file that contains a list of dates (dd.mm.yyyy):

30.07.2018
14.08.2019
18.08.2019
20.08.2019
01.01.2020

The dates in the list are deadlines.

What the output should look like: a list of dates that are older than the current date and dates that are going to expire in 10 days (if it expires in 1 to 10 days it's listed and if it expires today it's also listed. If it expires in 11 or more days then it's not listed).

New contributor
Hank is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • 1
    The output format does not involve sorting in any form or shape as far as I can see at the moment, and whatever algorithm I can think of would not requirer sorting of the input data either. Why do you need sorting? – Kusalananda Aug 14 at 18:10
  • Since you can sort dates in a file from oldest to newest and vise versa then there should be a way to "filter" things out. I'm actually wondering if that can be done in the command line. – Hank Aug 14 at 20:21
  • Could you give an example of the output? – guillermo chamorro Aug 14 at 20:49
  • 1
    If you can install an additional package, dateutils will make your life easier: fresse.org/dateutils – Wildcard Aug 14 at 21:37
0

Using GNU awk, or mawk:

$ cat file
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020
$ awk -f script.awk file   # running this on 2019-08-14
30.07.2018      expired 380 days ago
13.08.2019      expired 1 days ago
14.08.2019      expires in 0 days
18.08.2019      expires in 4 days
20.08.2019      expires in 6 days
21.08.2019      expires in 7 days
23.08.2019      expires in 9 days
24.08.2019      expires in 10 days

This will output the dates in the same order as the input data, with each date suffixed by a tab and a short message. Dates eleven days in the future or more will not be outputted.

The awk script:

BEGIN {
        FS = "."
        now = systime()/(24*60*60) - 1
}

{
        datespec = sprintf("%s %s %s 00 00 00", $3, $2, $1)
        timestamp = mktime(datespec)/(24*60*60)

        diff = timestamp - now

        if (diff < 0)
                message = sprintf("expired %d days ago", 1 - diff)
        else if (diff < 11)
                message = sprintf("expires in %d days", diff)
        else
                next

        printf("%s\t%s\n", $0, message)
}

mawk and GNU awk has been extended with date/time-related functions, and here we are using systime() to get the current time as a UNIX timestamp (seconds since 1970-01-01 00:00). We round this to full days by dividing by the number of seconds in a day.

For each input line, we use the three dot-delimited numbers with mktime() to create a UNIX timestamp for midnight on the given date (the very start of the day) and round this to full days as with now and call it timestamp.

Then it's a matter of comparing now and timestamp and figuring out what to print depending on how they differ.

See the documentation for GNU awk or mawk for how they document systime() and mktime().


Sorting the dates by computing their corresponding UNIX timestamps, prefixing the dates by this, sorting numerically, and discarding the now used timestamps (using mawk or GNU awk):

$ awk -F . -v OFS="\t" '{ print mktime(sprintf("%d %d %d 00 00 00", $3, $2, $1)), $0 }' file | sort -n | cut -f 2
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020

The same thing, but simpler, and also works with BSD awk:

$ awk -F . -v OFS="\t" '{ print sprintf("%s-%s-%s", $3, $2, $1), $0 }' file | sort | cut -f 2
30.07.2018
13.08.2019
14.08.2019
18.08.2019
20.08.2019
21.08.2019
23.08.2019
24.08.2019
25.08.2019
01.01.2020

This works by simply converting the dates into the YYYY-MM-DD (ISO 8601 Calendar date) format and sorting lexicographically on that rather than the UNIX timestamps.

Using the YYYY-MM-DD date format from the start would have made sorting much simpler, but we would still have to do the same sort of calculations as in the first awk script above to be able to (easily) say "this day is more than 10 days into the future".

0

I have come to this, if I understood you well, and taking the answer of @Kunasalanda as example:

This is using bash (or compatible shell) and GNU date. It would fall over on e.g. macOS (non-GNU date).

today=$(date -d $(date +'%Y-%m-%d') +%s)

while read i; do
  [[ -z "$i" ]] && continue
  date_format=$(echo "$i" | awk -F'.' -vOFS='-' '{print $3,$2,$1}')
  convert_date=$(date -d "$date_format" +%s)
  if [[ "$convert_date" -ge "$today" ]]; then
    expires=$(( ("$convert_date"- "$today")/86400 ))
    [[ ! "$expires" -gt 10 ]] && echo $i expires in $expires days
  fi
done < file

Ouput:

14.08.2019 expires in 0 days
18.08.2019 expires in 4 days
20.08.2019 expires in 6 days

Ignore blank lines

[[ -z "$i" ]] && continue

Format dd.mm.yy to yyyy-mm-dd to be able to perform operations

date_format=$(echo "$i" | awk -F'.' -vOFS='-' '{print $3,$2,$1}')

Convert date to seconds

convert_date=$(date -d "$date_format" +%s)

Choose only dates greater than today

if [[ "$convert_date" -ge "$today" ]]; then

Get the days that the given date will expire

expires=$(( ("$convert_date"- "$today")/86400 ))

Output only if expiration is not greater than 10 days

[[ ! "$expires" -gt 10 ]] && echo "$i" expires in "$expires" days
  • 1
    You should mention that this is using bash (or compatible shell) and GNU date. It would fall over on e.g. macOS (non-GNU date). – Kusalananda Aug 14 at 22:18

Your Answer

Hank is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.