2010-09-15 21 views
22

में एक लाइब्रेरी और webservice का उपयोग कर रहा हूं, आईएसओ 8601 में समय-अंतराल संचारित करता है: PnYnMnDTnHnMnS। मैं इस तरह के प्रारूपों को सेकंड में कनवर्ट करना चाहता हूं। और इसके विपरीत। सेकंड की गणना करने के लिए बहुत आसान है।पार्स और आईएसओ 8601 दिनांक और समय अंतराल, जैसे PHP

उदाहरण अंतराल मान हैं:

  • PT1M या PT60S (1 मिनट)
  • PT1H, PT60M या PT3600S (1 घंटा)

मैं दो कार्यों की जरूरत है: करने के लिए इस तरह के मूल्यों से पार्स सेकंड: iso8601_interval_to_seconds() और सेकंड से ऐसे अंतराल में: iso8601_interval_from_seconds()

उत्तरार्द्ध अपेक्षाकृत सरल है, क्योंकि इसे `PT {$ सेकंड} एस" के रूप में किया जा सकता है, बस हर समय सेकंड पास करें। हो सकता है कि यह एक पार्सर के साथ अच्छा हो सकता है जो एच (घंटा) या एम (मिनट) पर स्विच करता है?

पहला कठिन है, लेकिन शायद PHP में कई स्ट्रिंग-टू-डेट कन्वर्टर्स में से एक के साथ एक चाल है? मुझे सीखना अच्छा लगेगा कि अंतराल को पार्स करने के लिए इस तरह के फ़ंक्शन का उपयोग कैसे करें। या एक विकल्प सीखो।

+0

एक बहुत देर से सावधानी ... सेकंड के लिए P1MT परिवर्तित करने के लिए असंभव है जब तक आप जानते हैं कि आप 28 के साथ, एक महीने परिवर्तित कर रहे हैं हो सकता है 29, 30, या 31 दिन उस मामले के लिए, आप पी 1 वाईटी को चार साल में गलत होने के बिना 365 दिनों में भी परिवर्तित नहीं कर सकते हैं। (एक कारण है कि मानक में दिन या सेकंड में अंतराल निर्दिष्ट नहीं होते हैं।) – Bevan

+0

@ बेवन: ली द्वारा उत्तर इस के साथ विवरण में जाता है। टीएल; डीआर: आपको एक शुरुआती तारीख चाहिए। – berkes

+0

आह - धन्यवाद @berkes, पृष्ठ को स्किम करते समय मुझे याद आया (मुझे कुछ असंबंधित होने के दौरान यह मिला)। – Bevan

उत्तर

17

ऐसा लगता है कि PHP 5.3 के DateInterval इसका समर्थन करता है।

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

+1

डेटइंटरवाल ('पीटी 1 एच') समान आकर्षण काम करता है!अब, मैं इन स्ट्रिंग्स को फिर से बनाने के लिए एक अच्छा तरीका देखना चाहूंगा, अन्यथा PTXXXS, दूसरे में हरकत :) – berkes

+0

⚠️ PHP की 'डेट इंटरवल()' में एक बग है जो आईएसओ 8601 प्रस्तुतियों में भिन्नताओं को अनुमति नहीं देता है : https://bugs.php.net/bug.php?id=53831 –

0

क्या आप देख रहे हैं दिनांक समय है :: diff

DateInterval वस्तु के रूप में वर्णन नीचे दो तिथियों या विफलता पर गलत के बीच का अंतर का प्रतिनिधित्व:

$datetime1 = new DateTime('2009-10-11'); 
$datetime2 = new DateTime('2009-10-13'); 
$interval = $datetime1->diff($datetime2); 
echo $interval->format('%R%d days'); 

बस के बजाय तारीखों के सेकंड का उपयोग करें।

इस से http://www.php.net/manual/en/datetime.diff.php

है DateInterval के लिए एक संदर्भ को देखने के http://www.php.net/manual/en/class.dateinterval.php

+0

मैं यह देखने में असफल रहा कि यह PT10M -alike ISO 8601 प्रारूपों में कनवर्ट करने में कैसे मदद करता है। – berkes

7

ध्यान रखें कि अवधियों, जिनमें शामिल है दिन, महीने, और/या सेकंड की तरह एक अवधि में साल परिवर्तित सही ढंग से जानने के बिना नहीं किया जा सकता एक वास्तविक प्रारंभिक तिथि/समय।

उदाहरण

1 SEP 2010: +P1M2D means +2764800 seconds 
1 OCT 2010: +P1M2D means +2851200 seconds 

क्योंकि सितंबर 30 दिन होते हैं, और अक्टूबर 31-दिन है है कि के लिए

। लीप-साल और लीप-सेकंड की वजह से, वर्ष अंतराल को परिवर्तित करने के साथ एक ही समस्या होती है। लीप-साल महीनों के रूपांतरण के लिए और जटिलता भी पेश करते हैं - क्योंकि फरवरी से लीप-साल में एक दिन लंबा है, अन्यथा यह अन्यथा है। दिन उन क्षेत्रों में समस्याग्रस्त हैं जहां डेलाइट सेविंग टाइम का अभ्यास किया जाता है - डीएसटी संक्रमण के दौरान होने वाली एक दिवसीय अवधि वास्तव में 1 घंटे लंबी होती है, अन्यथा यह अन्यथा होगी।

यह सब कहा जा रहा है - आप निश्चित रूप से युक्त घंटे, मिनट और सेकंड्स को केवल सेकेंड वाले मानों में संपीड़ित मूल्यों को संकुचित कर सकते हैं। मैं सुझाव दूंगा कि आप नौकरी करने के लिए एक सरल पार्सर बनाएं (या शायद नियमित अभिव्यक्ति पर विचार करें)।

बस उपरोक्त उल्लिखित संकटों से अवगत रहें - वहां ड्रेगन होंगे। यदि आप दिन, महीनों और/या वर्षों से निपटने का इरादा रखते हैं, तो आपको ज्ञात दिनांक/समय के संदर्भ में गणित करने के लिए अंतर्निहित तंत्रों में से एक का उपयोग करने की आवश्यकता है। जैसा कि अन्य ने उल्लेख किया है: दिनांक अंतराल वर्ग, संयोजन में सूखे, डेटटाइम कक्षा पर प्रदान किए गए कार्यों शायद इस से निपटने का सबसे सहज तरीका है। लेकिन यह केवल PHP संस्करण 5.3.0 या उससे अधिक में उपलब्ध है।

आप v5.3.0 से भी कम समय के साथ काम करना है, तो आप इस छोटे से मणि के आसपास कुछ बनाने की कोशिश कर सकते हैं:

$startDateTime = '19700101UTC'; 
$duration = strtotime($startDateTime.'+1Year1Day1Second') - strtotime($startDateTime); 
print("Duration in Seconds: $duration"); 

strtotime सीधे आईएसओ 8601 प्रारूप के साथ काम नहीं करेगा (जैसे P1Y1DT1S।) , लेकिन प्रारूप यह है कि समझता है (1Year1Day1Second) बहुत दूर नहीं है - यह एक बहुत सीधी-आगे रूपांतरण होगा। (थोड़ा "हैकी" ... लेकिन यह आपके लिए PHP है)।

शुभकामनाएं!

+0

इस बारे में सोचने के बारे में सोचकर मैं उम्मीद करता हूं कि सेकंड + महीनों + दिनों + घंटे + मिनट + सेकेंड को इसे और अधिक पठनीय बनाने के लिए सेकेंड की पूर्ण संख्या को फिर से लिखना होगा, इसका वास्तविक मूल्य नहीं बदलेगा, जिसका अर्थ है कि जहां भी एक परिवर्तनीय अंतराल है, मानक मूल्य चुना जाएगा। तो, महीनों के लिए, यह 30 दिन = 1 कैलेंडर महीने होगा। मैं यह जानने की कोशिश कर रहा हूं कि वे इसे मानक में कहां निर्दिष्ट करते हैं लेकिन देर हो रही है, और मैं केवल भुगतान के बिना अंतिम मसौदा देख सकता हूं: http://xml.coverpages.org/ISO-FDIS-8601.pdf – Fanis

+5

पर पहले यह * ऐसा लगता है कि यह सहज ज्ञान होगा, लेकिन यदि आप वास्तव में इसके बारे में सोचते हैं, तो यह स्पष्ट हो जाता है कि चीजें वास्तव में इस तरह काम नहीं कर सकती हैं। यह बताता है कि "कैलेंडर समय" (दिन, महीनों, वर्ष) "पूर्ण समय" (सेकेंड, मिनट, घंटे) के रूप में उतना ही महत्वपूर्ण है - जब हम कैलेंडर समय का उपयोग करते हैं, तो हमारा मतलब है कि जब हम पूर्ण समय का उपयोग करते हैं तो कुछ मौलिक रूप से भिन्न होता है। उदाहरण के लिए: आपके जन्मदिन कितने दूर हैं? हमेशा 1 साल, हमेशा 8760 घंटे नहीं। अगर पिछले महीने का क्रेडिट कार्ड बिल 21 अगस्त दिनांकित था, तो इस महीने की तारीख क्या होगी? 21 सितंबर। हमेशा 1 महीने, 30 दिनों के नहीं। – Lee

8

strtotime आईएसओ 8601 प्रारूप सीधे (। जैसे P1Y1DT1S), लेकिन प्रारूप है कि यह समझ में (1Year1Day1Second) करता है साथ काम नहीं करेंगे नहीं भी दूर है - यह होगा एक बहुत सीधी-सपाट रूपांतरण । (थोड़ा "हैकी" ... लेकिन यह आपके लिए PHP है)।

धन्यवाद ली, मुझे पता है strtotime इस प्रारूप को स्वीकार नहीं किया था। यह मेरी पहेली का लापता हिस्सा था। शायद मेरे काम आपका जवाब पूरा कर सकते हैं।

function parse_duration($iso_duration, $allow_negative = true){ 
    // Parse duration parts 
    $matches = array(); 
    preg_match('/^(-|)?P([0-9]+Y|)?([0-9]+M|)?([0-9]+D|)?T?([0-9]+H|)?([0-9]+M|)?([0-9]+S|)?$/', $iso_duration, $matches); 
    if(!empty($matches)){  
     // Strip all but digits and - 
     foreach($matches as &$match){ 
      $match = preg_replace('/((?!([0-9]|-)).)*/', '', $match); 
     } 
     // Fetch min/plus symbol 
     $result['symbol'] = ($matches[1] == '-') ? $matches[1] : '+'; // May be needed for actions outside this function. 
     // Fetch duration parts 
     $m = ($allow_negative) ? $matches[1] : ''; 
     $result['year'] = intval($m.$matches[2]); 
     $result['month'] = intval($m.$matches[3]); 
     $result['day'] = intval($m.$matches[4]); 
     $result['hour'] = intval($m.$matches[5]); 
     $result['minute'] = intval($m.$matches[6]); 
     $result['second'] = intval($m.$matches[7]);  
     return $result; 
    } 
    else{ 
     return false; 
    } 
} 

फ़ंक्शन नकारात्मक स्वरूपों का भी समर्थन करता है। -P10Y9MT7M5S एक सरणी वापस करेगा: [वर्ष] => -10 [महीना] => -9 [दिन] => 0 [घंटा] => 0 [मिनट] => -7 [दूसरा] = > -5 यदि यह व्यवहार वांछित नहीं है तो दूसरे पैरामीटर के रूप में गलत हो। इस तरह फ़ंक्शन हमेशा सकारात्मक मान लौटाएगा। न्यूनतम/प्लस प्रतीक अभी भी परिणाम कुंजी ['प्रतीक'] में उपलब्ध होगा।

और थोड़ा अद्यतन: यह फ़ंक्शन सेकंड की कुल राशि प्राप्त करने के लिए पहले फ़ंक्शन का उपयोग करता है।

function get_duration_seconds($iso_duration){ 
    // Get duration parts 
    $duration = parse_duration($iso_duration, false); 
    if($duration){ 
     extract($duration); 
     $dparam = $symbol; // plus/min symbol 
     $dparam .= (!empty($year)) ? $year . 'Year' : ''; 
     $dparam .= (!empty($month)) ? $month . 'Month' : ''; 
     $dparam .= (!empty($day)) ? $day . 'Day' : ''; 
     $dparam .= (!empty($hour)) ? $hour . 'Hour' : ''; 
     $dparam .= (!empty($minute)) ? $minute . 'Minute' : ''; 
     $dparam .= (!empty($second)) ? $second . 'Second' : ''; 
     $date = '19700101UTC'; 
     return strtotime($date.$dparam) - strtotime($date); 
    } 
    else{ 
     // Not a valid iso duration 
     return false; 
    } 
} 

$foo = '-P1DT1S'; 
echo get_duration_seconds($foo); // Output -86399 
$bar = 'P1DT1S'; 
echo get_duration_seconds($bar); // Output 86401 
+0

हाय, PHP 5.4 के साथ अब तक एक और सीधी विधि है? ऐसा नहीं है कि मैं इस समारोह के लिए आपको बहुत धन्यवाद नहीं देना चाहता, लेकिन शायद पहले से ही एक क्लीनर विधि है। – andreszs

+0

मैंने इस उम्र पहले हेहेह लिखा था। मुझे लगता है कि मैं समारोह को फिर से लिख सकता हूं। समय पर बहुत कम समय, लेकिन मैं इसे बाद में देख लूंगा। –

+0

क्या आप पाइप '|' वर्णों को समझा सकते हैं? उनके बाद एक वैकल्पिक शाखा नहीं होती है, लेकिन वे बैकरेफर में शामिल होने के लिए एक प्रश्न चिह्न '? |' से पहले नहीं हैं। http://php.net/manual/de/regexp.reference.subpatterns.php एक खाली विकल्प की आवश्यकता नहीं है, क्योंकि '?' क्वांटिफ़ायर का उपयोग किया जाता है। – CoDEmanX

1
function parsePTTime($pt_time) 
{ 
    $string = str_replace('PT', '', $pt_time); 
    $string = str_replace('H', 'Hour', $string); 
    $string = str_replace('M', 'Minute', $string); 
    $string = str_replace('S', 'Second', $string); 

    $startDateTime = '19700101UTC'; 
    $seconds = strtotime($startDateTime . '+' . $string) - strtotime($startDateTime); 

    return $seconds; 
} 

टेस्ट:

PT1H   - OK 
PT23M  - OK 
PT45S  - OK 
PT1H23M  - OK 
PT1H45S  - OK 
PT23M45S  - OK 
PT1H23M45S - OK 
संबंधित मुद्दे