मैं वर्ष के दिन (1-366) और वर्ष (जैसे 2011) से प्रारूप YYYYMMDD में जाने के लिए देख रहा हूँ?
मैं वर्ष के दिन (1-366) और वर्ष (जैसे 2011) से प्रारूप YYYYMMDD में जाने के लिए देख रहा हूँ?
जवाबों:
यह बैश फंक्शन मेरे लिए ग्नू-आधारित प्रणाली पर काम करता है:
jul () { date -d "$1-01-01 +$2 days -1 day" "+%Y%m%d"; }
कुछ उदाहरण:
$ y=2011; od=0; for d in {-4..4} 59 60 {364..366} 425 426; do (( d > od + 1)) && echo; printf "%3s " $d; jul $y $d; od=$d; done
-4 20101227
-3 20101228
-2 20101229
-1 20101230
0 20101231
1 20110101
2 20110102
3 20110103
4 20110104
59 20110228
60 20110301
364 20111230
365 20111231
366 20120101
425 20120229
426 20120301
यह समारोह जूलियन दिवस को पिछले वर्ष के अंतिम दिन के रूप में मानता है।
और यहाँ UNIX- आधारित सिस्टम, जैसे कि macOS, के लिए bash फंक्शन है:
jul () { (( $2 >=0 )) && local pre=+; date -v$pre$2d -v-1d -j -f "%Y-%m-%d" $1-01-01 +%Y%m%d; }
jul () { date -v+$2d -v-1d -j -f "%Y-%m-%d" $1-01-01 +%Y%m%d; }
सिर्फ बैश में नहीं किया जा सकता है, लेकिन अगर आपके पास पर्ल है:
use POSIX;
my ($jday, $year) = (100, 2011);
# Unix time in seconds since Jan 1st 1970
my $time = mktime(0,0,0, $jday, 0, $year-1900);
# same thing as a list that we can use for date/time formatting
my @tm = localtime $time;
my $yyyymmdd = strftime "%Y%m%d", @tm;
date
कोरुटिल्स में कमांड के बारे में सोच सकते हैं । मैंने इसे चेक किया और यह केवल वर्तमान तिथि को प्रारूपित करने या इसे नए मूल्य पर सेट करने का समर्थन करता है, इसलिए यह एक विकल्प नहीं है।
date
कमांड का उपयोग करके किया जा सकता है। मेरा जवाब देखिए। लेकिन पर्ल रास्ता ज्यादा आसान और तेज है।
date -d
info 'Date input formats'
यह देखने के लिए चलाएं कि किन स्वरूपों की अनुमति है।
YYYY-DDD दिनांक स्वरूप हो प्रतीत नहीं होता है, और कोशिश कर रहा
$ date -d '2011-011'
date: invalid date `2011-011'
दिखाता है कि यह काम नहीं करता है, इसलिए मुझे लगता njd
है कि यह सही है, सबसे अच्छा तरीका बाहरी उपकरण का उपयोग करना है bash
और इसके अलावा date
।
यदि आप वास्तव में केवल बैश और मूल कमांड लाइन टूल का उपयोग करना चाहते हैं, तो आप कुछ इस तरह कर सकते हैं:
julian_date_to_yyyymmdd()
{
date=$1 # assume all dates are in YYYYMMM format
year=${date%???}
jday=${date#$year}
for m in `seq 1 12`; do
for d in `seq 1 31`; do
yyyymmdd=$(printf "%d%02d%02d" $year $m $d)
j=$(date +"%j" -d "$yyyymmdd" 2>/dev/null)
if test "$jday" = "$j"; then
echo "$yyyymmdd"
return 0
fi
done
done
echo "Invalid date" >&2
return 1
}
लेकिन यह एक बहुत ही धीमा तरीका है।
एक तेज लेकिन अधिक जटिल तरीका प्रत्येक महीने में लूप करने की कोशिश करता है, उस महीने में आखिरी दिन पाता है, फिर देखता है कि जूलियन दिन उस सीमा में है या नहीं।
# year_month_day_to_jday <year> <month> <day> => <jday>
# returns 0 if date is valid, non-zero otherwise
# year_month_day_to_jday 2011 2 1 => 32
# year_month_day_to_jday 2011 1 32 => error
year_month_day_to_jday()
{
# XXX use local or typeset if your shell supports it
_s=$(printf "%d%02d%02d" "$1" "$2" "$3")
date +"%j" -d "$_s"
}
# last_day_of_month_jday <year> <month>
# last_day_of_month_jday 2011 2 => 59
last_day_of_month_jday()
{
# XXX use local or typeset if you have it
_year=$1
_month=$2
_day=31
# GNU date exits with 0 if day is valid, non-0 if invalid
# try counting down from 31 until we find the first valid date
while test $_day -gt 0; do
if _jday=$(year_month_day_to_jday $_year $_month $_day 2>/dev/null); then
echo "$_jday"
return 0
fi
_day=$((_day - 1))
done
echo "Invalid date" >&2
return 1
}
# first_day_of_month_jday <year> <month>
# first_day_of_month_jday 2011 2 => 32
first_day_of_month_jday()
{
# XXX use local or typeset if you have it
_year=$1
_month=$2
_day=1
if _jday=$(year_month_day_to_jday $_year $_month 1); then
echo "$_jday"
return 0
else
echo "Invalid date" >&2
return 1
fi
}
# julian_date_to_yyyymmdd <julian day> <4-digit year>
# e.g. julian_date_to_yyyymmdd 32 2011 => 20110201
julian_date_to_yyyymmdd()
{
jday=$1
year=$2
for m in $(seq 1 12); do
endjday=$(last_day_of_month_jday $year $m)
if test $jday -le $endjday; then
startjday=$(first_day_of_month_jday $year $m)
d=$((jday - startjday + 1))
printf "%d%02d%02d\n" $year $m $d
return 0
fi
done
echo "Invalid date" >&2
return 1
}
last_day_of_month_jday
उदाहरण के लिए date -d "$yyyymm01 -1 day"
(केवल GNU तिथि) या का उपयोग करके लागू किया जा सकता है $(($(date +"%s" -d "$yyyymm01") - 86400))
।
((day--))
:। बैश में for
इस तरह से लूप होते हैं for ((m=1; m<=12; m++))
(कोई ज़रूरत नहीं seq
)। यह मानना बहुत सुरक्षित है कि आपके द्वारा उपयोग की जा रही कुछ अन्य विशेषताओं के गोले हैं local
।
local
बिजीबॉक्स है ash
।
यदि वर्ष का दिन (1-366) 149 है और वर्ष 2014 है ,
$ date -d "148 days 2014-01-01" +"%Y%m%d"
20140529
वर्ष -1 मान के दिन को इनपुट करना सुनिश्चित करें ।
बाश में मेरा समाधान
from_year=2013
from_day=362
to_year=2014
to_day=5
now=`date +"%Y/%m/%d" -d "$from_year/01/01 + $from_day days - 2 day"`
end=`date +"%Y/%m/%d" -d "$to_year/01/01 + $to_day days - 1 day"`
while [ "$now" != "$end" ] ;
do
now=`date +"%Y/%m/%d" -d "$now + 1 day"`;
echo "$now";
calc_day=`date -d "$now" +%G'.'%j`
echo $calc_day
done
मुझे लगता है कि यह उम्र से पहले पूछा गया था, लेकिन मेरे द्वारा देखे गए उत्तरों में से कोई भी मैं शुद्ध बीएचएस पर विचार नहीं करता क्योंकि वे सभी जीएनयू का उपयोग करते हैं date
। मैंने सोचा था कि मैं जवाब देने के लिए एक छुरा लूंगा ... लेकिन मैं आपको समय से पहले चेतावनी देता हूं, जवाब सुरुचिपूर्ण नहीं है, न ही यह 100 से अधिक लाइनों पर छोटा है। यह नीचे गिराया जा सकता है, लेकिन मैं दूसरों को आसानी से देखने देना चाहता था कि यह क्या करता है।
यहां प्राथमिक "ट्रिक्स" यह पता लगा रही हैं कि क्या एक वर्ष एक लीप वर्ष (या नहीं) है %
, जो वर्ष के MODULUS को 4 से विभाजित करके प्राप्त किया जाता है, और फिर प्रत्येक महीने में दिनों को जोड़ते हैं, और यदि आवश्यक हो तो फरवरी के लिए एक अतिरिक्त दिन। , मूल्यों की एक सरल तालिका का उपयोग कर।
कृपया बेहतर तरीके से टिप्पणी करने और सुझाव देने के लिए स्वतंत्र महसूस करें, क्योंकि मैं मुख्य रूप से खुद को और अधिक जानने के लिए यहां हूं, और मैं अपने आप को एक सर्वश्रेष्ठ नौसिखिया समझूंगा। मैंने इसे पोर्टेबल बनाने की पूरी कोशिश की, क्योंकि मुझे पता है कि कैसे, और इसका मतलब है कि मेरी राय में कुछ समझौता है।
कोड पर ... मुझे आशा है कि यह बहुत आत्म-व्याख्यात्मक है।
#!/bin/sh
# Given a julian day of the year and a year as ddd yyyy, return
# the values converted to yyyymmdd format using ONLY bash:
ddd=$1
yyyy=$2
if [ "$ddd" = "" ] || [ "$yyyy" = "" ]
then
echo ""
echo " Usage: <command> 123 2016"
echo ""
echo " A valid julian day from 1 to 366 is required as the FIRST"
echo " parameter after the command, and a valid 4-digit year from"
echo " 1901 to 2099 is required as the SECOND. The command and each"
echo " of the parameters must be separated from each other with a space."
echo " Please try again."
exit
fi
leap_yr=$(( yyyy % 4 ))
if [ $leap_yr -ne 0 ]
then
leap_yr=0
else
leap_yr=1
fi
last_doy=$(( leap_yr + 365 ))
while [ "$valid" != "TRUE" ]
do
if [ 0 -lt "$ddd" ] && [ "$last_doy" -ge "$ddd" ]
then
valid="TRUE"
else
echo " $ddd is an invalid julian day for the year given."
echo " Please try again with a number from 1 to $last_doy."
exit
fi
done
valid=
while [ "$valid" != "TRUE" ]
do
if [ 1901 -le "$yyyy" ] && [ 2099 -ge "$yyyy" ]
then
valid="TRUE"
else
echo " $yyyy is an invalid year for this script."
echo " Please try again with a number from 1901 to 2099."
exit
fi
done
if [ "$leap_yr" -eq 1 ]
then
jan=31 feb=60 mar=91 apr=121 may=152 jun=182
jul=213 aug=244 sep=274 oct=305 nov=335
else
jan=31 feb=59 mar=90 apr=120 may=151 jun=181
jul=212 aug=243 sep=273 oct=304 nov=334
fi
if [ "$ddd" -gt $nov ]
then
mm="12"
dd=$(( ddd - nov ))
elif [ "$ddd" -gt $oct ]
then
mm="11"
dd=$(( ddd - oct ))
elif [ "$ddd" -gt $sep ]
then
mm="10"
dd=$(( ddd - sep ))
elif [ "$ddd" -gt $aug ]
then
mm="09"
dd=$(( ddd - aug ))
elif [ "$ddd" -gt $jul ]
then
mm="08"
dd=$(( ddd - jul ))
elif [ "$ddd" -gt $jun ]
then
mm="07"
dd=$(( ddd - jun ))
elif [ "$ddd" -gt $may ]
then
mm="06"
dd=$(( ddd - may ))
elif [ "$ddd" -gt $apr ]
then
mm="05"
dd=$(( ddd - apr ))
elif [ "$ddd" -gt $mar ]
then
mm="04"
dd=$(( ddd - mar ))
elif [ "$ddd" -gt $feb ]
then
mm="03"
dd=$(( ddd - feb ))
elif [ "$ddd" -gt $jan ]
then
mm="02"
dd=$(( ddd - jan ))
else
mm="01"
dd="$ddd"
fi
if [ ${#dd} -eq 1 ]
then
dd="0$dd"
fi
if [ ${#yyyy} -lt 4 ]
then
until [ ${#yyyy} -eq 4 ]
do
yyyy="0$yyyy"
done
fi
printf '\n %s%s%s\n\n' "$yyyy" "$mm" "$dd"
OLD_JULIAN_VAR=$(date -u -d 1840-12-31 +%s)
TODAY_DATE=`date --date="$odate" +"%Y-%m-%d"`
TODAY_DATE_VAR=`date -u -d "$TODAY_DATE" +"%s"`
export JULIAN_DATE=$((((TODAY_DATE_VAR - OLD_JULIAN_VAR))/86400))
echo $JULIAN_DATE
नीचे गणितीय रूप से दर्शाया गया है
[(date in sec)-(1840-12-31 in sec)]/(sec in a day 86400)