Linux date कमांड के साथ ISO8601 तिथियों को पार्स कैसे करें


15

मैं एक फ़ाइल टाइमस्टैम्प उत्पन्न करने के लिए तिथि कमांड का उपयोग करने की कोशिश कर रहा हूं जो कि तिथि कमांड स्वयं व्याख्या कर सकती है। हालाँकि, दिनांक आदेश अपने स्वयं के आउटपुट को पसंद नहीं करता है, और मुझे यकीन नहीं है कि इसके आसपास कैसे काम किया जाए। इसका स्पष्ट उदाहरण:

sh-4.2$ date
Fri Jan  3 14:22:19 PST 2014
sh-4.2$ date +%Y%m%dT%H%M
20140103T1422
sh-4.2$ date -d "20140103T1422"
Thu Jan  2 23:22:00 PST 2014

दिनांक 15 घंटे की ऑफसेट के साथ स्ट्रिंग की व्याख्या करता प्रतीत होता है। क्या इसके लिए कोई ज्ञात वर्कअराउंड हैं?

संपादित करें: यह प्रदर्शन का मुद्दा नहीं है:

sh-4.2$ date +%s
1388791096
sh-4.2$ date +%Y%m%dT%H%M
20140103T1518
sh-4.2$ date -d 20140103T1518 +%s
1388737080
sh-4.2$ python
Python 3.3.3 (default, Nov 26 2013, 13:33:18) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1388737080 - 1388791096
-54016
>>> 54016/3600
15.004444444444445
>>> 

यूनिक्स टाइमस्टैम्प के रूप में प्रदर्शित होने पर यह अभी भी 15 घंटे से बंद है।

EDIT # 1

शायद मुझे इस सवाल को थोड़ा और अलग करना चाहिए। कहो कि मेरे पास फॉर्म की ISO8601 बुनियादी टाइमस्टैम्प की सूची है:

  • YYYYMMDDThhmm
  • YYYYMMDDThhmmss

उन्हें संगत यूनिक्स टाइमस्टैम्प में बदलने का सबसे सरल तरीका क्या है?

उदाहरण के लिए:

- 20140103T1422   = 1388787720
- 20140103T142233 = 1388787753

1
@ ड्र्यूबेन मैं टाइमस्टैम्प में कोई विशेष पात्र नहीं रख सकता। बस संख्या और अक्षर। तो नहीं, मैं ऐसा नहीं कर सकता, दुर्भाग्य से।
अलेक्स.फोन्निच

@sim TZ सेट नहीं है, लेकिन / etc / स्थानीय समय जुड़ा हुआ है।
alex.forencich

तुम मुझे मार रहे हो, क्या यह तुम्हारा अंतिम प्रश्न है? 8-)
SLM

20140103T1518आईएसओ 8601 मान्य नहीं है, यह
टाइमजोन

जवाबों:


9

आप "ज्ञात वर्कअराउंड" के लिए पूछें। यहाँ एक सरल है:

$ date -d "$(echo 20140103T1422 | sed 's/T/ /')"
Fri Jan  3 14:22:00 PST 2014

यह sedएक स्थान के साथ "टी" को बदलने के लिए उपयोग करता है। परिणाम एक प्रारूप है जो dateसमझता है।

यदि हम ISO8601 तिथि पर सेकंड जोड़ते हैं, तो dateऔर अधिक परिवर्तन की आवश्यकता है:

$ date -d "$(echo 20140103T142211 | sed -r 's/(.*)T(..)(..)(..)/\1 \2:\3:\4/')"
Fri Jan  3 14:22:11 PST 2014

उपरोक्त में, sed"T" को एक स्थान से बदल देता है और HHMMSS को HH: MM: SS में भी अलग कर देता है।


मेरे लिए काम करता है अगर + हटा दिया जाता है। हालाँकि, यह दूसरी परिशुद्धता टाइमस्टैम्प के लिए काम नहीं करता है, केवल मिनट परिशुद्धता।
अलेक्स.फोन्निच

@ alex.forencich उत्तर सेकंड सटीक के साथ अद्यतन। मुझे पता है कि अगर मैं चुना सेकंड प्रारूप आप की जरूरत नहीं है।
जॉन १०२४

8

Coreutils जानकारी डॉक्स कि आईएसओ 8601 "विस्तारित प्रारूप" समर्थित है कहते हैं।

आपको +%zइसे काम करने के लिए हाइफ़न, कॉलन और एक जोड़ना होगा ।

$ date +"%Y-%m-%dT%H:%M:%S%z"
2014-01-03T16:08:23-0800
$ date -d 2014-01-03T16:08:23-0800
Fri Jan  3 16:08:23 PST 2014

आपके प्रश्न के दूसरे भाग का उत्तर देने के लिए ...

चूंकि तिथि प्रारूप में केवल संख्याएँ और चिह्न होते हैं, इसलिए आप प्रत्येक प्रतीक को एक अद्वितीय अक्षर से बदल सकते हैं, उदाहरण के लिए tr

$ ts="$(date +"%Y-%m-%dT%H:%M:%S%z" | tr -- '-:+' 'hcp')"; echo "$ts"
2014h01h03T16c18c04h0800
$ date -d "$(echo "$ts" | tr -- 'hcp' '-:+')"
Fri Jan  3 16:18:04 PST 2014

