Làm thế nào để kiểm tra xem một ngày có nằm trong một phạm vi nhất định không?


86

Nếu bạn có $start_date$end_date, làm thế nào bạn có thể kiểm tra xem ngày do người dùng đưa ra có nằm trong phạm vi đó không?

ví dụ

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

Tại thời điểm hiện tại, ngày tháng là chuỗi, việc chuyển đổi chúng thành số nguyên dấu thời gian có hữu ích không?


Nó sẽ hữu ích, sau đó bạn có quyền truy cập vào bất kỳ chức năng thao tác ngày nào ở đó.
ChrisF

3
Chỉ cần Thận trọng với các giới hạn timestamp như timestamps Unix bắt đầu từ thời đại, đó là ngày 01 tháng 1 năm 1970 (1970/01/01), do đó bạn có thể có hành vi hài hước cho những ngày thử nghiệm trước năm 1970.
Shadi Almosri

1
@Shadi Bạn biết có những thứ như là những con số TIÊU CỰC, phải không?
Jeremy Logan

@fiXedd cũng tồn tại vấn đề cơ bản tương tự - ngay cả khi cho phép dấu thời gian âm, dấu thời gian 32 bit không thể đại diện cho các ngày trước năm 1902.
Frank Farmer

Câu trả lời:


122

Chuyển đổi chúng thành dấu thời gian là một cách ổn, sử dụng strtotime , ví dụ:

$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));
}

Hoạt động tuyệt vời. Cảm ơn.
GeneCode

47

Sử dụng lớp DateTime nếu bạn có PHP 5.3+. Dễ sử dụng hơn, chức năng tốt hơn.

DateTime hỗ trợ nội bộ múi giờ, với các giải pháp khác là tùy thuộc vào bạn để xử lý điều đó.

<?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);

Bạn có thể sẽ chuyển nó thành một hàm có ba tham số và trả về một boolean. Nên rất dễ kiểm tra?
oldwizard

Tôi sẽ nói rằng hàm nên trả về true cho 2012-02-01là giữa 2012-02-01 ... 2014-04-30 23:59:59.
Salman A

2
Tôi luôn ủng hộ DateTimecác chức năng thời gian sơ sài mà PHP cung cấp sẵn. Để đưa bắt đầu và ngày kết thúc trong vòng kiểm tra này rất đơn giản thay đổi giá trị trở lạireturn $date >= $startDate && $date <= $endDate;
zanderwar

@zanderway bạn đang nói> mặc định là so sánh "ngày" chứ không phải so sánh giây? $ startDate đã chỉ định giây, vì vậy tôi đang tự hỏi liệu "> =" có thực sự cần thiết không?
PJ Brunet

46

Không cần thiết phải chuyển đổi sang dấu thời gian để thực hiện so sánh, vì các chuỗi được xác thực dưới dạng ngày ở định dạng chuẩn 'YYYY-MM-DD'.

Thử nghiệm này sẽ hoạt động:

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

được:

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

LƯU Ý: So sánh các chuỗi như thế này không cho phép các ngày "không hợp lệ", ví dụ: (ngày 32 tháng 12) '2009-13-32' và cho các chuỗi có định dạng kỳ lạ '2009/3/3', sao cho so sánh chuỗi sẽ KHÔNG tương đương với so sánh ngày tháng hoặc dấu thời gian. Đây chỉ hoạt động nếu giá trị ngày trong chuỗi đang ở trong một QUÁNCanonical định dạng.

CHỈNH SỬA để thêm ghi chú ở đây, giải thích rõ ràng hơn.

Bằng sự ĐỒNG Ý , tôi có nghĩa là ví dụ: các chuỗi được so sánh phải có định dạng giống hệt nhau: tháng phải luôn có hai ký tự, ngày phải luôn có hai ký tự và ký tự phân tách phải luôn là dấu gạch ngang. Chúng tôi không thể so sánh một cách đáng tin cậy các "chuỗi" không phải là năm bốn ký tự, tháng hai ký tự, ngày hai ký tự. Ví dụ: nếu chúng ta có một kết hợp của một ký tự và hai tháng ký tự trong chuỗi, chúng ta sẽ nhận được kết quả không mong đợi khi chúng ta so sánh, '2009-9-30'với '2009-10-11'. Con người chúng ta thấy "9" nhỏ hơn "10", nhưng so sánh chuỗi sẽ thấy '2009-9'lớn hơn '2009-1'. Chúng ta không nhất thiết phải có ký tự phân cách dấu gạch ngang; chúng tôi có thể so sánh một cách đáng tin cậy các chuỗi trong'YYYYMMDD'định dạng; nếu có một ký tự phân cách, nó phải luôn ở đó và luôn giống nhau.

