A = "2002-20-10"
B = "2003-22-11"
Làm thế nào để tìm thấy sự khác biệt về ngày giữa hai ngày?
A = "2002-20-10"
B = "2003-22-11"
Làm thế nào để tìm thấy sự khác biệt về ngày giữa hai ngày?
Câu trả lời:
Nếu bạn có GNU date
, nó cho phép in biểu diễn của một ngày tùy ý ( -d
tùy chọn). Trong trường hợp này, hãy chuyển đổi ngày thành giây kể từ EPOCH, trừ và chia cho 24 * 3600.
Hoặc bạn cần một cách di động?
echo "( `date -d $B +%s` - `date -d $A +%s`) / (24*3600)" | bc -l
Cách bash - chuyển đổi ngày tháng sang định dạng% y% m% d và sau đó bạn có thể thực hiện việc này ngay từ dòng lệnh:
echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
%y%m%d
định dạng ngày tháng . Ví dụ: gnu date sẽ chấp nhận %Y-%m-%d
định dạng OP đã sử dụng. Nói chung, ISO-8601 là một lựa chọn tốt (và định dạng của OP là một trong những định dạng như vậy). Tốt hơn nên tránh các định dạng có năm 2 chữ số.
days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) ))
. lưu ý rằng $days_diff
sẽ là một số nguyên (tức là không có số thập phân)
date
cài đặt. Nó hoạt động cho GNU date
. Nó không hoạt động với POSIX date
. Đây có lẽ không phải là vấn đề đối với hầu hết người đọc, nhưng nó đáng lưu ý.
%Y-%m-%d
, cho đến khi chúng tôi giới thiệu August 2.0
và October 2.0
định dạng của OP là %Y-%d-%m
. Liên quan xkcd: xkcd.com/1179
tl; dr
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s)) / (60*60*24) ))
Coi chừng! Nhiều giải pháp cơ bản ở đây bị hỏng cho các phạm vi ngày kéo dài ngày bắt đầu tiết kiệm ánh sáng ban ngày (nếu có). Điều này là do cấu trúc $ ((math)) thực hiện phép toán 'tầng' / cắt ngắn trên giá trị kết quả, chỉ trả về toàn bộ số. Hãy để tôi minh họa:
DST bắt đầu vào ngày 8 tháng 3 năm nay ở Hoa Kỳ, vì vậy hãy sử dụng phạm vi ngày bao gồm:
start_ts=$(date -d "2015-03-05" '+%s')
end_ts=$(date -d "2015-03-11" '+%s')
Hãy xem những gì chúng ta nhận được với dấu ngoặc kép:
echo $(( ( end_ts - start_ts )/(60*60*24) ))
Trả về '5'.
Thực hiện việc này bằng cách sử dụng 'bc' với độ chính xác cao hơn cho chúng ta một kết quả khác:
echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc
Trả về '5,95' - 0,05 còn thiếu là giờ bị mất từ trình chuyển đổi DST.
Vậy điều này phải được thực hiện như thế nào cho đúng?
Tôi sẽ đề nghị sử dụng cái này thay thế:
printf "%.0f" $(echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc)
Ở đây, 'printf' làm tròn kết quả chính xác hơn được tính bằng 'bc', cho chúng ta phạm vi ngày chính xác là '6'.
Chỉnh sửa: đánh dấu câu trả lời trong nhận xét từ @ hank-schultz bên dưới, mà tôi đã sử dụng gần đây:
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s) )/(60*60*24) ))
Điều này cũng sẽ an toàn cho bước nhảy thứ hai miễn là bạn luôn trừ ngày trước đó cho ngày muộn hơn, vì số giây nhuận sẽ chỉ thêm vào sự khác biệt - việc cắt bớt có hiệu quả làm tròn xuống kết quả chính xác.
echo $(( ($(date --date="2015-03-11 UTC" +%s) - $(date --date="2015-03-05 UTC" +%s) )/(60*60*24) ))
:, trả về 6, thay vì 5.
Và trong trăn
$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
bash
và shell
, vì vậy tôi nghĩ chúng ta có thể giả định rằng chúng ta đang nói về hệ thống * nix. Trong các hệ thống như vậy echo
và date
có mặt đáng tin cậy, nhưng python thì không.
Điều này phù hợp với tôi:
A="2002-10-20"
B="2003-11-22"
echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days
Bản in
398 days
Điều gì đang xảy ra?
date -d
để xử lý các chuỗi thời giandate %s
để chuyển đổi chuỗi thời gian thành giây kể từ năm 1970 (unix epoche)Nếu tùy chọn -d hoạt động trong hệ thống của bạn, đây là một cách khác để thực hiện. Có một cảnh báo rằng nó sẽ không tính đến những năm nhuận vì tôi đã coi 365 ngày mỗi năm.
date1yrs=`date -d "20100209" +%Y`
date1days=`date -d "20100209" +%j`
date2yrs=`date +%Y`
date2days=`date +%j`
diffyr=`expr $date2yrs - $date1yrs`
diffyr2days=`expr $diffyr \* 365`
diffdays=`expr $date2days - $date1days`
echo `expr $diffyr2days + $diffdays`
Đây là phiên bản MAC OS X để bạn tiện theo dõi.
$ A="2002-20-10"; B="2003-22-11";
$ echo $(((`date -jf %Y-%d-%m $B +%s` - `date -jf %Y-%d-%m $A +%s`)/86400))
nJoy!
A="2002-20-10"; B="2003-22-11"
echo $(((`date -jf "%Y-%d-%m" "$B" +%s` - `date -jf "%Y-%d-%m" "$A" +%s`)/86400))
, tức là gói cả hai định dạng và biến thành dấu ngoặc kép, nếu không có thể thất bại trên định dạng ngày tháng khác nhau (ví dụ %b %d, %Y
/ Jul 5, 2017
)
Ngay cả khi bạn không có ngày GNU, có thể bạn sẽ cài đặt Perl:
use Time::Local;
sub to_epoch {
my ($t) = @_;
my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/);
return timelocal(0, 0, 0, $d+0, $m-1, $y-1900);
}
sub diff_days {
my ($t1, $t2) = @_;
return (abs(to_epoch($t2) - to_epoch($t1))) / 86400;
}
print diff_days("2002-20-10", "2003-22-11"), "\n";
Điều này trả về 398.041666666667
- 398 ngày và một giờ do tiết kiệm ánh sáng ban ngày.
Câu hỏi đã xuất hiện trở lại trên nguồn cấp dữ liệu của tôi. Đây là một phương pháp ngắn gọn hơn bằng cách sử dụng một mô-đun đi kèm Perl
days=$(perl -MDateTime -le '
sub parse_date {
@f = split /-/, shift;
return DateTime->new(year=>$f[0], month=>$f[2], day=>$f[1]);
}
print parse_date(shift)->delta_days(parse_date(shift))->in_units("days");
' $A $B)
echo $days # => 398
Đây là cách tiếp cận làm việc của tôi bằng cách sử dụng zsh. Đã thử nghiệm trên OSX:
# Calculation dates
## A random old date
START_DATE="2015-11-15"
## Today's date
TODAY=$(date +%Y-%m-%d)
# Import zsh date mod
zmodload zsh/datetime
# Calculate number of days
DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 ))
echo "Your value: " $DIFF
Kết quả:
Your value: 1577
Về cơ bản, chúng tôi sử dụng tính năng strftime
reverse ( -r
) để chuyển đổi chuỗi ngày của chúng tôi trở lại dấu thời gian, sau đó chúng tôi thực hiện tính toán của mình.
Tôi sẽ gửi một giải pháp khả thi khác trong Ruby. Có vẻ như đây là chiếc nhỏ nhất và trông sạch sẽ nhất cho đến nay:
A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF
date
hoặc một số ngôn ngữ kịch bản) và tôi thành thật nghĩ rằng Ruby là một cách tốt để đi đến đây. Giải pháp này rất ngắn gọn và không sử dụng bất kỳ thư viện không chuẩn hoặc các phần phụ thuộc khác. Trên thực tế, tôi nghĩ rằng có khả năng Ruby được cài đặt cao hơn so với việc cài đặt ngày GNU.
Sử dụng các hàm shell từ http://cfajohnson.com/shell/ssr/ssr-scripts.tar.gz ; chúng hoạt động trong bất kỳ trình bao Unix tiêu chuẩn nào.
date1=2012-09-22
date2=2013-01-31
. date-funcs-sh
_date2julian "$date1"
jd1=$_DATE2JULIAN
_date2julian "$date2"
echo $(( _DATE2JULIAN - jd1 ))
Xem tài liệu tại http://cfajohnson.com/shell/ssr/08-The-Dating-Game.shtml
Sử dụng lệnh mysql
$ echo "select datediff('2013-06-20 18:12:54+08:00', '2013-05-30 18:12:54+08:00');" | mysql -N
Kết quả: 21
LƯU Ý: Chỉ các phần ngày của các giá trị được sử dụng trong tính toán
Tham khảo: http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html# Chức năng_datediff
trên unix, bạn nên cài đặt ngày GNU. bạn không cần phải đi lệch khỏi bash. đây là giải pháp được rút ra theo ngày, chỉ để hiển thị các bước. nó có thể được đơn giản hóa và mở rộng đến ngày tháng đầy đủ.
DATE=$(echo `date`)
DATENOW=$(echo `date -d "$DATE" +%j`)
DATECOMING=$(echo `date -d "20131220" +%j`)
THEDAY=$(echo `expr $DATECOMING - $DATENOW`)
echo $THEDAY
Điều này giả định rằng một tháng là 1/12 của một năm:
#!/usr/bin/awk -f
function mktm(datespec) {
split(datespec, q, "-")
return q[1] * 365.25 + q[3] * 365.25 / 12 + q[2]
}
BEGIN {
printf "%d\n", mktm(ARGV[2]) - mktm(ARGV[1])
}
Hãy thử cái này:
perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'
Giả sử chúng tôi rsync các bản sao lưu Oracle DB vào đĩa cấp ba theo cách thủ công. Sau đó, chúng tôi muốn xóa các bản sao lưu cũ trên đĩa đó. Vì vậy, đây là một tập lệnh bash nhỏ:
#!/bin/sh
for backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'}
do
for f in `find $backup_dir -type d -regex '.*_.*_.*' -printf "%f\n"`
do
f2=`echo $f | sed -e 's/_//g'`
days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400))
if [ $days -gt 30 ]; then
rm -rf $backup_dir/$f
fi
done
done
Sửa đổi lịch và thời gian lưu giữ ("30 ngày") để phù hợp với nhu cầu của bạn.
Đối với MacOS sierra (có thể từ Mac OS X yosemate),
Để nhận thời gian kỷ nguyên (Giây từ năm 1970) từ tệp và lưu vào tệp var:
old_dt=`date -j -r YOUR_FILE "+%s"`
Để nhận thời gian của thời gian hiện tại
new_dt=`date -j "+%s"`
Để tính toán chênh lệch của hai thời gian trên
(( diff = new_dt - old_dt ))
Để kiểm tra xem chênh lệch quá 23 ngày
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s)) )) SECOUND
sử dụng nó để lấy ngày hôm nay và giây của bạn kể từ ngày bạn muốn. nếu bạn muốn nó với ngày chỉ cần chia nó với 86400
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s))/ 86400)) SECOUND