How to summarize multiple Intervals in PHP - php

In my app I can create projects and for each project I can record work reports. Each report has a start and an end timestamp. A table in the project description shows every report for this project and it also calculates the duration (with DateTime and the diff() function used between start and end timestamp). Now I want to calculate the total work time on the projects but I have no idea how I can do this. I already tried looping through all reports somehow and then use DateTime functions, but I'm getting nowhere... My last desperate attempt was this:
public static function calculateDuration($start, $end)
{
$start = date('Y-m-d H:i:s', $start);
$end = date('Y-m-d H:i:s', $end);
$s = new \DateTime($start);
$e = new \DateTime($end);
$interval = $e->diff($s);
return $interval->format('%H:%I');
}
public static function calculateTotal($idProject)
{
$reports = self::find('id_project = "' . $idProject . '"');
$totalReports = new \DateTime();
foreach ($reports as $report) {
$totalReports->add(new \DateInterval(self::calculateDuration($report->getStart(), $report->getEnd())));
}
/*echo '<pre>';
die(var_dump($totalReports));
echo '</pre>';*/
return $totalReports->format('H:I');
}
the calculateDuration functions works perfectly, but of course calculateTotal doesn't, because DateInterval does not take a string like "0:30". So that is completely useless...
I hope I provided all the needed information, just let me know if you need something else.

For clarity on my comments: You already have calculateDuration doing all the work, and it internally deals with a DateInterval object. So why not make use of it? Here, getInterval is a protected method that's used by both existing methods and returns the DateInterval object directly. Now calculateDuration becomes a simple formatting function, and calculateTotal has access to the DateInterval object.
protected static function getInterval($start, $end)
{
$s = new \DateTime('#' . $start);
$e = new \DateTime('#' . $end);
return $e->diff($s);
}
public static function calculateDuration($start, $end)
{
return self::getInterval($start, $end)->format('%H:%I');
}
public static function calculateTotal($idProject)
{
// ...
$totalReports = new \DateTime();
$totalReportsEnd = clone $totalReports;
foreach ($reports as $report) {
$totalReportsEnd->add(self::getInterval(
$report->getStart(),
$report->getEnd()
));
}
$totalInterval = $totalReportsEnd->diff($totalReports);
// do as you wish with the interval
}

Just create a valid DateInterval format instead of returning hours and minutes:
// Untested. Might need escaping.
return $interval->format('PT%HH%IM');

Related

Is there a shorter Datetime construct for the following code?

Currently I am using such fragment:
if (is_numeric($date)) {
$datetime = new DateTime('#'.$date);
} else {
$datetime = new DateTime($date);
}
Where $date is either unixtimestamp or some date string like 2016/03/03.
What are the best failsafe equivalent for this construct ?
Maybe some one-liner ? A wrapper class ?
I am asking about some shorter construct as we are using the above in many places in our system. So I would like to replace this with something more readable and failsafe.
If you want something reusable across your project, wrap it in your own class, e.g.
class AcmeDateTime extends \DateTime
{
public function __construct($time = "now", DateTimeZone $timezone = null)
{
$time = is_numeric($time) ? "#" . $time : $time;
parent::__construct($time, $timezone);
}
}
You could use ternary operator in php to shorten the 4 lines to a single line like this:
$datetime = new DateTime((is_numeric($date) ? '#' : '') . $date);

PHP - Google Analytics API - Using variables in data_ga->get

