Please bear with me as I try to explain my predicament. I need to somehow get the difference between two dates by reversing a function I have to add months and years?
Problem
The date add function provided with PHP >= 5.3 does not add dates in the manner I require.
Example: +3 Months to 30Nov = 2Mar
Solution
I use the function below (code ref 2) to produce the results I need.
Example: +3 Months to 30Nov = 28Feb
However when using the below (code ref 1) to calculate the difference it does so based on the addition function provide with PHP >= 5.3 in that I get 2 instead of 3 months difference between 30Nov and 28Feb.
If anyone could help come up with an accurate date diff based on the code ref 2 logic I, and I'm sure others in the same boat would be very grateful.
<< CODE REF 1 >>
<?php
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 2
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 3
?>
<< CODE REF 2 >>
<?php
$datetime = new DateTime('2000-11-30');
$y = 0;
$m = 3;
$d = 0;
if ($d>0){
$datetime->add(new DateInterval('P'.$d.'D'));
}
if ($d<0){
$datetime->sub(new DateInterval('P'.$d.'D'));
}
if ($y!=0){
$init=clone $datetime;
$modifier=$y.' years';
$datetime->modify($modifier);
while ($datetime->format('m')!=$init->format('m')){
$datetime->modify('-1 day');
}
}
if ($m!=0){
$init=clone $datetime;
$modifier=$m.' months';
$back_modifier =-$m.' months';
$datetime->modify($modifier);
$back_to_init= clone $datetime;
$back_to_init->modify($back_modifier);
while ($init->format('m')!=$back_to_init->format('m')){
$datetime->modify('-1 day');
$back_to_init= clone $datetime;
$back_to_init->modify($back_modifier);
}
}
echo $datetime->format('Y-m-d'); // 2001-02-28
?>
SOLUTION FOUND
By changing the way we use the original function we instead find out the number of years and months as desired, many thanks to all the helpful suggestions. The reason for y=1 and m=4 is because the year starts at one and the month starts at one, otherwise it would be 0 and 3 as originally requested if starting at zero.
<?php
function date_yr_mth($date1='2000-11-30',$date2='2001-02-28'){
$y1 = date("Y", strtotime($date1));
$m1 = date("n", strtotime($date1));
$d1 = date("j", strtotime($date1));
$y2 = date("Y", strtotime($date2));
$m2 = date("n", strtotime($date2));
$d2 = date("j", strtotime($date2));
$t2 = date("t", strtotime($date2));
$cm_diff = $m2-$m1;
$cy_diff = $y2-$y1;
if ($d2>=$d1){
$add_mth1 = 1;
}else{
$add_mth1 = 0;
}
$add_mth2 = 12*$cy_diff+$cm_diff;
if ($d2==$t2 && $d2<$d1){
$add_mth3 = 1;
}else{
$add_mth3 = 0;
}
$total_mths = $add_mth1+$add_mth2+$add_mth3;
$arr = array();
$arr['y'] = floor(($total_mths-1)/12)+1;
$arr['m'] = $total_mths-($arr['y']-1)*12;
print_r($arr);
// [y] => 1
// [m] => 4
}
?>
The way to approach this is to extend DateTime and overide the add() and sub() methods to behave as you want them to. That, after all is one of the advantages of OOP.
The way to get your desired behaviours is to set the day of the month to the 1st before doing calling add() or sub() and then restoring the original or highest possible day afterwards.
My first attempt is below, not thoroughly tested, but adding 1 month to 31st Jan gave 28th Feb, which, I believe is your desired behaviour:-
class MyDateTime extends \DateTime
{
public function add($interval)
{
$oldDay = (int)$this->format('d');
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
parent::add($interval);
$maxDay = (int)$this->format('t');
if($oldDay > $maxDay){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
} else {
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
}
return $this;
}
public function sub($interval)
{
$oldDay = (int)$this->format('d');
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
parent::sub($interval);
$maxDay = (int)$this->format('t');
if($oldDay > $maxDay){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
} else {
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
}
return $this;
}
public function diff($dateTime2, $absolute = false)
{
if((int)$this->format('t') > (int)$dateTime2->format('t')){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), (int)$dateTime2->format('t'));
}
if((int)$this->format('t') < (int)$dateTime2->format('t')){
$dateTime2->setDate((int)$dateTime2->format('Y'), (int)$dateTime2->format('m'), (int)$this->format('t'));
}
return parent::diff($dateTime2, $absolute);
}
}
Here is a working example using your exampe dates
Here is an example using the diff() method as you can see it gives a 3 month difference. You can also see that adding the resulting DateInterval to the original date results in the second date.
The sub() method may require a bit more thought, but I don't have time just now. I'll take a more thorough look if I get a few spare minutes later.
This way you would get the absolute difference between months without taking in account the day.
<?php
function getMonthDiff($firstMonth, $secondMonth)
{
$firstMonth = $firstMonth->format("Y") * 12 + $firstMonth->format("m");
$secondMonth = $secondMonth->format("Y") * 12 + $secondMonth->format("m");
return abs($firstMonth - $secondMonth);
}
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
echo getMonthDiff($datetime1, $datetime2);
echo "<br />";
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
echo getMonthDiff($datetime1, $datetime2);
Related
$start = '22:00:00';
$end = '08:00:00';
$now = Carbon::now('UTC');
How can I check if the time of $now is within the timerange?
There are several ways to achieve that by using Carbon. One of the easiest ways is using createFromTimeString and between methods:
$now = Carbon::now();
$start = Carbon::createFromTimeString('22:00');
$end = Carbon::createFromTimeString('08:00')->addDay();
if ($now->between($start, $end)) {
// ¯\_(ツ)_/¯
}
Try this:
$time = Carbon::now();
$morning = Carbon::create($time->year, $time->month, $time->day, 8, 0, 0); //set time to 08:00
$evening = Carbon::create($time->year, $time->month, $time->day, 18, 0, 0); //set time to 18:00
if($time->between($morning, $evening, true)) {
//current time is between morning and evening
} else {
//current time is earlier than morning or later than evening
}
The true in $time->between($morning, $evening, true) checks whether the $time is between and including $morning and $evening. If you write false instead it checks just if it is between the two times but not including.
Actually, you could leave true away because it is set by default and not needed.
Check here for more information on how to compare dates and times with Carbon.
$start = '22:00:00';
$end = '08:00:00';
$now = Carbon::now('UTC');
$time = $now->format('H:i:s');
if ($time >= $start && $time <= $end) {
...
}
Should do it, but doesn't take date into consideration
You can reverse check algorithm.
<?php
$pushChannel = "general";
$now = Carbon::now();
$start = Carbon::createFromTime(8, 0);
$end = Carbon::createFromTime(22, 0);
if (!$now->between($start, $end)) {
$pushChannel = "silent";
$restrictStartTime = Carbon::createFromTime(22, 0, 0); //carbon inbuild function which will create todays date with the given time
$restrictEndTime = Carbon::createFromTime(8, 0, 0)->addDays(1); //this will create tomorrows date with the given time
$now = Carbon::now();
if($now->gt($restrictStartTime) && $now->lt($restrictEndTime)) {
.....
}
Please Try below code,
$start = '22:00:00';
$end = '08:00:00';
$now = Carbon::now('UTC');
$nowTime = $now->hour.':'.$now->minute.':'.$now->second;
if(strtotime($nowTime) > strtotime($start) && strtotime($nowTime) < strtotime($end) ) {
echo 'YES';
} else {
echo 'NO';
}
What Chris is trying to point out is if the endtime crosses over midnight then you must account for that.
This is not the cleanest way to do it but here is a method that seems to work.
private function isNowBetweenTimes($timezone, $startDateTime, $endDateTime) {
$curTimeLocal = Carbon::now($timezone);
$startTime = $curTimeLocal->copy();
$startTime->hour = $startDateTime->hour;
$startTime->minute = $startDateTime->minute;
$endTime = $curTimeLocal->copy();
$endTime->hour = $endDateTime->hour;
$endTime->minute = $endDateTime->minute;
if ($endTime->lessThan($startTime))
$endTime->addDay();
return ($curTimeLocal->isBetween($startTime, $endTime));
}
This example only cares about the hour and minutes and not the seconds but you can easily copy that as well. The key to this is comparing start and end time before comparing them to the current time and add a day to end time if end time is less than start time.
For complete solution which supports all start and end time range you can use bitwise XOR.
/*
* must using hours in 24 hours format e.g. set 0 for 12 pm, 6 for 6 am and 13 for 1 pm
*/
private $startTime = '0';
private $endTime = '6';
$currentHour = \Carbon\Carbon::now()->hour;
$start = $this->startTime > $this->endTime ? !($this->startTime <= $currentHour) : $this->startTime <= $currentHour;
$end = $currentHour < $this->endTime;
if (!($start ^ $end)) {
//Do stuff here if you want exactly between start and end time
}
an updated version of #AliN11's answer taking into account ranges accross two days or in the same day
$now = now();
$start = Carbon::createFromTimeString('22:00');
$end = Carbon::createFromTimeString('08:00');
if ($start > $end) {
$end = $end->addDay();
}
if ($now->between($start, $end)||$now->addDay()->between($start, $end)) {
//add statements
}
<?php
$now = date("H");
if ($now < "20") {
echo "Have a good day!";
}
Try this :
$start = 22; //Eg. start hour
$end = 08; //Eg. end hour
$now = Carbon::now('UTC');
if( $start < $now->hour && $now->hour < $end){
// Do something
}
#AliN11's (currently top) answer is good, but doesn't work as one would immediately expect, after midnight it just breaks, as raised in the comments by #Sasha
The solution is to reverse the logic, and check if the time is not between the inverse hours.
Here is an alternative that works as one would expect:
$now = Carbon::now();
$start = Carbon::createFromTimeString('08:00');
$end = Carbon::createFromTimeString('22:00');
if (! $now->between($start, $end)) {
// We're all good
}
Yes, the midnight plays a vital role in time duration. We can find now() being the given time range as follows:
$now = Carbon::now();
$start = Carbon::createFromTime('22', '00');
$end = Carbon::createFromTime('08', '00');
if ($start->gt($end)) {
if ($now->gte($start)) {
$end->addDay();
} elseif ($now->lte($end)) {
$start->subDay();
} else {
return false;
}
}
return $now->between($start, $end);
I have a date
2016-09-16
How can I check that if that date is less than 3 days old?
I'm being really stupid and the frustration is making me not figure it out
Here's my code
public function isNew()
{
return strtotime($this->created_at) > time() && strtotime($this->created_at) < strtotime('+3 days',time());
}
Should be easy to use DateTime and DateInterval to handle this.
$date = new DateTime('2016-09-16');
$diff = (new DateTime)->diff($date)->days;
return $diff < 3;
Using PHP's DateTime and DateInterval Classes would do you much good. Here's how:
<?php
function isNewerThan3Days($date) {
$today = new DateTime();
$date = new DateTime($date);
$diff = $today->diff($date);
$diffD = $diff->days;
if($diffD>=3){
return false;
}
return true;
}
var_dump(isNewerThan3Days("2016-09-14")); //<== YIELDS:: boolean true
Use diff(). It will return a DateInterval object. Within that object will be a days property (days) that you can access.
// compare two distinct dates:
$datetime1 = new DateTime('2016-09-16');
$datetime2 = new DateTime('2016-09-12');
$interval = $datetime1->diff($datetime2);
$daysOld = $interval->days;
// int(4)
// or compare today vs your date...
$datetime1 = new DateTime('2016-09-16');
$now = new DateTime();
$interval = $now->diff($datetime1);
$daysOld = $interval->days;
// int(0)
// then determine if it's at least 3 days old:
$is3daysOld = ($daysOld >= 3 ? true : false);
http://php.net/manual/en/datetime.diff.php
This should do it for you.
$date = new DateTime('2015-09-16');
$now = new DateTime();
$interval = $date->diff($now);
$difference = $interval->format('%a');
if($difference < 3) {
// $date is fewer than 3 days ago
}
In your isNew() method:
public function isNew() {
$created_at = new DateTime($this->created_at);
$now = new DateTime();
$interval = $created_at->diff($now);
$difference = $interval->format('%a');
if($difference < 3) {
return true;
}
return false;
}
return $this->created_at->diffInDays() < 3;
Without parameter diffInDays() will return the number of complete days between created_at and now.
Why don't you use Carbon ?
You can easily do that and many more in carbon like so :
$dt = Carbon::createFromDate(2011, 8, 1);
echo $dt->subDays(5)->diffForHumans(); // 5 days before
I want to count the total day difference from user input
For example when the user inputs
start_date = 2012-09-06 and end-date = 2012-09-11
For now I am using this code to find the diffeence
$count = abs(strtotime($start_date) - strtotime($end_date));
$day = $count+86400;
$total = floor($day/(60*60*24));
The result of total will be 6. But the problem is that I dont want to include the days at weekend (Saturday and Sunday)
2012-09-06
2012-09-07
2012-09-08 Saturday
2012-09-09 Sunday
2012-09-10
2012-09-11
So the result will be 4
----update---
I have a table that contains date,the table name is holiday date
for example the table contains 2012-09-07
So, the total day will be 3, because it didn't count the holiday date
how do I do that to equate the date from input to date in table?
Very easy with my favourites: DateTime, DateInterval and DatePeriod
$start = new DateTime('2012-09-06');
$end = new DateTime('2012-09-11');
// otherwise the end date is excluded (bug?)
$end->modify('+1 day');
$interval = $end->diff($start);
// total days
$days = $interval->days;
// create an iterateable period of date (P1D equates to 1 day)
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
// best stored as array, so you can add more than one
$holidays = array('2012-09-07');
foreach($period as $dt) {
$curr = $dt->format('D');
// substract if Saturday or Sunday
if ($curr == 'Sat' || $curr == 'Sun') {
$days--;
}
// (optional) for the updated question
elseif (in_array($dt->format('Y-m-d'), $holidays)) {
$days--;
}
}
echo $days; // 4
In my case I needed the same answer as OP, but wanted something a little smaller. #Bojan's answer worked, but I didn't like that it doesn't work with DateTime objects, required using timestamps, and was comparing against strings instead of the actual objects themselves (which feels hacky)... Here's a revised version of his answer.
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
{
$days = 0;
while($startDate->diff($endDate)->days > 0) {
$days += $startDate->format('N') < 6 ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
}
return $days;
}
Per #xzdead's comment if you'd like this to be inclusive of the start and end date:
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
{
$isWeekday = function (\DateTime $date) {
return $date->format('N') < 6;
};
$days = $isWeekday($endDate) ? 1 : 0;
while($startDate->diff($endDate)->days > 0) {
$days += $isWeekday($startDate) ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
}
return $days;
}
The easiest and fastest way to get difference without weekends is by using Carbon library.
Here's an example how to use it:
<?php
$from = Carbon\Carbon::parse('2016-05-21 22:00:00');
$to = Carbon\Carbon::parse('2016-05-21 22:00:00');
echo $to->diffInWeekdays($from);
use DateTime:
$datetime1 = new DateTime('2012-09-06');
$datetime2 = new DateTime('2012-09-11');
$interval = $datetime1->diff($datetime2);
$woweekends = 0;
for($i=0; $i<=$interval->d; $i++){
$datetime1->modify('+1 day');
$weekday = $datetime1->format('w');
if($weekday !== "0" && $weekday !== "6"){ // 0 for Sunday and 6 for Saturday
$woweekends++;
}
}
echo $woweekends." days without weekend";
// 4 days without weekends
date('N') gets the day of the week (1 - Monday, 7 - Sunday)
$start = strtotime('2012-08-06');
$end = strtotime('2012-09-06');
$count = 0;
while(date('Y-m-d', $start) < date('Y-m-d', $end)){
$count += date('N', $start) < 6 ? 1 : 0;
$start = strtotime("+1 day", $start);
}
echo $count;
Here is the improved version of #dan-lee function:
function get_total_days($start, $end, $holidays = [], $weekends = ['Sat', 'Sun']){
$start = new \DateTime($start);
$end = new \DateTime($end);
$end->modify('+1 day');
$total_days = $end->diff($start)->days;
$period = new \DatePeriod($start, new \DateInterval('P1D'), $end);
foreach($period as $dt) {
if (in_array($dt->format('D'), $weekends) || in_array($dt->format('Y-m-d'), $holidays)){
$total_days--;
}
}
return $total_days;
}
To use it:
$start = '2021-06-12';
$end = '2021-06-17';
$holidays = ['2021-06-15'];
echo get_total_days($start, $end, $holidays); // Result: 3
Have a look at this post:
Calculate business days
(In your case, you could leave out the 'holidays' part since you're after working/business days only)
<?php
//The function returns the no. of business days between two dates
function getWorkingDays($startDate,$endDate){
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
}
else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
return $workingDays;
}
// This will return 4
echo getWorkingDays("2012-09-06","2012-09-11");
?>
If you don't need full days but accurate seconds instead try this code. This accepts unix timestamps as an input.
function timeDifferenceWithoutWeekends($from, $to) {
$start = new DateTime("#".$from);
$current = clone $start;
$end = new DateTime("#".$to);
$sum = 0;
while ($current<$end) {
$endSlice = clone $current;
$endSlice->setTime(0,0,0);
$endSlice->modify('+1 day');
if ($endSlice>$end) {
$endSlice= clone $end;
}
$seconds = $endSlice->getTimestamp()-$current->getTimestamp();
$currentDay = $current->format("D");
if ($currentDay != 'Sat' && $currentDay != 'Sun') {
$sum+=$seconds;
}
$current = $endSlice;
}
return $sum;
}
/**
* Getting the Weekdays count[ Excludes : Weekends]
*
* #param type $fromDateTimestamp
* #param type $toDateTimestamp
* #return int
*/
public static function getWeekDaysCount($fromDateTimestamp = null, $toDateTimestamp=null) {
$startDateString = date('Y-m-d', $fromDateTimestamp);
$timestampTomorrow = strtotime('+1 day', $toDateTimestamp);
$endDateString = date("Y-m-d", $timestampTomorrow);
$objStartDate = new \DateTime($startDateString); //intialize start date
$objEndDate = new \DateTime($endDateString); //initialize end date
$interval = new \DateInterval('P1D'); // set the interval as 1 day
$dateRange = new \DatePeriod($objStartDate, $interval, $objEndDate);
$count = 0;
foreach ($dateRange as $eachDate) {
if ( $eachDate->format("w") != 6
&& $eachDate->format("w") != 0
) {
++$count;
}
}
return $count;
}
Kindly have a look at this precise php function returning days count with weekends excluded.
function Count_Days_Without_Weekends($start, $end){
$days_diff = floor(((abs(strtotime($end) - strtotime($start))) / (60*60*24)));
$run_days=0;
for($i=0; $i<=$days_diff; $i++){
$newdays = $i-$days_diff;
$futuredate = strtotime("$newdays days");
$mydate = date("F d, Y", $futuredate);
$today = date("D", strtotime($mydate));
if(($today != "Sat") && ($today != "Sun")){
$run_days++;
}
}
return $run_days;
}
Try it out, it really works..
A very simple solution using Carbon\Caborn
here is the repository file which is called from a controller store function
<?php
namespace App\Repositories\Leave;
use App\Models\Holiday;
use App\Models\LeaveApplication;
use App\Repositories\BaseRepository;
use Carbon\Carbon;
class LeaveApplicationRepository extends BaseRepository
{
protected $holiday;
public function __construct(LeaveApplication $model, Holiday $holiday)
{
parent::__construct($model);
$this->holiday = $holiday;
}
/**
* Get all authenticated user leave
*/
public function getUserLeave($id)
{
return $this->model->where('employee_id',$id)->with(['leave_type','approver'])->get();
}
/**
* #param array $request
*/
public function create($request)
{
$request['total_days'] = $this->getTotalDays($request['start_date'],$request['end_date']);
return $this->model->create($request->only('send_to','leave_type_id','start_date','end_date','desc','total_days'));
}
/**
* Get total leave days
*/
private function getTotalDays($startDate, $endDate)
{
$holidays = $this->getHolidays(); //Get all public holidays
$leaveDays = 0; //Declare values which hold leave days
//Format the dates
$startDate = Carbon::createFromFormat('Y-m-d',$startDate);
$endEnd = Carbon::createFromFormat('Y-m-d',$endDate);
//Check user dates
for($date = $startDate; $date <= $endEnd; $date->modify('+1 day')) {
if (!$date->isWeekend() && !in_array($date,$holidays)) {
$leaveDays++; //Increment days if not weekend and public holidays
}
}
return $leaveDays; //return total days
}
/**
* Get Current Year Public Holidays
*/
private function getHolidays()
{
$holidays = array();
$dates = $this->holiday->select('date')->where('active',1)->get();
foreach ($dates as $date) {
$holidays[]=Carbon::createFromFormat('Y-m-d',$date->date);
}
return $holidays;
}
}
Controller function receives user input request and validate before call the repository function
<?php
namespace App\Http\Controllers\Leave;
use App\Http\Controllers\AuthController;
use App\Http\Requests\Leave\LeaveApplicationRequest;
use App\Repositories\Leave\LeaveApplicationRepository;
use Exception;
class LeaveApplicationController extends AuthController
{
protected $leaveApplication;
/**
* LeaveApplicationsController constructor.
*/
public function __construct(LeaveApplicationRepository $leaveApplication)
{
parent::__construct();
$this->leaveApplication = $leaveApplication;
}
/**
* Store a newly created resource in storage.
*/
public function store(LeaveApplicationRequest $request)
{
try {
$this->leaveApplication->create($request);
return $this->successRoute('leaveApplications.index','Leave Applied');
}
catch (Exception $e) {
return $this->errorWithInput($request);
}
}
}
Here's an alternative to calculate business days between two dates and also excludes USA holidays using Pear's Date_Holidays from http://pear.php.net/package/Date_Holidays.
$start_date and $end_date should be DateTime objects (you can use new DateTime('#'.$timestamp) to convert from timestamp to DateTime object).
<?php
function business_days($start_date, $end_date)
{
require_once 'Date/Holidays.php';
$dholidays = &Date_Holidays::factory('USA');
$days = 0;
$period = new DatePeriod($start_date, new DateInterval('P1D'), $end_date);
foreach($period as $dt)
{
$curr = $dt->format('D');
if($curr != 'Sat' && $curr != 'Sun' && !$dholidays->isHoliday($dt->format('Y-m-d')))
{
$days++;
}
}
return $days;
}
?>
okay, I am at my wits end with this. been trying to solve this for 3 days now and I am getting nowhere with this.
I need to get the value of $offset between two locations and take it off of a set time which is (00:00).
here is how I set the $offset value and it works just fine.
<?php
if( isset($_POST['submit']))
{
//be sure to validate and clean your variables
$timezone1 = htmlentities($_POST['timezone1']);
$timezone2 = htmlentities($_POST['timezone2']);
//then you can use them in a PHP function.
function get_timezone_offset( $origin_tz, $remote_tz ) {
$timezone1 = new DateTimeZone ( $origin_tz );
$timezone2 = new DateTimeZone ( $remote_tz );
$datetime1 = new DateTime ("now", $timezone1);
$datetime2 = new DateTime ("now", $timezone2);
$offset = $timezone1->getOffset($datetime1) - $timezone2->getOffset($datetime2);
return $offset;
}
$offset = get_timezone_offset($timezone1, $timezone2);
}
?>
And here is how I've tried to do what i want using DateTime, this code will only echo's the $offset value without taking it off of the 00:00
<?php
if (0 > $offset)
{
// set an object with the current date
$date = new DateTime();
$date->setTime(00, 00);
// the second date
$date2 = new DateTime($offset/3600 * 1);
// apply the diff() method, getting a DateInterval object ($diDiff)
$diDiff = $date->diff($date2) ;
}
echo $diDiff->format("%H:%i");
?>
And i even tried to use strtotime but strtotime returns a wrong value and i have been advised by some guys on stackoverflow to use DateTime.
<?php
$time1 = strtotime('00:00');
if (0 > $offset)
{
// For negative offset (hours behind)
$hour_dif = date('H:i', strtotime($time1 -$offset/3600));
$time1 = "{$hour_dif}";
}
elseif (0 < $offset)
{
// For positive offset (hours ahead)
$hour_dif = date('H:i', strtotime($time1 +$offset/3600));
$time1 = "{$hour_dif}";
}
else
{
// For offsets in the same timezone.
$time1 = "in the same timezone";
}
echo "{$time1}";
?>
Please someone help me out as it is absolutely killing my time.
You can also easily solve this using Carbon, a class that will greatly simplify doing date calculations of any kind:
// example timezones
$timezone1 = 'Europe/Berlin';
$timezone2 = 'Asia/Yakutsk';
$dt1 = Carbon::createFromDate(2000, 1, 1, $timezone1);
$dt2 = Carbon::createFromDate(2000, 1, 1, $timezone2);
// false will force a relative difference, so it can be a negative result
$difference = $dt1->diffInMinutes($dt2, false);
$dtMidnight = Carbon::create(2000, 1, 1, 12, 0, 0);
// get the difference from midnight
$differenceFromMidnight = $dtMidnight->addMinutes($difference);
echo $differenceFromMidnight->hour;
echo $differenceFromMidnight->minute;
This handles both positive and negative offsets:
$sign = $offset >= 0 ? 1 : -1;
$offset = $offset * $sign; // make sure offset is a positive number
// set an object with the current date
$date = new DateTime();
$date->setTime(00, 00);
// the second date
$date2 = new DateTime();
$interval = new DateInterval("PT" . $offset . "S");
if ($sign > 0) {
$date2->add($interval);
} else {
$date2->sub($interval);
}
echo $date2->format("H:i");
The following code will print the input time adjusted by $offset amount of hours.
$date = new DateTime();
$date->setTime(00, 00);
$date->add(DateInterval::createFromDateString("{$offset} hours"));
echo $date->format('H:i');
I have, again, tested this solution (with PHP 5.4.17) and it correctly shifts the time.
PHPFiddle: http://phpfiddle.org/main/code/rhd-pj4
I'm looking for a function that calculates years from a date in format: 0000-00-00.
Found this function, but it wont work.
// Calculate the age from a given birth date
// Example: GetAge("1986-06-18");
function getAge($Birthdate)
{
// Explode the date into meaningful variables
list($BirthYear,$BirthMonth,$BirthDay) = explode("-", $Birthdate);
// Find the differences
$YearDiff = date("Y") - $BirthYear;
$MonthDiff = date("m") - $BirthMonth;
$DayDiff = date("d") - $BirthDay;
// If the birthday has not occured this year
if ($DayDiff < 0 || $MonthDiff < 0)
$YearDiff--;
}
echo getAge('1990-04-04');
outputs nothing :/
i have error reporting on but i dont get any errors
Your code doesn't work because the function is not returning anything to print.
As far as algorithms go, how about this:
function getAge($then) {
$then_ts = strtotime($then);
$then_year = date('Y', $then_ts);
$age = date('Y') - $then_year;
if(strtotime('+' . $age . ' years', $then_ts) > time()) $age--;
return $age;
}
print getAge('1990-04-04'); // 19
print getAge('1990-08-04'); // 18, birthday hasn't happened yet
This is the same algorithm (just in PHP) as the accepted answer in this question.
A shorter way of doing it:
function getAge($then) {
$then = date('Ymd', strtotime($then));
$diff = date('Ymd') - $then;
return substr($diff, 0, -4);
}
An alternative way to do this is with PHP's DateTime class which is new as of PHP 5.2:
$birthdate = new DateTime("1986-06-18");
$today = new DateTime();
$interval = $today->diff($birthdate);
echo $interval->format('%y years');
See it in action
A single line function can work here
function calculateAge($dob) {
return floor((time() - strtotime($dob)) / 31556926);
}
To calculate Age
$age = calculateAge('1990-07-10');
You need to return $yearDiff, I think.