Theo CANONICAL , ý tôi là một định dạng dẫn đến các chuỗi sẽ được sắp xếp theo thứ tự ngày. Tức là, chuỗi sẽ có đại diện là "năm" trước, sau đó là "tháng", sau đó là "ngày". Chúng tôi không thể so sánh đáng tin cậy các chuỗi theo 'MM-DD-YYYY'định dạng, vì đó không phải là định dạng chuẩn. So sánh chuỗi sẽ so sánh MM(tháng) trước khi so sánh YYYY(năm) vì so sánh chuỗi hoạt động từ trái sang phải.) Một lợi ích lớn của định dạng chuỗi 'YYYY-MM-DD' là nó là chuẩn; Các ngày được biểu thị ở định dạng này có thể được so sánh một cách đáng tin cậy dưới dạng chuỗi.

[ADDENDUM]

Nếu bạn thực hiện chuyển đổi dấu thời gian php, hãy lưu ý những hạn chế.

Trên một số nền tảng, php không hỗ trợ các giá trị dấu thời gian sớm hơn 1970-01-01 và / hoặc muộn hơn 2038-01-19. (Đó là bản chất của số nguyên 32-bit dấu thời gian unix.) Các phiên bản sau pf php (5.3?) Được cho là giải quyết vấn đề đó.

Múi giờ cũng có thể là một vấn đề, nếu bạn không cẩn thận sử dụng cùng một múi giờ khi chuyển đổi từ chuỗi sang dấu thời gian và từ dấu thời gian trở lại chuỗi.

HTH


1
Điều này là thú vị.
Ionuț G. Stan

1
Mặc dù không đúc bạn có thể chạy vào vấn đề nếu các giá trị của $ date_from_user, hoặc $ start_date, end_date hoặc $ không phải là ngày .. tức là $ end_date = 'Balh Blah' .. chắc chắn sẽ không hoạt động chính xác
Mike Dinescu

@ spencer7593, bạn có một số tài liệu tham khảo cho hành vi này?
Ionuț G. Stan

2
Bạn có thể sử dụng checkdate () để xác nhận
meleyal

1
@Sergio: vâng, so sánh chuỗi tương tự hoạt động đối với các giá trị thời gian, miễn là các chuỗi có định dạng chính tắc chuẩn (tức là đồng hồ 24 giờ, nửa đêm được biểu thị là '00: 00: 00 ', giây cuối cùng trước nửa đêm được biểu thị là' . 23:59:59' để được đảm bảo rằng sự so sánh chuỗi sẽ 'làm việc', bạn cần phải đảm bảo rằng các cơ quan đại diện của chuỗi giá trị thời gian đang ở trong một định dạng được bảo đảm.
spencer7593

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

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

Điều đó sẽ không bao gồm bất kỳ kết quả phù hợp chính xác nào với ngày bắt đầu hoặc ngày kết thúc
TheTXI

OP không yêu cầu các trận đấu bao gồm.
Jeremy Logan

3

Chuyển đổi cả hai ngày thành dấu thời gian rồi thực hiện

mã giả:

if date_from_user > start_date && date_from_user < end_date
    return true

Bạn có thể muốn chỉnh sửa nó để bạn cũng bao gồm start_date và end_date trong phạm vi. Ngay bây giờ nếu date_from_user bằng một trong hai, nó sẽ không được tính.
TheTXI

OP không chỉ định phạm vi bao gồm hoặc độc quyền, vì vậy tôi sẽ để họ lựa chọn chiến lược sử dụng
Glen

3

Ở định dạng bạn đã cung cấp, giả sử người dùng đủ thông minh để cung cấp cho bạn các ngày hợp lệ, trước tiên bạn không cần chuyển đổi thành ngày, bạn có thể so sánh chúng dưới dạng chuỗi.


1
Đến thời điểm này trong mã, ngày tháng đã được xác thực
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

Chuyển đổi chúng thành ngày tháng hoặc số nguyên dấu thời gian và sau đó chỉ cần kiểm tra $ date_from_user là <= $ end_date và> = $ start_date


3
Bạn có thể làm rõ 'chuyển đổi chúng thành ngày tháng'? Bạn làm điều đó như thế nào? Tôi nghĩ PHP không có loại ngày?
meleyal

2

Bạn có thể thử điều này:

//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
ghi chú phiên bản: iterator_to_array()có sẵn kể từ PHP 5.1
Raptor

0

Tôi thấy phương pháp này dễ nhất:

$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

  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.