วิธีตรวจสอบว่าวันที่อยู่ในช่วงที่กำหนดหรือไม่?


86

หากคุณมี$start_dateและ$end_dateคุณจะตรวจสอบได้อย่างไรว่าวันที่ที่ผู้ใช้กำหนดอยู่ในช่วงนั้นหรือไม่?

เช่น

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

ในขณะที่วันที่เป็นสตริงการแปลงเป็นจำนวนเต็มการประทับเวลาจะช่วยได้หรือไม่


มันจะช่วยได้จากนั้นคุณจะสามารถเข้าถึงฟังก์ชั่นการจัดการวันที่ที่มีอยู่
ChrisF

3
เพียงแค่คำนึงถึงข้อ จำกัด การประทับเวลาเนื่องจากการประทับเวลาของ Unix เริ่มต้นในยุคซึ่งคือวันที่ 1 มกราคม 1970 (1970-01-01) ดังนั้นคุณสามารถมีพฤติกรรมตลก ๆ สำหรับวันทดสอบก่อนปี 1970
Shadi Almosri

1
@Shadi คุณรู้ไหมว่ามีตัวเลขเชิงลบใช่ไหม?
Jeremy Logan

@fiXedd มีปัญหาพื้นฐานเดียวกันแม้ว่าจะอนุญาตการประทับเวลาที่เป็นลบ แต่การประทับเวลา 32 บิตก็ไม่สามารถแสดงวันที่ก่อนปี 1902 ได้
Frank Farmer

คำตอบ:


123

การแปลงเป็นการประทับเวลาเป็นวิธีที่จะดำเนินไปได้ดีโดยใช้strtotimeเช่น

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28';

check_in_range($start_date, $end_date, $date_from_user);


function check_in_range($start_date, $end_date, $date_from_user)
{
  // Convert to timestamp
  $start_ts = strtotime($start_date);
  $end_ts = strtotime($end_date);
  $user_ts = strtotime($date_from_user);

  // Check that user date is between start & end
  return (($user_ts >= $start_ts) && ($user_ts <= $end_ts));
}

1
ใช้งานได้ดี ขอบคุณ.
GeneCode

48

ใช้คลาส DateTime ถ้าคุณมี PHP 5.3+ ใช้งานง่ายขึ้นฟังก์ชันการทำงานที่ดีขึ้น

DateTime รองรับเขตเวลาภายในโดยโซลูชันอื่น ๆ ขึ้นอยู่กับคุณในการจัดการ

<?php    
/**
 * @param DateTime $date Date that is to be checked if it falls between $startDate and $endDate
 * @param DateTime $startDate Date should be after this date to return true
 * @param DateTime $endDate Date should be before this date to return true
 * return bool
 */
function isDateBetweenDates(DateTime $date, DateTime $startDate, DateTime $endDate) {
    return $date > $startDate && $date < $endDate;
}

$fromUser = new DateTime("2012-03-01");
$startDate = new DateTime("2012-02-01 00:00:00");
$endDate = new DateTime("2012-04-30 23:59:59");

echo isDateBetweenDates($fromUser, $startDate, $endDate);

คุณน่าจะเปลี่ยนสิ่งนี้เป็นฟังก์ชันที่รับพารามิเตอร์สามตัวและส่งคืนบูลีน น่าจะง่ายมากในการทดสอบ?
oldwizard

ฉันจะบอกว่าฟังก์ชั่นควรกลับจริงสำหรับอยู่ระหว่าง2012-02-01 2012-02-01 ... 2014-04-30 23:59:59
Salman A

2
ฉันมักจะชอบDateTimeฟังก์ชั่นเวลาร่างที่ PHP นำเสนอนอกกรอบ หากต้องการรวมวันที่เริ่มต้นและวันที่สิ้นสุดไว้ในเช็คนี้ให้เปลี่ยนค่าส่งคืนเป็นreturn $date >= $startDate && $date <= $endDate;
zanderwar

@zanderway คุณกำลังพูดว่า> ค่าเริ่มต้นเป็นการเปรียบเทียบ "วัน" ไม่ใช่การเปรียบเทียบวินาทีใช่หรือไม่ $ startDate มีการระบุวินาทีดังนั้นฉันจึงสงสัยว่า "> =" จำเป็นจริงหรือ?
PJ Brunet

46

ไม่จำเป็นต้องแปลงเป็นการประทับเวลาเพื่อทำการเปรียบเทียบเนื่องจากสตริงได้รับการตรวจสอบความถูกต้องเป็นวันที่ในรูปแบบบัญญัติ "YYYY-MM-DD"

