दिनांक और बैश का उपयोग करके समय घटाएं


19

एसई नेटवर्क पर अन्य सभी प्रश्न परिदृश्यों के साथ सौदा करते हैं, जहां या तो तारीख को माना जाता है now( क्यू ) या जहां केवल एक तारीख निर्दिष्ट है ( क्यू )।

मैं जो करना चाहता हूं वह एक तारीख और समय की आपूर्ति है, और फिर उस से एक समय घटाएं।
यहाँ मैं पहले की कोशिश की है:

date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"

यह परिणाम है 2018-12-10 06:39:55- यह 7 घंटे जोड़ा गया। फिर 20:05 मिनट घटाया गया।

के पेज manऔर infoपेज को पढ़ने के बाद date, मुझे लगा कि मैंने इसे इसके साथ तय कर लिया है:

date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"

लेकिन, एक ही परिणाम। यह 7 घंटे भी कहाँ से मिलता है?

मैंने अन्य तारीखों की भी कोशिश की क्योंकि मुझे लगा कि शायद उस दिन हमारे पास 7200 लीप सेकंड थे, जो लोल को जानता है। लेकिन वही परिणाम।

कुछ और उदाहरण:

$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00

$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00

लेकिन यहां यह दिलचस्प हो जाता है। यदि मैं इनपुट पर समय छोड़ देता हूं, तो यह ठीक काम करता है:

$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00

$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00

$ date --version
date (GNU coreutils) 8.30

मुझे किसकी याद आ रही है?

अद्यतन: मैंने Zअंत में जोड़ा है , और इसने व्यवहार को बदल दिया है:

$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00

मैं अभी भी उलझन में हूँ। दिनांक के बारे में GNU जानकारी पृष्ठ में इसके बारे में बहुत कुछ नहीं है ।

मुझे लगता है कि यह एक समय क्षेत्र का मुद्दा है, लेकिन आईएसओ 8601 पर द कैलेंडर विकी के हवाले से :

यदि कोई UTC संबंध जानकारी समय प्रतिनिधित्व के साथ नहीं दी जाती है, तो समय को स्थानीय समय माना जाता है।

जो मुझे चाहिए। मेरा स्थानीय समय भी सही ढंग से निर्धारित है। मुझे यकीन नहीं है कि डेट टाइमजोन के साथ डेट करने के लिए मुझे इस सरल मामले में डेटाइम की आपूर्ति करने और इसके कुछ को घटाना चाहते हैं। यह तारीख स्ट्रिंग से घंटे घटाना नहीं होना चाहिए पहले? यहां तक ​​कि अगर यह इसे पहले एक तारीख में परिवर्तित करता है और फिर घटाव करता है, अगर मैं किसी भी घटाव को छोड़ देता हूं तो मुझे वही मिलता है जो मैं चाहता हूं:

$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00

तो अगर यह वास्तव में एक समय क्षेत्र का मुद्दा है, तो यह पागलपन कहां से आता है?


जवाबों:


21

अंतिम उदाहरण में आपके लिए चीजें स्पष्ट होनी चाहिए: टाइमज़ोन

$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S 
2019-01-19_08:30:00

जैसा कि आउटपुट स्पष्ट रूप से टाइमज़ोन से भिन्न होता है, मुझे समय-सीमा निर्दिष्ट किए बिना टाइम स्ट्रिंग के लिए लिए गए कुछ गैर-स्पष्ट डिफ़ॉल्ट पर संदेह होगा। कुछ मूल्यों का परीक्षण, यह UTC-05: 00 प्रतीत होता है , हालांकि मुझे यकीन नहीं है कि वह क्या है।

$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z           
2019-01-19_05:00:00UTC

इसका उपयोग केवल तिथि अंकगणित करते समय किया जाता है।


ऐसा लगता है कि यहाँ मुद्दा यह है कि अंकगणित के रूप - 2 hoursमें नहीं लिया जाता है, लेकिन एक समयक्षेत्र विनिर्देशक के रूप में :

# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date:     new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC

इसलिए, न केवल कोई अंकगणित किया जा रहा है, समय पर दिन के उजाले में 1 घंटे का समायोजन लगता है, जो हमारे लिए कुछ निरर्थक समय है।

यह भी इसके लिए रखती है:

# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date:     new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC

थोड़ा और डिबगिंग, पार्सिंग लगता है: 2019-01-19T05:00:00 - 2( -2समयक्षेत्र होने के नाते), और hours(= 1 घंटा), एक निहित जोड़ के साथ। यह देखना आसान हो जाता है कि क्या आप इसके बजाय मिनट का उपयोग करते हैं:

# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date:     new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC

तो, ठीक है, तिथि अंकगणित किया जा रहा है, बस वह नहीं जो हमने मांगा था। ¯ \ (ツ) / ¯


1
@confetti यह वास्तव में करता है; मुझे लगता है कि इस डिफ़ॉल्ट TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%STZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
टाइमज़ोन

2
dateआईएसओ 8601 मानक के अनुसार, एक संभावित बग हो सकता है , यदि कोई समय क्षेत्र की आपूर्ति नहीं की जाती है, तो स्थानीय समय (क्षेत्र) मान लिया जाना चाहिए, जो एक अंकगणितीय ऑपरेशन के मामले में नहीं है। हालांकि मेरे लिए बहुत अजीब मुद्दा है।
कंफ़ेद्दी

1
@confetti में समस्या पाई गई: - 2 hoursयहाँ समयक्षेत्र निर्दिष्ट के रूप में लिया गया है।
ओलोरीन

2
वाह। अब किसी तरह समझ में आता है। ठीक है, कम से कम इसे समझाता है। यह पता लगाने के लिए बहुत-बहुत धन्यवाद। मेरे लिए ऐसा लगता है कि उनके पार्सर को एक अपडेट की आवश्यकता है, हालांकि स्पष्ट रूप से एक प्रारूप और व्हाट्सएप के साथ इस तरह आप `2 घंटे` द्वारा टाइमज़ोन निर्दिष्ट नहीं करना चाहते हैं और यह निश्चित रूप से भ्रम पैदा कर रहा है। यदि वे पार्सर को अपडेट नहीं करना चाहते हैं, तो कम से कम मैनुअल को इस बारे में एक नोट प्राप्त करना चाहिए।
कंफ़ेद्दी

1
आज मुझे तारीख के --debugविकल्प के बारे में पता चला ! महान व्याख्या।
जेफ स्कालर

6

यह सही ढंग से काम करता है जब आप पहले इनपुट की तारीख को आईएसओ 8601 में बदलते हैं:

$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018

धन्यवाद, यह वास्तव में काम करता है, लेकिन क्या इसके लिए कोई स्पष्टीकरण है? मैंने अपने प्रश्न के बारे में आईएसओ 8601 के बारे में कुछ और जानकारी जोड़ी है, और मैं वास्तव में यह नहीं देख रहा हूं कि dateआपूर्ति की गई किसी भी घटा के बिना यह कहां गड़बड़ कर देगा, समयक्षेत्र को अछूता छोड़ दिया गया है और सब कुछ उम्मीद के मुताबिक है, बिना किसी आपूर्ति के समय क्षेत्र की जानकारी या रूपांतरण।
कंफ़ेद्दी

मैं बता नहीं सकता, क्षमा करें। अगर कोई और इसका जवाब दे सकता है तो मुझे खुशी होगी क्योंकि मैं भी सोच रहा था।
pLumo

मुझे भी खुशी होगी, लेकिन मैं इसे अभी के लिए स्वीकार करूंगा क्योंकि यह मेरी समस्या को ठीक करता है!
कंफ़ेद्दी

3
यह काम करता है क्योंकि टाइमजोन स्पेसिफ़ायरdate -I (उदाहरण 2018-12-10T00:00:00+02:00) को आउटपुट करता है, जो ओलरिन के जवाब
ilkkachu

6

TLDR: यह एक बग नहीं है। आपने अभी सूक्ष्म लेकिन प्रलेखित व्यवहारों में से एक पाया है date। जब समय अंकगणित के साथdate , तो एक टाइमज़ोन-स्वतंत्र प्रारूप (जैसे यूनिक्स समय) का उपयोग करें या इस कमांड को ठीक से उपयोग करने के तरीके को जानने के लिए बहुत सावधानी से प्रलेखन पढ़ें ।


