지금부터 앞으로 주어진 날짜까지 며칠을 알려주는 스크립트 나 함수를 작성하고 싶습니다. 내가 해결하기 위해 고군분투하는 것은 주어진 날짜를 처리하고 현재 날짜와 비교하는 방법입니다 … 나는 뭔가를 상상하고 있습니다.
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))
나는 그것을 너무 힘들게 만들고있다. 아마도 날짜를 이해하고 비교할 수있는 텍스트 처리 도구가있을 것입니다.
어떻게해야합니까?
답변
에포크 시간
일반적으로 시간을 (Unix) 에포크 시간 (1-1-1970에서 초 )으로 변환하면 시간 계산이 가장 쉽습니다 . 파이썬에는 시간을 에포크 시간으로 변환하고 원하는 날짜 형식으로 되돌릴 수있는 도구가 있습니다.
다음과 같은 형식을 간단히 설정할 수 있습니다.
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
… 이것은 1-1-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))
… 그리고 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
스크립트의 실제 경로를 설정하십시오 …
답변
GNU의 date
유틸리티는 이런 종류의 꽤 좋다. 다양한 날짜 형식을 구문 분석 한 다음 다른 형식으로 출력 할 수 있습니다. 여기서 우리 %s
는 에포크 이후 초 수를 출력하는 데 사용 합니다. 그런 다음 뺄 연산의 간단한 문제입니다 $now
으로부터 $future
8만6천4백초 / 일에 의해 분할 :
#!/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"
답변
함수를 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)으로 나누어 일로 변환합니다.
답변
여기에 루비 버전이 있습니다
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
답변
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
답변
두 날짜가 같은 해에 속하면 간단한 해결책은 다음과 같습니다.
echo $((1$(date -d 2019-04-14 +%j) - 1$(date +%j)))
“% j”형식을 사용하여 연도를 기준으로 날짜 위치를 반환합니다 (예 : 현재 날짜의 경우 135). 반올림 문제를 피하고 과거의 날짜를 처리하여 부정적인 결과를 낳습니다.
그러나 연도 경계를 넘어 서면 실패합니다. 2 월 마지막이 지난 경우 매년 수동으로 365를 추가하거나 빼기 연도별로 366을 추가 (또는 빼기) 할 수 있지만 다른 솔루션과 거의 비슷합니다.
순수한 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 이전의 날짜에 대해서는 자동으로 실패합니다. 사용자 입력 삭제는 사용자에게 연습으로 남습니다.
두 기능을 하나로 리팩토링 할 수 있지만 이해하기 어려울 수 있습니다.
스크립트는 과거의 윤년을 올바르게 처리하기 위해 철저한 테스트가 필요합니다. 나는 그것이 옳다는 것을 내기하지 않을 것입니다.