it-swarm.com.de

Skript oder Funktion, um die Anzahl der Tage bis zu einem bestimmten Datum zurückzugeben

Ich möchte ein Skript oder eine Funktion schreiben, um mir mitzuteilen, wie viele Tage von jetzt bis zu einem bestimmten Datum in der Zukunft vergangen sind. Was ich kämpfe, um herauszufinden, ist, wie ich das gegebene Datum verarbeite und es mit dem aktuellen Datum vergleiche ... Ich stelle mir so etwas vor

read -p "enter the date in the format YYYY-MM-DD "

Und dann gehe ich davon aus, dass ich einen String habe, der für die Shell bedeutungslos ist, und ich muss einige Auswertungen durchführen wie ... ?? (Dies ist nur ein Beispiel; ich denke, bc wäre erforderlich)

i=$(($(date +%Y)-${REPLY%%-*}))
j=$(($(date +%m)-${REPLY:5:2}))
k=$(($(date +%d)-${REPLY##*-}))

Und dann weiß ich nicht, was ich mit diesen Zahlen anfangen soll ... ??

if $i > 1 then assign l=$((i*365)) and else what?? # what about leap years?
Using $j somehow assign m   # confused before I've started
Using $k somehow assign n   # just as bad
echo $((l+m+n))   

Ich mache es mir sicher zu schwer; wahrscheinlich gibt es ein Textverarbeitungswerkzeug, das Daten versteht und sie vergleichen kann.

Wie kann ich das machen?

28
Zanna

Epochenzeit

Im Allgemeinen sind Zeitberechnungen am einfachsten, wenn wir die Zeit zuerst in (Unix) Epochen Zeit (Sekunden von 1-1-1970) konvertieren. In Python haben wir Werkzeuge, um die Zeit in die Epochenzeit und zurück in ein beliebiges Datumsformat zu konvertieren.

Wir können einfach ein Format einstellen, wie:

pattern = "%Y-%m-%d"

... und heute definieren:

today = "2016-12-07"

und schreiben Sie anschließend eine Funktion, um die Arbeit zu erledigen:

def convert_toepoch(pattern, stamp):
    return int(time.mktime(time.strptime(stamp, pattern)))

Dann ist die Ausgabe von:

nowepoch = convert_toepoch(pattern, today)
print(nowepoch)

> 1481065200

... das ist, wie erwähnt, die Anzahl der Sekunden seit dem 1.1.1970

Berechnung der Tage zwischen zwei Daten

Wenn wir dies heute und zu einem späteren Zeitpunkt tun, berechnen Sie anschließend die Differenz:

#!/usr/bin/env python3
import time

# set our date pattern
pattern = "%Y-%m-%d" 

def convert_toepoch(pattern, stamp):
    return int(time.mktime(time.strptime(stamp, pattern)))

# automatically get today's date 
today = time.strftime(pattern); future = "2016-12-28"

nowepoch = convert_toepoch(pattern, today)
future_Epoch = convert_toepoch(pattern, future)

print(int((future_Epoch - nowepoch)/86400))

Die Ausgabe wird bis zum Datum berechnet, da wir das Format %Y-%m-%d verwenden. Eine Rundung auf Sekunden würde möglicherweise eine falsche Datumsverschiebung ergeben, wenn wir uns beispielsweise 24 Stunden nähern.

Terminal-Version

#!/usr/bin/env python3
import time

# set our date pattern
pattern = "%Y-%m-%d" 

def convert_toepoch(pattern, stamp):
    return int(time.mktime(time.strptime(stamp, pattern)))

# automatically get today's date 
today = time.strftime(pattern)
# set future date
future = input("Please enter the future date (yyyy-mm-dd): ")
nowepoch = convert_toepoch(pattern, today)
future_Epoch = convert_toepoch(pattern, future)
print(int((future_Epoch - nowepoch)/86400))

enter image description here

... und die Zenity-Option

#!/usr/bin/env python3
import time
import subprocess

# set our date pattern
pattern = "%Y-%m-%d" 

def convert_toepoch(pattern, stamp):
    return int(time.mktime(time.strptime(stamp, pattern)))

# automatically get today's date 
today = time.strftime(pattern)
# set future date
try:
    future = subprocess.check_output(
        ["zenity", "--entry", "--text=Enter a date (yyyy-mm-dd)"]
        ).decode("utf-8").strip()
except subprocess.CalledProcessError:
    pass
else:     
    nowepoch = convert_toepoch(pattern, today)
    future_Epoch = convert_toepoch(pattern, future)
    subprocess.call(
        ["zenity", "--info",
         "--text="+str(int((future_Epoch - nowepoch)/86400))
         ])

enter image description here

enter image description here

Und nur zum Spaß ...

Eine winzige Anwendung. Fügen Sie es zu einer Verknüpfung hinzu, wenn Sie es häufig verwenden.

enter image description here

Das Drehbuch:

#!/usr/bin/env python3
import time
import subprocess
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Pango, Gdk

class OrangDays(Gtk.Window):

    def __init__(self):

        self.pattern = "%Y-%m-%d" 
        self.currdate = time.strftime(self.pattern)
        big_font = "Ubuntu bold 45"
        self.firstchar = True

        Gtk.Window.__init__(self, title="OrangeDays")
        maingrid = Gtk.Grid()
        maingrid.set_border_width(10)
        self.add(maingrid)

        datelabel = Gtk.Label("Enter date")
        maingrid.attach(datelabel, 0, 0, 1, 1)

        self.datentry = Gtk.Entry()
        self.datentry.set_max_width_chars(12)
        self.datentry.set_width_chars(12)
        self.datentry.set_placeholder_text("yyyy-mm-dd")
        maingrid.attach(self.datentry, 2, 0, 1, 1)

        sep1 = Gtk.Grid()
        sep1.set_border_width(10)
        maingrid.attach(sep1, 0, 1, 3, 1)

        buttongrid = Gtk.Grid()
        buttongrid.set_column_homogeneous(True)
        maingrid.attach(buttongrid, 0, 2, 3, 1)

        fakebutton = Gtk.Grid()
        buttongrid.attach(fakebutton, 0, 0, 1, 1)

        calcbutton = Gtk.Button("Calculate")
        calcbutton.connect("clicked", self.showtime)
        calcbutton.set_size_request(80,10)
        buttongrid.attach(calcbutton, 1, 0, 1, 1)

        fakebutton2 = Gtk.Grid()
        buttongrid.attach(fakebutton2, 2, 0, 1, 1)

        sep2 = Gtk.Grid()
        sep2.set_border_width(5)
        buttongrid.attach(sep2, 0, 1, 1, 1)

        self.span = Gtk.Label("0")
        self.span.modify_font(Pango.FontDescription(big_font))
        self.span.set_alignment(xalign=0.5, yalign=0.5)
        self.span.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("#FF7F2A"))
        maingrid.attach(self.span, 0, 4, 100, 1)

        sep3 = Gtk.Grid()
        sep3.set_border_width(5)
        maingrid.attach(sep3, 0, 5, 1, 1)

        buttonbox = Gtk.Box()
        maingrid.attach(buttonbox, 0, 6, 3, 1)
        quitbutton = Gtk.Button("Quit")
        quitbutton.connect("clicked", Gtk.main_quit)
        quitbutton.set_size_request(80,10)
        buttonbox.pack_end(quitbutton, False, False, 0)

    def convert_toepoch(self, pattern, stamp):
        return int(time.mktime(time.strptime(stamp, self.pattern)))

    def showtime(self, button):
        otherday = self.datentry.get_text()
        try:
            nextepoch = self.convert_toepoch(self.pattern, otherday)
        except ValueError:
            self.span.set_text("?")
        else:
            todayepoch = self.convert_toepoch(self.pattern, self.currdate)
            days = str(int(round((nextepoch-todayepoch)/86400)))
            self.span.set_text(days)


def run_gui():
    window = OrangDays()
    window.connect("delete-event", Gtk.main_quit)
    window.set_resizable(True)
    window.show_all()
    Gtk.main()

run_gui()
  • Kopiere es in eine leere Datei, speichere es als orangedays.py
  • Starte es:

    python3 /path/to/orangedays.py
    

Zum einpacken

Verwenden Sie für das winzige Anwendungsskript die folgende .desktop -Datei:

[Desktop Entry]
Exec=/path/to/orangedays.py
Type=Application
Name=Orange Days
Icon=org.gnome.Calendar

enter image description here

  • Kopieren Sie den Code in eine leere Datei und speichern Sie ihn als orangedays.desktop in ~/.local/share/applications
  • In der Schlange

    Exec=/path/to/orangedays.py
    

    setze den tatsächlichen Pfad zum Skript ...

29
Jacob Vlijm

Das GNU date -Dienstprogramm kann so etwas ziemlich gut. Es ist in der Lage, eine Vielzahl von Datumsformaten zu analysieren und dann in einem anderen Format auszugeben. Hier verwenden wir %s, um die Anzahl der Sekunden seit der Epoche auszugeben. Es ist dann eine einfache Sache der Arithmetik, $now vom $future zu subtrahieren und durch 86400 Sekunden/Tag zu dividieren:

#!/bin/bash

read -p "enter the date in the format YYYY-MM-DD "

future=$(date -d "$REPLY" "+%s")
now=$(date "+%s")
echo "$(( ( $future / 86400 ) - ( $now / 86400 ) )) days"
23
Digital Trauma

Sie können versuchen, mit der Funktion awk etwas in mktime zu tun

awk '{print (mktime($0) - systime())/86400}'

Das awk erwartet, dass es das Datum von der Standardeingabe im Format "JJJJ MM TT HH MM SS" liest und dann die Differenz zwischen der angegebenen und der aktuellen Zeit in Tagen ausgibt.

mktime konvertiert einfach eine Zeit (im angegebenen Format) in die Anzahl der Sekunden von einer Referenzzeit (1970-01-01 00:00:00 UTC); systime simple gibt die aktuelle Uhrzeit im selben Format an. Subtrahieren Sie eine von der anderen und Sie erhalten in Sekunden, wie weit sie voneinander entfernt sind. Teilen Sie durch 86400 (24 * 60 * 60), um in Tage umzurechnen.

10
Nick Sillito

Hier ist eine Ruby Version

require 'date'

puts "Enter a future date in format YYYY-MM-DD"
answer = gets.chomp

difference = (Date.parse(answer) - Date.today).numerator

puts difference > 1 ? "That day will come after #{difference} days" :
  (difference < 0) ? "That day passed #{difference.abs} days ago" :
 "Hey! That is today!"

Beispiellauf:

Unten finden Sie ein Beispiel für die Ausführung des Skripts Ruby ./day-difference.rb (vorausgesetzt, Sie haben es als day-difference.rb gespeichert).

Mit einem zukünftigen Datum

$ Ruby day-difference.rb
Enter a future date in format YYYY-MM-DD
2021-12-30
That day will come after 1848 days

Mit einem verstrichenen Datum

$ Ruby day-difference.rb
Enter a future date in format YYYY-MM-DD
2007-11-12
That day passed 3314 days ago

Wann ist das heutige Datum vergangen?

$ Ruby day-difference.rb
Enter a future date in format YYYY-MM-DD
2016-12-8
Hey! That is today!

Hier ist eine nette Website, um die Unterschiede des Datums zu überprüfen http://www.timeanddate.com/date/duration.html

10
Anwar

Es gibt ein dateutils -Paket, das für den Umgang mit Daten sehr praktisch ist. Lesen Sie hier mehr darüber github: dateutils

Installieren Sie es durch

Sudo apt install dateutils

Für Ihr Problem einfach,

dateutils.ddiff <start date> <end date> -f "%d days"

wobei die Ausgabe als Sekunden, Minuten, Stunden, Tage, Wochen, Monate oder Jahre gewählt werden kann. Es kann bequem in Skripten verwendet werden, in denen die Ausgabe für andere Aufgaben verwendet werden kann.


Zum Beispiel

dateutils.ddiff 2016-12-26  2017-05-12 -f "%m month and %d days"
4 month and 16 days

dateutils.ddiff 2016-12-26  2017-05-12 -f "%d days"
137 days
6
ankit7540

Sie können die awk Velours-Bibliothek verwenden:

$ velour -n 'print t_secday(t_utc(2018, 7, 1) - t_now())'
7.16478

Oder:

$ velour -n 'print t_secday(t_utc(ARGV[1], ARGV[2], ARGV[3]) - t_now())' 2018 7 1
7.16477
2
Steven Penny

Eine kurze Lösung, wenn beide Daten zum selben Jahr gehören, ist:

echo $((1$(date -d 2019-04-14 +%j) - 1$(date +%j)))

verwenden des "% j" -Formats, das die Position des Datums in Tagen im Jahr zurückgibt, d. h. 135 für das aktuelle Datum. Es vermeidet Rundungsprobleme und behandelt Datumsangaben in der Vergangenheit, was zu negativen Ergebnissen führt.

Das Überschreiten der Jahresgrenzen wird jedoch scheitern. Sie können 365 manuell für jedes Jahr oder 366 für jedes Schaltjahr addieren (oder subtrahieren), wenn der letzte Februar überschritten ist. Dies ist jedoch fast so ausführlich wie bei anderen Lösungen.

Hier die reine Bash-Lösung:

#!/bin/bash
#
# Input sanitizing and asking for user input, if no date was given, is left as an exercise
# Suitable only for dates from 1.1.1970 to 31.12.9999
#
# Get date as parameter (in format yyyy-MM-dd
#
date2=$1
# for testing, more convenient:
# date2=2019-04-14
#
year2=${date2:0:4}
year1=$(date +%Y)
#
# difference in days, ignoring years:
# since %j may lead to values like 080..099, 
# which get interpreted as invalid octal numbers, 
# I prefix them with "1" each (leads to 1080..1099) 
daydiff=$((1$(date -d 1$date2 +%j)- $(date +%j)))
#
yeardiff=$((year2-year1))
# echo yeardiff $yeardiff
#
#
# summarize days per year, except for the last year:
#
daysPerYearFromTo () {
    year1=$1
    year2=$2
    days=0
    for y in $(seq $year1 $((year2-1)))
    do
        ((days+=$(date -d $y-12-31 +"%j")))
    done
    echo $days
}
# summarize days per year in the past, except for the last year:
#
daysPerYearReverse () {
    year1=$1
    year2=$2
    days=0
    for y in $(seq $((year1-1)) -1 $year2)
    do
        ((days+=$(date -d $y-12-31 +"%j")))
    done
    echo $days
}

case $yeardiff in
    0) echo $daydiff
        ;;
    # date in one of previous years:
    -[0-9]*) echo $((daydiff-$(daysPerYearReverse $year1 $year2)))
        ;;
    # date in one of future years:
    [0-9]*) echo $((daydiff+$(daysPerYearFromTo $year1 $year2)))
        ;;
esac

Shellcheck schlägt viele doppelte Anführungszeichen vor, aber für Tage, die das Jahr 9999 überschreiten, sollten Sie einen anderen Ansatz in Betracht ziehen. In der Vergangenheit wird es für Daten vor dem 1970.01.01 im Hintergrund fehlschlagen. Das Desinfizieren von Benutzereingaben wird dem Benutzer als Übung überlassen.

Die beiden Funktionen können in eine überarbeitet werden, was das Verständnis jedoch erschwert.

Bitte beachten Sie, dass das Skript umfangreiche Tests benötigt, um Schaltjahre in der Vergangenheit korrekt zu handhaben. Ich würde nicht wetten, dass es richtig ist.

0
user unknown