การทดสอบนี้จะใช้ได้ผล:

( ( $date_from_user >= $start_date ) && ( $date_from_user <= $end_date ) )

ให้:

$start_date     = '2009-06-17';
$end_date       = '2009-09-05';
$date_from_user = '2009-08-28';

หมายเหตุ: การเปรียบเทียบสตริงเช่นนี้อนุญาตให้ใช้วันที่ "ไม่ถูกต้อง" เช่น (วันที่ 32 ธันวาคม) "2009-13-32" และสำหรับสตริงที่มีรูปแบบแปลก ๆ "2009/3/3" ดังนั้นการเปรียบเทียบสตริงจะไม่เทียบเท่ากับ การเปรียบเทียบวันที่หรือการประทับเวลา สิ่งนี้ใช้ได้เฉพาะในกรณีที่ค่าวันที่ในสตริงอยู่ในCONSISTENTและCANONICALรูปแบบ

แก้ไขเพื่อเพิ่มบันทึกที่นี่โดยมีรายละเอียดเกี่ยวกับสิ่งที่ชัดเจน

โดยCONSISTENTฉันหมายถึงตัวอย่างเช่นว่าสตริงที่กำลังเปรียบเทียบต้องอยู่ในรูปแบบที่เหมือนกัน: เดือนจะต้องมีอักขระสองตัวเสมอวันนั้นจะต้องมีอักขระสองตัวเสมอและอักขระตัวคั่นจะต้องเป็นเส้นประเสมอ เราไม่สามารถเปรียบเทียบ "สตริง" ที่ไม่ใช่ปีอักขระสี่ตัวเดือนสองอักขระวันอักขระสองตัวได้อย่างน่าเชื่อถือ ถ้าเรามีการผสมผสานของตัวละครตัวหนึ่งและสองตัวละครในเดือนสตริง, ตัวอย่างเช่นเราต้องการได้รับผลที่ไม่คาดคิดเมื่อเราเปรียบเทียบการ'2009-9-30' '2009-10-11'เรามนุษย์ปุถุชนดูที่ "9" ในฐานะที่เป็นน้อยกว่า "10" แต่การเปรียบเทียบสตริงจะเห็นเป็นมากกว่า'2009-9' '2009-1'เราไม่จำเป็นต้องมีอักขระคั่นกลาง เราสามารถเปรียบเทียบสตริงใน'YYYYMMDD'รูปแบบ; หากมีอักขระคั่นจะต้องอยู่ตรงนั้นเสมอและเหมือนกันเสมอ

โดยCANONICALฉันหมายถึงรูปแบบที่จะทำให้เกิดสตริงที่จะเรียงตามลำดับวันที่ นั่นคือสตริงจะมีการแสดง "ปี" ก่อนจากนั้น "เดือน" ตามด้วย "วัน" เราไม่สามารถเปรียบเทียบสตริงใน'MM-DD-YYYY'รูปแบบได้อย่างน่าเชื่อถือเพราะไม่ใช่รูปแบบบัญญัติ การเปรียบเทียบสตริงจะเปรียบเทียบMM(เดือน) ก่อนที่จะเปรียบเทียบYYYY(ปี) เนื่องจากการเปรียบเทียบสตริงทำงานจากซ้ายไปขวา) ประโยชน์อย่างมากของรูปแบบสตริง "YYYY-MM-DD" คือเป็นแบบบัญญัติ วันที่ที่แสดงในรูปแบบนี้สามารถเปรียบเทียบเป็นสตริงได้อย่างน่าเชื่อถือ

[ADDENDUM]

หากคุณใช้การแปลงการประทับเวลา php โปรดระวังข้อ จำกัด

ในบางแพลตฟอร์ม php ไม่สนับสนุนค่าการประทับเวลาก่อนปี 1970-01-01 และ / หรือใหม่กว่า 2038-01-19 (นั่นเป็นลักษณะของจำนวนเต็ม 32 บิตของ unix timestamp) รุ่นที่ใหม่กว่า pf php (5.3?)

เขตเวลาอาจเป็นปัญหาได้เช่นกันหากคุณไม่ระมัดระวังที่จะใช้เขตเวลาเดียวกันเมื่อแปลงจากสตริงเป็นการประทับเวลาและจากการประทับเวลากลับเป็นสตริง

HTH


1
แม้ว่าจะไม่มีการแคสต์ แต่คุณอาจประสบปัญหาได้หากค่าของ $ date_from_user หรือ $ start_date หรือ $ end_date ไม่ใช่วันที่ .. เช่น $ end_date = 'Balh Blah' .. จะทำงานไม่ถูกต้อง
Mike Dinescu