I'm having a little trouble with Google Analytics and asking it to provide results based on a variable containing a date rather than a date as a plain string.
Declaration of variables:
$date = new DateTime();
$end_date = $date->format('Y-m-d');
$date = sub(new DateInterval('P1M'));
$start_date = $date->format('Y-m-d');
Code:
function getResults($analytics, $profileId) {
return $analytics->data_ga->get('ga:'.$profileId, $start_date, $end_date, 'ga:sessions');
}
The variables are assigned elsewhere; but when I run the code I'm getting the following:
There was a general error : (get) missing required params: 'start-date', 'end-date'
Anyone know why, when using them as plain strings with single quotes works? (e.g: '2014-09-04 for today)
I just had a moment of inspiration. I realised that my "Code" was inside a function. It made sense that the variables had to be passed to the function for the code to understand it.
Fixed Code
function runMainDemo($analytics, $start_date, $end_date)
{
try
{
$profileId = getFirstProfileId($analytics);
if (isset($profileId))
{
$results = getResults($analytics, $profileId, $start_date, $end_date);
...
}
...
}
...
}
function getResults($analytics, $profileId, $start_date, $end_date) {
return $analytics->data_ga->get('ga:'.$profileId, $start_date, $end_date, 'ga:sessions');
}

Looping through method within an object Laravel 4

I am trying to loop through a method I created for dates in my object. However, it's only looping the first results and I am not sure how I can make it loop through every result and apply accordingly.
Date Method
public function getDate($date) {
$date = preg_replace('/,/', '', $date);
$newDate = strtotime($date);
$dateFormat = date('l: F d, Y',$newDate);
return $dateFormat;
}
Controller calling the Model
public function showDashboard() {
$pages = Pages::orderBy('created_at', 'DESC')->get();
// foreach($pages as $page) {
// $date = $this->getDate($page->created_at);
// }
//var_dump($date); die;
return View::make('dashboard.index', ['pageTitle' => 'Dashboard','pages' => $pages]);
}
dumping $date only returns one result which looks like the last date in the database table. If I put the dump inside the loop I only get the first result.
I tried applying the method directly to the Blade template $this->getDate($page->created_at); but returns an error stating it is not a defined method. The blade template is just a simple foreach loop that would show each record. What I want accomplished is foreach one of those created_at records I want the getDate method applied to it.
You've not set $date as an array - its writing over itself each time..
public function showDashboard() {
$pages = Pages::orderBy('created_at', 'DESC')->get();
$date = array();
foreach($pages as $page) {
$date[] = $this->getDate($page->created_at);
}
var_dump($date); die;
return View::make('dashboard.index', ['pageTitle' => 'Dashboard','pages' => $pages]);
}

Issue with eager loading of neasted models with Laravel

Any idea why the following code is working proprely, returns the device with sensors and measuraments
public function getLastMinutes($device_id,$sensor_id,$minutes = 10) {
...
$devices = Auth::user()->devices()->where("device_id",$device_id)->with(array('sensors.measurements' => function($query) use ($minutes,$sensor_id) {
$date = new DateTime;
$date->modify(-1*$minutes.' minutes');
$formatted_date = $date->format('Y-m-d H:i:s');
$query->where('measurements.created_at','>=',$formatted_date);
}))->get()->toArray();
return Response::json($devices);
...
but when i add the second where("sensor_id",$sensor_id) the measuraments disappiers from the json object returned
public function getLastMinutes($device_id,$sensor_id,$minutes = 10) {
...
$devices = Auth::user()->devices()->where("device_id",$device_id)->with(array('sensors.measurements' => function($query) use ($minutes,$sensor_id) {
$date = new DateTime;
$date->modify(-1*$minutes.' minutes');
$formatted_date = $date->format('Y-m-d H:i:s');
$query->where("sensor_id",$sensor_id)->where('measurements.created_at','>=',$formatted_date);
}))->get()->toArray();
return Response::json($devices);
...
There is something i'm missing?
Thank you for your help!
I figure out the problem. by doing with(array('sensors.measurements .... in the object query you do not have any access to sensor... this means that by doing this $query->where("sensor_id",$sensor_id) the sensors_id will be searched on the measurements table... which is uncorrected. So the solution is have to with one that contains 'sensors' and another one that contains 'sensors.measuraments'.
So from this (wrong)
public function getLastMinutes($device_id,$sensor_id,$minutes = 10) {
...
$devices = Auth::user()->devices()->where("device_id",$device_id)->with(array('sensors.measurements' => function($query) use ($minutes,$sensor_id) {
$date = new DateTime;
$date->modify(-1*$minutes.' minutes');
$formatted_date = $date->format('Y-m-d H:i:s');
$query->where("sensor_id",$sensor_id)->where('measurements.created_at','>=',$formatted_date);
}))->get()->toArray();
return Response::json($devices);
...
to this one (correct)
...
$devices = Auth::user()->devices()->where("device_id",$device_id)
->with(array('sensors' => function($query) use ($sensor_id) {
$query->where('sensors.sensor_id',$sensor_id);
}))
->with(array('sensors.measurements' => function($query) use ($minutes,$sensor_id) {
$date = new DateTime;
$date->modify(-1*$minutes.' minutes');
$formatted_date = $date->format('Y-m-d H:i:s');
$query->where('measurements.created_at','>=',$formatted_date);
}))
->get()->toArray();
return Response::json($devices);
...
little tip. laravel-debugbar is a great project and you should check it out, but it actually did not help me much since i have a SPA and Laravel is doing a RESTFUL json server and for some reason laravel-debugbar did not kick in... but this little piece of code was atually great (taken from Get the query executed in Laravel 3/4)
$queries = DB::getQueryLog();
$last_query = end($queries);
return Response::json($last_query);
Hope can help you

PHP Optional Function Arguments

I'm a little stuck trying to create a function that takes a single, optional argument. Instead of this being a string I'd like it to be the result of a function (or even better, a DateTime object). Essentially - I want the user to either pass in a DateTime object, or for the function to resort to todays date if no arguments are supplied. Is this possible with PHP? By trying to create the new object in the function header as such
function myDateFunction($date = new DateTime()){
//My function goes here.
}
causes PHP to fall over.
Many thanks.
Yes. It is possible if you move $date instantiation to function body:
<?php
header('Content-Type: text/plain');
function myDateFunction(DateTime $date = null){
if($date === null){
$date = new DateTime();
}
return $date->format('d.m.Y H:i:s');
}
echo
myDateFunction(),
PHP_EOL,
myDateFunction(DateTime::createFromFormat('d.m.Y', '11.11.2011'));
?>
Result:
15.09.2013 17:25:02
11.11.2011 17:25:02
From php.net:
Type hinting allowing NULL value
The default value must be a constant expression, not (for example) a variable, a class member or a function call.
http://php.net/manual/en/functions.arguments.php#example-154
You can do it this way:
function myDateFunction($date = null){
if(is_null($date) || !($date instanceof DateTime)) {
$date = new DateTime();
}
return $date;
}
var_dump(myDateFunction());
You can use other option:
function myDateFunction($date = null){
if(is_null($date)) $date = new DateTime();
}
function myDateFunc($date = null){
if(!isset($date) || $date !instanceof DateTime){
$date = new DateTime()
}
/* YOur code here*/
}
for optional argument in your function, you can write code like
function myDateFunction($date = ''){
//My function goes here.
if($date==''){ $date = new DateTime()}
}
hope it helps

Categories