AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 858160
Accepted
Zanna
Zanna
Asked: 2016-12-08 12:09:27 +0800 CST2016-12-08 12:09:27 +0800 CST 2016-12-08 12:09:27 +0800 CST

返回从现在到给定日期的天数的脚本或函数

  • 772

我想写一个脚本或函数来告诉我从现在到未来给定日期有多少天。我正在努力解决的是如何处理给定的日期并将其与当前日期进行比较......我在想像

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

我肯定让自己太难了;可能有一个文本处理工具可以理解日期并可以比较它们。

我怎样才能做到这一点?

command-line
  • 7 7 个回答
  • 5500 Views

7 个回答

  • Voted
  1. Best Answer
    Jacob Vlijm
    2016-12-08T13:29:07+08:002016-12-08T13:29:07+08:00

    纪元时间

    一般来说,如果我们首先将时间转换为(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
    

    在此处输入图像描述

    • 将代码复制到一个空文件中,保存orangedays.desktop为~/.local/share/applications
    • 在行

      Exec=/path/to/orangedays.py
      

      设置脚本的实际路径...

    • 31
  2. Digital Trauma
    2016-12-08T16:39:14+08:002016-12-08T16:39:14+08:00

    GNUdate实用程序非常擅长这类事情。它能够解析多种日期格式,然后以另一种格式输出。这里我们%s用来输出自纪元以来的秒数。$now然后从中减去$future并除以 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"
    
    • 26
  3. Nick Sillito
    2016-12-08T12:51:00+08:002016-12-08T12:51:00+08:00

    您可以尝试在 中做某事awk,使用该mktime功能

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

    awk 期望以“YYYY MM DD HH MM SS”格式从标准输入读取日期,然后打印指定时间与当前时间之间的差异(以天为单位)。

    mktime简单地将时间(以指定格式)转换为距参考时间(1970-01-01 00:00:00 UTC)的秒数;systime simple 以相同的格式指定当前时间。从另一个中减去一个,您可以在几秒钟内得到它们之间的距离。除以 86400 (24 * 60 * 60) 转换为天数。

    • 10
  4. Anwar
    2016-12-09T07:17:20+08:002016-12-09T07:17:20+08:00

    这是一个 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

    • 10
  5. ankit7540
    2016-12-26T23:19:05+08:002016-12-26T23:19:05+08:00

    有一个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
    
    • 6
  6. Zombo
    2016-12-26T22:45:00+08:002016-12-26T22:45:00+08:00

    您可以使用 awk Velor 库:

    $ 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
  7. user unknown
    2019-05-15T15:12:36+08:002019-05-15T15:12:36+08:00

    如果两个日期属于同一年,一个简短的解决方案是:

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

    使用“%j”格式,它返回日期的位置(以年为单位),即当前日期为 135。它避免了舍入问题并处理过去的日期,从而产生负面结果。

    但是,跨越年份边界,这将失败。您可以为每年手动添加(或减去)365 或为每个闰年添加(或减去)366,如果超过 2 月的最后一天,但这几乎与其他解决方案一样冗长。

    这里是纯 bash 解决方案:

    #!/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 年的天数,您应该考虑使用不同的方法。对于过去,它会在 1970.01.01 之前的日期静默失败。清理用户输入作为练习留给用户。

    这两个函数可以重构为一个,但这可能会使它更难理解。

    请注意,该脚本需要进行详尽的测试才能正确处理过去的闰年。我不敢打赌这是对的。

    • 0

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve