Сценарий или функция для возврата, сколько дней с этого времени до данной даты

Я хотел бы записать сценарий или функцию, чтобы сказать мне сколько дней с этого времени до данной даты в будущем. То, что я изо всех сил пытаюсь разработать, - то, как обработать данную дату и сравнить ее с текущей датой... Я воображаю что-то как

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

И затем я предполагаю, что у меня есть строка, это бессмысленно к оболочке, и я должен сделать некоторые оценки как...?? (Это - просто пример; я предполагаю bc был бы необходим),

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

И затем я не знаю, что сделать с теми числами...??

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))   

Я, конечно, делаю его слишком трудно для меня; вероятно, существует инструмент обработки текста, который понимает даты и может сравнить их.

Как я могу сделать это?

28
задан 7 December 2016 в 15:00

7 ответов

Время эпохи

В целом вычисления вовремя являются самыми легкими, если мы сначала преобразовываем время в (Unix) время эпохи (секунды с 01.01.1970). В Python у нас есть инструменты для преобразования времени во время эпохи, и назад в любой формат даты мы предпочитаем.

Мы можем просто установить формат, как:

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

... и определите сегодня:

today = "2016-12-07"

и впоследствии запишите функцию, чтобы сделать задание:

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

Затем вывод:

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

> 1481065200

... который является, как упомянуто, числом секунд с 01.01.1970

Вычисление дней между двумя датами

Если мы делаем это и на сегодня и на наша будущая дата, впоследствии вычисляем различие:

#!/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))

Вывод будет вычислен по дате, так как мы используем формат %Y-%m-%d. Округление на секундах возможно дало бы неправильное различие в дате, если мы близки 24 часа, например.

Версия программы

#!/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

... И опция Zenity

#!/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

И только для забавы...

Крошечное приложение. Добавьте его к ярлыку при использовании его часто.

enter image description here

Сценарий:

#!/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()
  • Скопируйте его в пустой файл, сохраните его как orangedays.py
  • Выполнение это:

    python3 /path/to/orangedays.py
    

Обернуть его

Используйте для крошечного сценария приложений выше следующего .desktop файл:

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

enter image description here

  • Скопируйте код в пустой файл, сохраните его как orangedays.desktop в ~/.local/share/applications
  • В строке

    Exec=/path/to/orangedays.py
    

    установите фактический путь к сценарию...

29
ответ дан 23 November 2019 в 00:54

утилита GNU date довольно хороша в этом виде вещи. Это может проанализировать хорошее множество форматов даты и затем вывода в другом формате. Здесь мы используем %s для вывода числа секунд с эпохи. Это - затем простой вопрос арифметики, чтобы вычесть $now из $future и разделиться на 86 400 секунд/день:

#!/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
ответ дан 23 November 2019 в 00:54

Вот Выполнение версии

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!"

Ruby В качестве примера:

шанс В качестве примера сценария ruby ./day-difference.rb дан ниже (предположение, что Вы сохранили его как day-difference.rb)

С будущей датой

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

С переданной датой

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

, Когда передано, сегодняшняя дата

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

Вот является хорошим веб-сайтом для проверки различий даты http://www.timeanddate.com/date/duration.html

10
ответ дан 23 November 2019 в 00:54

Существует dateutils пакет, который очень удобен для контакта с датами. Читайте больше об этом здесь Установка github:dateutils

это

sudo apt install dateutils

Для Вашей проблемы, просто,

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

, где вывод может быть выбран в качестве секунд, minues, часов, дней, недель, месяцев или лет. Это может удобно использоваться в сценариях, где вывод может использоваться для других задач.

<час>

, Например,

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
ответ дан 23 November 2019 в 00:54

Короткое решение, если обе даты принадлежат тому же году:

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

использование "%j" - формат, который возвращает положение даты в течение многих дней в году, т.е. 135 для текущей даты. Это старается не округлять проблемы и обрабатывает даты, в прошлом дающие отрицательные результаты.

Однако пересекающие границы года, это перестанет работать. Вы могли добавить (или вычесть), 365 вручную в течение каждого года или 366 в течение каждого високосного года, если последний из февраля пересечен, но это будет почти столь же подробным как другие решения.

Здесь чистое решение для удара:

#!/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 предлагает большое двойное заключение в кавычки, но в течение многих дней, превышая 9999 год необходимо рассмотреть другой подход. Для прошлого это перестанет работать тихо для дат до 01.01.1970. Очистку ввода данных пользователем оставляют как осуществление пользователю.

две функции могут быть пересмотрены в одну, но это могло бы мешать понимать.

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

0
ответ дан 23 November 2019 в 00:54

Вы могли попытаться выполнить в чем-то awk, использование mktime функция

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

awk ожидает читать дату из стандартного входа в формате "YYYY MM DD HH MM SS" и затем печатает различие между указанным временем и текущим временем в днях.

mktime просто преобразовывает время (в указанном формате) к числу секунд со ссылочного времени (01.01.1970 0:00:00 UTC); простой systime указывает текущее время в том же формате. Вычтите один из другой, и Вы добираетесь, как далеко независимо они находятся в секундах. Разделитесь на 86 400 (24 * 60 * 60) для преобразования в дни.

10
ответ дан 23 November 2019 в 00:54

Можно пользоваться awk библиотекой Velour:

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

Или:

$ velour -n 'print t_secday(t_utc(ARGV[1], ARGV[2], ARGV[3]) - t_now())' 2018 7 1
7.16477
2
ответ дан 23 November 2019 в 00:54

Другие вопросы по тегам:

Похожие вопросы: