2012-01-24 19 views
5

यहाँ मैं अब तक क्या कर लिया है:प्रारूपित स्ट्रिंग के रूप में दो दिनों के बीच अंतर की गणना कैसे करें?

/** 
* Parse a duration between 2 date/times in seconds 
* and to convert that duration into a formatted string 
* 
* @param integer $time_start start time in seconds 
* @param integer $time_end end time in seconds 
* @param string $format  like the php strftime formatting uses %y %m %w %d %h or %i. 
* @param boolean $chop  chop off sections that have 0 values 
*/ 
public static function FormatDateDiff($time_start = 0, $time_end = 0, $format = "%s", $chop = false) { 

     if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start); 

     list($year_start,$month_start,$day_start) = explode('-',date('Y-m-d',$time_start)); 
     list($year_end,$month_end,$day_end) = explode('-',date('Y-m-d',$time_end)); 

     $years = $year_end - $year_start; 
     $months = $month_end - $month_start; 
     $days = $day_start - $day_end; 
     $weeks = 0; 
     $hours = 0; 
     $mins = 0; 
     $secs = 0; 

     if(mktime(0,0,0,$month_end,$day_end) < mktime(0,0,0,$month_start,$day_start)) { 
      $years -= 1; 
     } 
     if($days < 0) { 
      $months -= 1; 
      $days += 30; // this is an approximation...not sure how to figure this out 
     } 
     if($months < 0) $months += 12; 
     if(strpos($format, '%y')===false) { 
      $months += $years * 12; 
     } 
     if(strpos($format, '%w')!==false) { 
      $weeks = floor($days/7); 
      $days %= 7; 
     } 
     echo date('Y-m-d',$time_start).' to '.date('Y-m-d',$time_end).": {$years}y {$months}m {$weeks}w {$days}d<br/>"; 
} 

मैं गणित सही पाने के लिए नहीं कर पा रहे (यह अधूरा और गलत है)। इसे निष्क्रिय रूप से विभाजित करने से लीप वर्षों और महीनों की अलग-अलग लंबाई के कारण काम नहीं होगा।

तर्क स्ट्रिंग के आधार पर तर्क को भी बदलने की आवश्यकता है। उदाहरण के लिए, 04-फरवरी -2010 को 28-जून -2011 (यूनिक्स टाइमस्टैम्प के रूप में) प्रारूप स्ट्रिंग %y year %m month %d day के साथ आउटपुट 1 year 4 month 24 day आउटपुट होना चाहिए, लेकिन यदि %y year छोड़ा गया है तो उसे महीने में 12 महीने जोड़ना होगा, यानी आउटपुट 16 month 24 day होना चाहिए।

को समय भी संभालना चाहिए ... लेकिन मुझे अभी तक यह नहीं मिला है। इन date_diff समाधान के


कोई नहीं सप्ताह संभाल। और मुझे नहीं पता कि मैं इसे date_diff में कैसे हैक कर सकता हूं, इसलिए यह वास्तव में मेरे लिए एक समाधान नहीं है।

इसके अलावा, $diff->format जो मैंने पूछा है वह नहीं करता है ... "बड़ी इकाइयां" छोड़े जाने पर कुल महीनों और दिनों को देने के लिए। उदाहरण:

>>> $start = new DateTime('04-Feb-2010') 
>>> $end = new DateTime('28-Jun-2011') 
>>> $diff = $start->diff($end) 
>>> $diff->format('%m months, %d days') 
'4 months, 24 days' 

16 months, 24 days होना चाहिए, जैसा कि मैंने पहले बताया था। इससे पहले कि आप इसे पूरी तरह समझ सकें, कृपया मेरे प्रश्न को डुप्ली के रूप में बंद करने के लिए इतनी जल्दी रुकना बंद करें। यदि अन्य प्रश्नों के समाधान को हल करने के लिए tweaked किया जा सकता है, ठीक है, लेकिन कृपया बताएं कि कैसे, क्योंकि मुझे यह नहीं मिलता है।

स्पष्ट है कि,

  • अगर %y छोड़ दिया जाता है, साल महीने
  • अगर %m छोड़ दिया जाता है में उपलब्ध हो जाएगा, महीनों
  • अगर %w छोड़ दिया जाता है, सप्ताह के दिनों में उपलब्ध हो जाएगा
  • %h छोड़ा गया है, घंटों को
  • में घुमाया जाना चाहिएछोड़ दिया जाता है, मिनट सेकंड

"छोटी इकाइयों" छोड़े गए हैं, अगले सबसे बड़ी इकाई गोल या फिदा जहां यह समझ में आता है किया जा सकता है में उपलब्ध हो जाएगा।

+1

आप ऊपर पीएचपी 5.3.0 या है, तो यह आपकी मदद कर सकता है: [DateInterval :: प्रारूप] (http://www.php.net/manual/en/dateinterval.format.php) – drew010

+2

डुप्लिकेट [इस पोस्ट] (http: // stackoverflow।कॉम/प्रश्न/676824/कैसे-गणना-अंतर-बीच-दो-तिथियों-उपयोग-php) – bowlerae

+0

@ ड्रू010: नहीं ... जो सप्ताहों को संभाल नहीं करता है। – mpen

उत्तर

1

मुझे एक स्वीकृत उत्तर की उम्मीद नहीं है, लेकिन यहां सप्ताहों को करने के लिए date_diff कैसे प्राप्त करें।

<?php 

$january = new DateTime('2010-01-01'); 
$february = new DateTime('2011-02-20 3:35:28'); 
$interval = $february->diff($january); 

$parts = $interval->format('%y %m %d %h %i %s %a'); 

$weeks = 0; 
list($years, $months, $days, $hours, $minutes, $seconds, $total_days) = explode(' ', $parts); 

if ($days >= 7) { 
    $weeks = (int)($days/7); 
    $days %= 7; 
} 

echo "$years years, $months months, $weeks weeks, $days days, $hours hours, $minutes minutes $seconds seconds"; 
// 1 years, 1 months, 2 weeks, 5 days, 3 hours, 35 minutes 28 seconds 

शायद इसके साथ आप इसे रोलिंग करने और उपयोगकर्ता को दिए गए प्रारूप को संभालने के लिए अपने फ़ंक्शन में एकीकृत कर सकते हैं।

यदि बड़ी इकाइयां नहीं दी जाती हैं, तो आप सबसे बड़ी इकाई से शुरू कर सकते हैं और उन्हें अगली छोटी इकाई में वापस लागू कर सकते हैं। (यानी 1 साल 1 महीने बिना किसी वर्ष के 12 महीने तक जोड़ना चाहिए)। यदि प्रारूप में "माह" शामिल नहीं है, तो आप इस तथ्य को संभालने के लिए कुल दिनों का उपयोग कर सकते हैं कि महीनों में अलग-अलग दिनों की संख्या है।

+0

अच्छा! मैं इसके साथ खेलने का प्रयास करूंगा और देख सकता हूं कि मैं इसे वही कर सकता हूं जो मैं चाहता हूं। उम्मीद तो दिखती है। – mpen

+0

उम्मीद है कि आप इसके साथ कहीं भी जा सकते हैं। मैं हमेशा "अंतर्निर्मित" दिनांक विधियों पर भरोसा करने की कोशिश करता हूं जैसे कि अब डीएसटी सीमाओं, लीप वर्ष/सेकंड, और प्रत्येक महीने में अलग-अलग दिनों के साथ निपटने के दौरान कई मुद्दों के कारण। – drew010

+0

हाँ .... मैं पहले 'डेटटाइम' के साथ झुका रहा था, लेकिन इसके साथ अभी भी कुछ मुद्दे थे, इसलिए मैंने कहा "इसे पेंच करो! मैं इसे खुद लिखूंगा!"। गोपनीय रूप से यह गलत दृष्टिकोण था। यद्यपि आपका अच्छा और साफ है। मैं इसे स्वीकार करूंगा :) – mpen

1
$absolute = false; //default, returns years, months, days, etc. True would return seconds 
$difference = date_diff($dateTimeStart, $dateTimeEnd, $absolute); 
echo $difference->format("%y Year(s) %m Month(s) ..."); 

मैं यह पहली कोशिश करेगा, अगर यह अपने उद्देश्यों के लिए काम नहीं करता है तो आप प्रत्येक महीने में दिनों की सही संख्या लाने के लिए कैलेंडर कार्यों का उपयोग करने की कोशिश कर सकता है।

मुझे लगता है कि आपको सप्ताहों की गणना के लिए अपने तर्क पर निर्णय लेने की आवश्यकता होगी। निजी तौर पर, मैं $weeks = $difference->d/7; कहूंगा लेकिन एक महीने के एक हिस्से में विलुप्त हफ्तों की गणना करने के लिए कोई सख्ती से सही तरीका नहीं है। कैलेंडर के बारे में सोचें, हम अक्सर पहले, दूसरे, तीसरे सप्ताह के बारे में बात करते हैं, लेकिन जब तक कि रविवार (या सोमवार, या शनिवार, कंपनी, धर्म आदि के आधार पर) शुरू नहीं हुआ, तो वास्तव में हम इन विवरणों में पूर्ण नहीं हैं ।आप पूरी तरह से कह सकते हैं कि महीने की शुरुआत के बाद से 3 रविवार (उदाहरण के लिए) हैं, लेकिन तीन सप्ताह नहीं। 28 वें दिन, चार सप्ताह बीत चुके हैं? अगर बुध बुधवार को शुरू हुआ तो क्या होगा, तो क्या यह पांच है?

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

+0

'date_diff' सप्ताहों को संभाल नहीं करता है। आप का मतलब है कि प्रत्येक महीने में 2 तिथियों के बीच की संख्या की गणना करें और उन्हें या कुछ ऐसा समझाएं? या सिर्फ शुरुआत और अंत महीने ..? – mpen

+1

आप सही हैं, यह नहीं है। मुझे खेद है कि मैंने उस आवश्यकता को नहीं देखा। – Tim

+0

यह ठीक है। उस आवश्यकता को कोड में दफनाया गया था; मुझे इसे और स्पष्ट करना चाहिए था। हालांकि यह "बड़ी इकाइयों" आवश्यकता को संभाल नहीं पाएगा। – mpen

1

मैं इसके लिए DateTime::diff() का प्रयोग करेंगे:

$start = new DateTime('2012-01-01 12:00:00'); 
$end = new DateTime('2012-01-20 06:59:59'); 
$diff = $start->diff($end); 

echo $diff->format('%d days, %h hours, %m minutes, %s seconds'); 

स्वरूपों के बारे में अधिक जानकारी के लिए DateInterval::format() देखें।

+0

यह सप्ताहों को संभाल नहीं करता है। – mpen

1

मुझे लगता है कि मुझे मिल गया:

if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start); 