या आप का उपयोग कर इसे पार्स सकता है Tऔर -या +विभाजक, जैसे के रूप में खोल का उपयोग करते हुए ${var%word}और ${var#word}विस्तार

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T162228-0800
$ date=${ts%T*}; time=${ts#*T}
etc.    

या bashनियमित अभिव्यक्ति मिलान का उपयोग करना

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T165611-0800
$ [[ "$ts" =~ (.*)(..)(..)T(..)(..)(..)(.....) ]]
$ match=("${BASH_REMATCH[@]}")
$ Y=${match[1]}; m=${match[2]}; d=${match[3]}; H=${match[4]}; M=${match[5]}; S=${match[6]}; z=${match[7]}
$ date -d "$Y-$m-$d"T"$H:$M:$S$z"
Fri Jan  3 16:56:11 PST 2014

या पर्ल, पायथन, आदि।


टाइमस्टैम्प में कोई विशेष वर्ण नहीं हो सकते। क्या आप अपने आप को वापस जोड़ने का एक अच्छा तरीका जानते हैं?
alex.forencich

6

GNU Coreutils ने केवल 8.13 संस्करण (2011-09-08 को जारी) के बाद से आईएसओ 8601 तारीखों को इनपुट के रूप में समर्थित किया है। आपको पुराने संस्करण का उपयोग करना चाहिए।

पुराने संस्करणों के तहत, आपको Tएक स्थान से बदलने की आवश्यकता है। अन्यथा इसे अमेरिकी सैन्य समय क्षेत्र के रूप में व्याख्यायित किया जाता है ।

यहां तक ​​कि हाल के संस्करणों के तहत, केवल पूरी तरह से पंक्चर किए गए फॉर्म को मान्यता दी गई है, न कि केवल अंकों और Tमध्य में मूल प्रारूप ।

# Given a possibly abbreviated ISO date $iso_date...
date_part=${iso_date%%T*}
if [ "$date_part" != "$iso_date" ]; then
  time_part=${abbreviated_iso_date#*T}
  case ${iso_date#*T} in
    [!0-9]*) :;;
    [0-9]|[0-9][0-9]) time_part=${time_part}:00;;
    *)
      hour=${time_part%${time_part#??}}
      minute=${time_part%${time_part#????}}; minute=${minute#??}
      time_part=${hour}:${minute}:${time_part#????};;
  esac
else
  time_part=
fi
date -d "$date_part $time_part"

2

मैंने इस नोट को मैन पेज के लिए नोट किया date

DATE STRING
      The --date=STRING is a mostly free format human readable date string
      such as "Sun, 29 Feb 2004 16:21:42 -0800"  or  "2004-02-29
      16:21:42"  or  even  "next Thursday".  A date string may contain 
      items indicating calendar date, time of day, time zone, day of
      week, relative time, relative date, and numbers.  An empty string 
      indicates the beginning of the day.  The date  string  format
      is more complex than is easily documented here but is fully described 
      in the info documentation.

यह निर्णायक नहीं है, लेकिन यह स्पष्ट रूप से उस समय प्रारूप स्ट्रिंग को नहीं दिखाता है, जिसमें Tआप [ISO 8601] के लिए प्रयास कर रहे हैं। के रूप में @Gilles जवाब संकेत दिया, के समर्थन GNU coreutils में आईएसओ 8601 अपेक्षाकृत नया है।

स्ट्रिंग को पुन: स्वरूपित करना

अपनी स्ट्रिंग को सुधारने के लिए आप पर्ल का उपयोग कर सकते हैं।

उदाहरण:

$ date -d "$(perl -pe 's/(.*)T(\d{2})(\d{2})(\d{2})/$1 $2:$3:$4/' \
    <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

आप इस हैंडल को दोनों स्ट्रिंग्स बना सकते हैं जिसमें सेकंड शामिल हैं और जो नहीं हैं।

20140103T1422:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T1422")"
Fri Jan  3 14:22:00 EST 2014

20140103T142233:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

@ alex.forencich - एक वैकल्पिक कमांड जो दोनों समय स्वरूपों को संभाल लेगा। मुझे एक एहसान करो और उपरोक्त टिप्पणियों को हटा दें जो अब प्रासंगिक नहीं हैं।
स्लम

1

दिनांक के मैन पेज के अनुसार, आपके द्वारा आउटपुट किया जाने वाला प्रारूप वैसा नहीं dateहै जैसा इनपुट के रूप में अपेक्षित है। मैन पेज यही कहता है:

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

तो आप इसे इस तरह से कर सकते हैं:

# date +%m%d%H%M%Y
010402052014
# date 010402052014
Sat Jan  4 02:05:00 EAT 2014

क्योंकि चर में जो आउटपुट स्ट्रिंग को परिभाषित करने के लिए उपयोग किया जाता है, +%m%d%H%M%Yवह इनपुट के रूप में इसकी अपेक्षा के बराबर होगा।


फिर आप ISO8601 प्रारूप की तारीख को निर्धारित करने के लिए एक कमांड दे सकते हैं कि किस तारीख की आवश्यकता है? वास्तविक संग्रहित टाइमस्टैम्प को ISO8601 प्रारूप में होना चाहिए ताकि वे तिथि के अनुसार क्रमबद्ध हो सकें।
अलेक्स.फोर्निच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.