问题描述
我想编写一个脚本或函数来告诉我从现在到未来的给定日期有多少天。我正在努力解决的是如何处理给定日期并将其与当前日期进行比较…我在想像
read -p "enter the date in the format YYYY-MM-DD "
然后我假设我有一个对 shell 无意义的字符串,我必须进行一些评估,例如… ?? (这只是一个例子;我想可能需要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))
我肯定对自己来说太难了;可能有一个文本处理工具可以理解日期并可以进行比较。
我怎样才能做到这一点?
最佳方案
时代时间
通常,如果我们首先将时间转换为(Unix)纪元时间(1970年1月1日至秒),则按时间进行的计算最简单。在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
…如上所述,这是自1970年1月1日以来的秒数
计算两个日期之间的天数
如果我们在今天和将来的日期都这样做,请随后计算差异:
#!/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))
…还有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))
])
只是为了好玩…
一个很小的应用程序。如果经常使用,请将其添加到快捷方式。
剧本:
#!/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
-
将代码复制到一个空文件中,将其另存为
~/.local/share/applications
中的orangedays.desktop
-
在行中
Exec=/path/to/orangedays.py
设置脚本的实际路径…
次佳方案
GNU date
实用程序在这种事情上非常出色。它能够解析各种日期格式,然后以另一种格式输出。在这里,我们使用%s
输出自纪元以来的秒数。然后,从$future
中减去$now
并除以86400秒/天,这是一个简单的算法问题:
#!/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"
第三种方案
您可以尝试使用mktime
函数在awk
中做一些事情
awk '{print (mktime($0) - systime())/86400}'
awk希望从标准输入中以“ YYYY MM DD HH MM SS”格式读取日期,然后以天为单位打印指定时间与当前时间之间的时差。
mktime
只是将时间(以指定格式)转换为参考时间(1970年1月1日00:00:00 UTC)的秒数; systime simple以相同格式指定当前时间。彼此相减,您可以在几秒钟之内得到它们之间的距离。除以86400(24 * 60 * 60)即可转换为天数。
第四种方案
这是Ruby版本
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 ./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的差异
第五种方案
有一个dateutils
软件包,它非常便于处理日期。在这里阅读更多关于它的信息github:dateutils
安装方式
sudo apt install dateutils
对于您的问题,简单地说,
dateutils.ddiff <start date> <end date> -f "%d days"
输出可以选择为秒,分钟,小时,天,周,月或年。它可以方便地用于输出可以用于其他任务的脚本中。
例如,
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