$start_dt = new DateTime(); 
$end_dt = new DateTime(); 
$start_dt->setTimestamp($time_start); 
$end_dt->setTimestamp($time_end); 
$has_time = preg_match('`%[his]`',$format) > 0; 
if(!$has_time) { 
    $start_dt->setTime(0,0,0); 
    $end_dt->setTime(0,0,0); 
} 
$interval = $end_dt->diff($start_dt); 
$parts = $interval->format('%y %m %d %h %i %s %a'); 
$weeks = 0; 
list($years, $months, $days, $hours, $mins, $secs, $total_days) = explode(' ',$parts); 
if(strpos($format,'%y')===false) { 
    $months += $years * 12; 
} 
if(strpos($format,'%m')===false) { 
    $days = $total_days; 
    if(strpos($format,'%y')!==false) { 
     $start_dt->add(new DateInterval('P'.$years.'Y')); 
     $interval = $end_dt->diff($start_dt); 
     $days = $interval->days; 
    } 
} 
if(strpos($format,'%w')!==false) { 
    $weeks = (int)($days/7); 
    $days %= 7; 
} 
if(strpos($format,'%d')===false) { 
    $hours += $days * 24; 
} 
if(strpos($format,'%h')===false) { 
    $mins += $hours * 60; 
} 
if(strpos($format,'%i')===false) { 
    $secs += $mins * 60; 
} 

(FYI करें, मैं तो बस कुछ बुनियादी str_replacing अंत में कर अपने कस्टम प्रारूप स्ट्रिंग में फेंक)

संपादित करें: अभी भी 1 और परिदृश्य है जो मुझे नहीं पता कि कैसे संभालना है ... जब वर्षों और दिन अनुरोध किए जाते हैं लेकिन महीने नहीं, तो आउटपुट गलत होगा। मैं सोच रहा हूं कि मुझे 365 के साथ कुल दिनों को संशोधित करना चाहिए .... यह एक दुर्लभ परिदृश्य है।

संपादित 2: इसे हल किया गया! हम केवल शुरुआती तारीख में कई सालों को जोड़ देंगे और फिर कुल दिनों का पुनर्मूल्यांकन करेंगे।

+1

अच्छा समाधान मार्क, साफ और आसानी से पढ़ने के लिए आसान है। ऐसा लगता है कि आप लगभग वहां हैं। – drew010

1

यहां एक दिलचस्प समस्या पर मेरा प्रयास है। यह 100% काम नहीं कर रहा है, लेकिन यह बहुत करीब है।

फ़ंक्शन दिनांक अंतर और आवश्यक महीनों की कुल संख्या की गणना करके शुरू होता है। फिर, आरोही क्रम में क्रमबद्ध $tokens सरणी का उपयोग करके, यह उन टोकन के माध्यम से loops और इनपुट $format इनपुट के साथ मिलान करने का प्रयास करता है। यदि $format पाया जाता है, तो उपयुक्त मान महीनों या सेकंड की कुल संख्या से घटाया जाता है।