GNU dateआपकी सिस्टम सेटिंग्स ( TZपर्यावरण चर या, अगर परेशान, सिस्टम डिफॉल्ट) का उपयोग करता है , तो तारीख -d/ --dateविकल्प के साथ फीड की गई तारीख और +formatतर्क द्वारा बताई गई तारीख दोनों को निर्धारित करने के लिए । --dateविकल्प भी आप अपनी ही विकल्प तर्क के लिए समयक्षेत्र को ओवरराइड करते हैं लेकिन इसके बारे में समय-क्षेत्र पर हावी नहीं होता +formatयह भ्रम की जड़ है, IMHO।

यह देखते हुए कि मेरा टाइमज़ोन UTC-6 है, निम्न आदेशों की तुलना करें:

$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0

पहले वाला मेरे टाइमजोन का उपयोग करता है -dऔर दोनों के लिए+format । दूसरे के लिए UTC का उपयोग करता है, -dलेकिन मेरे timezone के लिए +format। तीसरा दोनों के लिए यूटीसी का उपयोग करता है।

अब, निम्नलिखित सरल कार्यों की तुलना करें:

$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400

भले ही यूनिक्स समय मुझे एक ही बात कह रहा है, "सामान्य" समय मेरे स्वयं के समयक्षेत्र के कारण भिन्न होता है।

अगर मैं एक ही ऑपरेशन करना चाहता था, लेकिन विशेष रूप से मेरे समयक्षेत्र का उपयोग कर रहा था:

$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000

5
युग / यूनिक्स समय का उल्लेख करने के लिए तैयार किया गया है, जो समय अंकगणित करने का एकमात्र एकमात्र तरीका है
रुई एफ रिबेरो

1
TL, DR अगर आप बस अपने स्थानीय समय को ज़ुलु समय (जैसे पश्चिमी तट यूएसए -8 घंटे या -08:00) से ऑफसेट करते हैं , तो बस उस समय को इनपुट करने के लिए अपील करें ... और कुछ नहीं। उदाहरण: स्थानीयdate -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T' देता है : 2019-03-02 18:05:36
बी लेयर

1
@ परत आप सही हैं, यह उस परिदृश्य में अपेक्षित रूप से काम करता है। लेकिन उस स्थिति की कल्पना करें जहां उस दृष्टिकोण का उपयोग करके किसी दिए गए स्क्रिप्ट को एक अलग टाइमज़ोन के साथ एक स्थान पर निष्पादित किया जाता है। तकनीकी रूप से सही होने के बावजूद +formatतर्क द्वारा दी गई जानकारी के आधार पर आउटपुट गलत हो सकता है। उदाहरण के लिए, अपने सिस्टम पर, एक ही आदेश आउटपुट: local: 2019-03-02 20:05:39(अगर मैं जोड़ने %:zके लिए +format, यह स्पष्ट हो जाता है कि जानकारी सही है और विसंगति समय-क्षेत्रों की वजह से है)।
nxnev

@ लेयर IMHO, एक बेहतर सामान्य दृष्टिकोण दोनों -dऔर +formatया यूनिक्स समय के लिए एक ही टाइमज़ोन का उपयोग करना होगा , जैसा कि मैंने उत्तर में कहा था, अप्रत्याशित परिणामों से बचने के लिए।
nxnev

1
@nxnev सहमत हैं, यदि आप प्रकाशित / साझा की जाने वाली स्क्रिप्ट लिख रहे हैं। शुरुआती शब्द "यदि आप अपना स्वयं का समयक्षेत्र जानते हैं", तो शाब्दिक अर्थ के अलावा, आकस्मिक / व्यक्तिगत उपयोग करने वाले हैं। किसी को अपने स्वयं के सिस्टम के tz जानने के रूप में कुछ के रूप में flimsy पर भरोसा करने वाली एक स्क्रिप्ट प्रकाशित करना शायद स्क्रिप्ट साझाकरण गेम में नहीं होना चाहिए। :) दूसरी तरफ मैं अपने सभी व्यक्तिगत वातावरण पर अपनी खुद की कमांड का उपयोग करता / करती हूं।
बी लेयर

4

जीएनयू date सरल तिथि अंकगणित का समर्थन करता है, हालांकि @sudodus के उत्तर में दिखाए गए समय की गणना कभी-कभी अधिक स्पष्ट (और अधिक पोर्टेबल) होती है।