@ spencer7593 คุณมีข้อมูลอ้างอิงสำหรับพฤติกรรมนี้หรือไม่?
Ionuț G. Stan

2
คุณสามารถใช้ checkdate () เพื่อตรวจสอบได้
meleyal

ทำงานตามเวลาหรือไม่? ฉันหมายความว่าฉันมีเวลาสองครั้งในรูปแบบ HH: MM: SS และฉันต้องการทราบว่าเวลาใดก็ตามที่อยู่ระหว่างสองสิ่งนี้
Andy Ibanez

1
@ เซอร์จิโอ: ใช่การเปรียบเทียบสตริงเดียวกันใช้ได้กับค่าเวลาตราบเท่าที่สตริงอยู่ในรูปแบบมาตรฐานมาตรฐาน (เช่นนาฬิกา 24 ชั่วโมงเที่ยงคืนแสดงเป็น '00: 00: 00 'วินาทีสุดท้ายก่อนเที่ยงคืนแสดงเป็น' 23:59:59 'เพื่อรับประกันว่าการเปรียบเทียบสตริงจะ "ใช้ได้ผล" คุณต้องรับประกันว่าการแสดงสตริงของค่าเวลาอยู่ในรูปแบบที่รับประกัน
spencer7593

4
$startDatedt = strtotime($start_date)
$endDatedt = strtotime($end_date)
$usrDatedt = strtotime($date_from_user)

if( $usrDatedt >= $startDatedt && $usrDatedt <= $endDatedt)
{
   //..falls within range
}

ซึ่งจะไม่รวมการแข่งขันที่ตรงกับวันที่เริ่มต้นหรือวันที่สิ้นสุด
TheTXI

OP ไม่ขอรวมการแข่งขัน
Jeremy Logan

3

แปลงวันที่ทั้งสองเป็นเวลาประทับจากนั้นทำ

pseudocode:

if date_from_user > start_date && date_from_user < end_date
    return true

คุณอาจต้องการแก้ไขเพื่อให้คุณรวม start_date และ end_date ไว้ในช่วงด้วย ตอนนี้ถ้า date_from_user เท่ากันก็จะไม่ถูกนับ
TheTXI

OP ไม่ได้ระบุช่วงรวมหรือช่วงพิเศษดังนั้นฉันจะปล่อยให้พวกเขาเลือกกลยุทธ์ที่จะใช้
Glen

3

ในรูปแบบที่คุณระบุสมมติว่าผู้ใช้ฉลาดพอที่จะระบุวันที่ที่ถูกต้องให้คุณคุณไม่จำเป็นต้องแปลงวันที่ก่อนคุณสามารถเปรียบเทียบเป็นสตริง


1
เมื่อถึงจุดนี้ในรหัสวันที่ได้รับการตรวจสอบแล้ว
meleyal

3
$start_date="17/02/2012";
$end_date="21/02/2012";
$date_from_user="19/02/2012";

function geraTimestamp($data)
{
    $partes = explode('/', $data); 
    return mktime(0, 0, 0, $partes[1], $partes[0], $partes[2]);
}


$startDatedt = geraTimestamp($start_date); 
$endDatedt = geraTimestamp($end_date);
$usrDatedt = geraTimestamp($date_from_user);

if (($usrDatedt >= $startDatedt) && ($usrDatedt <= $endDatedt))
{ 
    echo "Dentro";
}    
else
{
    echo "Fora";
}

2

แปลงเป็นวันที่หรือจำนวนเต็มเวลาจากนั้นตรวจสอบ $ date_from_user คือ <= $ end_date และ> = $ start_date


3
คุณช่วยชี้แจง 'แปลงเป็นวันที่' ได้หรือไม่? คุณจะทำอย่างไร? ฉันคิดว่า PHP ไม่มีประเภทวันที่?
meleyal

2

คุณสามารถลองสิ่งนี้:

//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");

//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);

1
หมายเหตุเวอร์ชัน: iterator_to_array()พร้อมใช้งานตั้งแต่ PHP 5.1
Raptor

0

ฉันพบว่าวิธีนี้ง่ายที่สุด:

$start_date = '2009-06-17';
$end_date = '2009-09-05';
$date_from_user = '2009-08-28';

$start_date = date_create($start_date);
$date_from_user = date_create($date_from_user);
$end_date = date_create($end_date);

$interval1 = date_diff($start_date, $date_from_user);
$interval2 = date_diff($end_date, $date_from_user);

if($interval1->invert == 0){
  if($interval2->invert == 1){

     // if it lies between start date and end date execute this code

  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.