हालांकि, महीनों या वर्षों के लिए शून्य से अधिक मूल्य होने की संभावना है, लेकिन $format स्ट्रिंग ने उन पैरामीटर में से कोई भी निर्दिष्ट नहीं किया है। यदि ऐसा है, तो सही गणना के साथ आने के लिए फ़ंक्शन उचित दिनों में रोल करता है।

मैंने संक्षेप में इसका परीक्षण किया है, और यह इस धागे के सभी उदाहरणों के लिए काम करता है। यह देखने के लिए कि क्या आप इसे तोड़ सकते हैं, आप codepad पर इसका परीक्षण कर सकते हैं! :) मुझे इस पर सुधार में दिलचस्पी होगी।

<?php 

function calc($start, $end, $format = '%s', $chop = false) 
{ 
    $tokens = array('%y', '%m', '%w', '%d', '%h', '%i', '%s'); 

    if(!is_a($start, 'DateTime') || !is_a($end, 'DateTime')) 
    { 
     return; 
    } 
    $diff = $start->diff($end); 

    $months = ($diff->y * 12) + $diff->m; 
    $secs = ($diff->d * 24 * 3600) + 
      ($diff->h * 3600) + 
      ($diff->i * 60) + 
      ($diff->s); 

    $output = array(); 
    while($token = array_shift($tokens)) 
    { 
     $token_present = !(strpos($format, $token) === false); 

     switch($token) 
     { 
      case '%y': 
       if(($months/12) > 0 && $token_present) 
       { 
        $output[$token] = floor($months/12); 
        $months -= $output[$token] * 12; 
       } 
      break; 
      case '%m': 
       if($months > 0 && $token_present) 
       { 
        $output[$token] = $months; 
        $months = 0; 
       } 
      break; 
      case '%w': 
       // Rollover between (months or years) and seconds 
       if((!isset($output['%y']) || !isset($output['%m'])) && $months > 0) 
       { 
        $days = $diff->format('%a'); 
       // Need a fix for leap year probably. 
       $days -= (isset($output['%y'])) ? ($output['%y'] * 365) : 0; 
       $days -= $diff->d; 
       $secs += ($days * 24 * 60 * 60); 
       } 

       $val = (7 * 24 * 60 * 60); 
       if(($secs/$val) > 0 && $token_present) 
       { 
        $output[$token] = floor($secs/$val); 
        $secs -= $output[$token] * $val; 
       } 
      break; 
      case '%d': 
       $val = (24 * 60 * 60); 
       if(($secs/$val) > 0 && $token_present) 
       { 
        $output[$token] = floor($secs/$val); 
        $secs -= $output[$token] * $val; 
       } 
      break; 
      case '%h': 
       $val = (60 * 60); 
       if(($secs/$val) > 0 && $token_present) 
       { 
        $output[$token] = floor($secs/$val); 
        $secs -= $output[$token] * $val; 
       } 
      break; 
      case '%i': 
       $val = (60); 
       if(($secs/$val) > 0 && $token_present) 
       { 
        $output[$token] = floor($secs/$val); 
        $secs -= $output[$token] * $val; 
       } 
      break; 
      case '%s': 
       if($secs > 0 && $token_present) 
       { 
        $output[$token] = $secs; 
       } 
      break; 
     } 
    } 

    // Filter out blank keys and replace their tokens in the $format string 
    $filtered = $chop ? array_filter($output) : $output; 
    $format = str_replace(array_diff(array_keys($output), array_keys($filtered)), '', $format); 

    return str_replace(array_keys($filtered), array_values($filtered), $format); 
} 

$start = new DateTime('04-Feb-2010'); 
$end = new DateTime('28-Jun-2011'); 
echo calc($start, $end, "%m months %d days\n"); // 16 months 24 days 

$january = new DateTime('2010-01-01'); 
$february = new DateTime('2011-02-20 3:35:28'); 
echo calc($january, $february, '%y years %m months %w weeks %d days %h hours %i minutes %s seconds'); // 1 years 1 months 2 weeks 5 days 3 hours 35 minutes 28 seconds 
+0

मैंने इसे तोड़ दिया: http://codepad.viper-7.com/lc16ez – mpen

+0

@ मार्क मैंने देखा कि बग ने जवाब पोस्ट किया है ... मुझे लगता है कि यह इसे ठीक करता है: http://codepad.viper-7.com/T7qehe – nickb

+0

हाँ .. यह वही परिणाम है जो मुझे मिलता है, हालांकि मुझे लगता है कि आपको अभी भी कुछ गोल करने वाली त्रुटियां मिली हैं, खासकर छलांग के वर्षों के आसपास। मुझे वहां "365" पसंद नहीं है;) मेरा समाधान वर्तमान में इस पृष्ठ बीटीडब्ल्यू के निचले हिस्से में है। – mpen

संबंधित मुद्दे

 संबंधित मुद्दे