+/- का उपयोग जब टाइमस्टैम्प में निर्दिष्ट कोई समयक्षेत्र नहीं होता है, तो अगली बार एक समयक्षेत्र का मिलान करने का प्रयास शुरू होता है, इससे पहले कि कुछ और पार्स हो।

यह करने का एक तरीका है, "-" के बजाय "पहले" का उपयोग करें:

$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec  9 18:39:55 GMT 2018

या

$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec  9 18:39:55 GMT 2018

(यद्यपि आप मनमाने ढंग से "Z" का उपयोग नहीं कर सकते, यह मेरे क्षेत्र में काम करता है, लेकिन यह इसे UTC / GMT ज़ोन टाइमस्टैम्प बनाता है - अपने ज़ोन का उपयोग करें, या% z /% Z को जोड़कर ${TZ:-$(date +%z)} इसके बजाय टाइमस्टैम्प में )

इन रूपों की अतिरिक्त समय शर्तों को जोड़कर समय समायोजित करें:

  • "5 घंटे पहले" 5 घंटे घटाएं
  • "4 घंटे" जोड़ें (निहित) 4 घंटे
  • "3 घंटे इसलिए" जोड़ें (स्पष्ट) 3 घंटे (पुराने संस्करणों में समर्थित नहीं)

कई जटिल समायोजन, किसी भी क्रम में, का उपयोग किया जा सकता है (हालांकि रिश्तेदार और परिवर्तनीय शब्द जैसे "14 सप्ताह इसलिए अंतिम सोमवार", मुसीबत के दौरान पूछ रहा है; ;-)

(यहां एक और छोटी दाढ़ी भी है, dateहमेशा एक वैध तारीख देगा, इसलिए date -d "2019-01-31 1 month"2019-03-03 देता है, जैसा कि "अगले महीने" होता है)

समर्थित समय और दिनांक स्वरूपों की व्यापक विविधता को देखते हुए, टाइमज़ोन पार्सिंग आवश्यक रूप से मैला है: यह एक एकल या बहु-अक्षर प्रत्यय, एक घंटा या घंटा: मिनट ऑफसेट, एक नाम "अमेरिका / डेनवर" (या एक फ़ाइल नाम भी हो सकता है) के मामले में TZ चर )।

तुम्हारी 2018-12-10T00:00:00 संस्करण काम नहीं करता है क्योंकि "टी" सिर्फ एक सीमांकक है, एक समयक्षेत्र नहीं, अंत में "जेड" जोड़ने से वह काम (चुने हुए क्षेत्र की शुद्धता के अधीन) भी अपेक्षित हो जाता है।

देखें: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html और विशेष खंड में 7.7।


1
अन्य विकल्पों में शामिल हैं: date -d "2018-12-10 00:00:00 now -5 hoursया todayया 0 hourके बजाय now, कुछ भी है कि बताता है dateकि समय के बाद टोकन एक समय क्षेत्र ऑफसेट नहीं है।
स्टीफन चेजलस

1
या, पूर्णता के लिए, के बाद पुन: क्रम आर्ग द्वारा तिथि-समय छोड़ कुछ भी नहीं: तिथि -d "-5 घंटे 2018/12/10 00:00:00" `
बी परत

2

यह समाधान समझना आसान है, लेकिन थोड़ा अधिक जटिल है, इसलिए मैं इसे एक शेलस्क्रिप्ट के रूप में दिखाता हूं।

  • '1970-01-01 से 00:00:00 UTC' के बाद 'सेकंड' में बदलें
  • अंतर जोड़ना या घटाना
  • अंतिम dateकमांड लाइन के साथ एक मानव पठनीय प्रारूप में परिवर्तित करें

Shellscript:

#!/bin/bash

startdate="2018-12-10 00:00:00"

ddif="0"          # days
diff="-5:-20:-5"  # hours:minutes:seconds

#-----------------------------------------------------------------------------

ss1970in=$(date -d "$startdate" "+%s")  # seconds since 1970-01-01 00:00:00 UTC
printf "%11s\n" "$ss1970in"

h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11s\n" "$difs"

ss1970ut=$((ss1970in + difs))  # add/subtract the time difference
printf "%11s\n" "$ss1970ut"

date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.