I am new to Laravel and not really sure how to do this.
I record dates in my database as start_day in my times table.
Date is persisted with the following format: 2019-10-03
Right now all I have is:
$months = DB::table('times')->where('start_day', '=', 2019)
How should I select data for each month of the year?
use whereYear
use Carbon\Carbon;
$months = DB::table('times')->whereYear('start_day', (string) Carbon::now()->year)->get();
If you want to select months only then
$months = DB::table('times')->select(DB::raw('MONTH(start_day) month')->whereYear('start_day', (string) Carbon::now()->year)->get();
You need to change the where() to whereYear() to search by year.
$months = DB::table('times')->whereYear('start_day', '=', 2019)
write
$month = array():
for($i=1;$i<=12;$i++){
$month[] = DB::table('times')->whereYear('start_day','2019')->whereMonth('start_day',$i)->get();
}
OR
$month = array():
for($i=1;$i<=12;$i++){
$month[] = DB::table('times')->where([['YEAR(start_day)', '=', 2019],['MONTH(start_day)','=',(int)$i]])->get();
}
you can try monthly , weekly , yearly in this format
$weeklyNumberOfSales = Sale::whereBetween('order_date', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])
->sum('qty');
$monthlyNumberOfSales = Sale::whereMonth('order_date',Carbon::now()->format('m'))
->sum('qty');
$yearlyNumberOfSales = Sale::whereYear('order_date',Carbon::now()->format('Y'))
->sum('qty');
model name Sale .
'order_date' and 'qty' are the field name
Related
I've got a query in my Laravel project that returns a collection of data from my database between two dates, it's then grouped by the hour (but I can change this to my liking), I'd now like to return the "dates" for data before they existed in the database as a way of building up a list of dates that I can display in my web page, eve though there will be no data for these days, my chart would look consistent.
As an example:
I want to see the past 30 days of data as a history, but the first 20 days of this period have no data yet, I still need to return the date keys for these days, except with just no data in them.
My current code is as follows (I'm using Carbon):
$uptimeData = UptimeChecks::where('user_id', 1)
->where('monitor_id', 1)
->where('checked_at', '>=', '2021-01-01 00:00:00')
->where('checked_at', '<=', '2021-01-30 23:59:59')
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$from = Carbon::now()->subDays(60);
$period = CarbonPeriod::create($from, '2021-01-30 23:59:59');
$dates = $period->toArray();
foreach ($dates as $key => $date) {
$dates[$key] = Carbon::parse($date)->format('Y-m-d');
}
$uptimeData = collect($uptimeData);
$uptimeData = $uptimeData->merge($dates);
$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) {
if (isset($item->checked_at)) {
$date = Carbon::parse($item->checked_at);
} else {
$date = Carbon::parse($item);
}
return $date->format('Y-m-d');
});
Even though there would be no entries to display a "checked_at" column, can this be spoofed with the date for that day with no data?
Update 03/05 # 20:30
I've updated my description to reflect the latest attempt to solve this problem, I appear to have constructed what I need, however, have some issues:
Where I'm looping over my $dates is there a way to build up some structure within each item so I don't have to do if/else checks on all my variables and keys?
For some reason, the "fake" dummy dates are being added after the real data, e.g: 1st Jan, 2nd Jan, 30th Dec ... how can I reverse this?
One way to achieve this is by creating a collection of the dates for the time period you want, and then merging the results of a query grouped by date into it.
Here's an example:
$from = '2021-01-01';
$to = '2021-01-31';
$period = CarbonPeriod::create($from, $to);
$dates = collect($period->toArray())->mapWithKeys(function ($date) {
return [$date->format('Y-m-d') => []];
});
// $dates = ['2021-01-01' => [], '2021-01-02' => [], ...etc]
$uptimeChecks = UptimeChecks::query()
->where('user_id', 1)
->where('monitor_id', 1)
->whereBetween('checked_at', [$from, $to])
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$uptimeDates = $uptimeChecks->groupBy(function ($item, $key) {
return $item->checked_at->format('Y-m-d');
});
// $uptimeDates = ['2021-01-02' => ['event1', 'event2'], ...etc]
$uptimeData = $dates->merge($uptimeDates);
// $uptimeData = ['2021-01-01' => [], '2021-01-02' => ['event1', 'event2'], ...etc]
This assumes you are casting the checked_at field to a date in your UptimeChecks Model.
I have a query that is pulling my data from the table based on the created_at column. I am trying to fill in the missing months for the year. So for example, I have data for February, but thats it. How Do i fill in an amount of 0 for January then March-December?
My query to pull out based on the full month name is as follows
$servers = Stat::where('type','servers')->orderBy('created_at', 'asc')->whereYear('created_at', '=', date("Y"))
->select(DB::raw("SUM(amount) as total"))
->get()
->groupBy(function($val) {
return Carbon::parse($val->created_at)->format('F');
});
In this case, I get my February and the total amount. I'd like the rest of the amounts that don't exist to be 0, or fill in the correct info if it exists later in the year.
You are using sum() for the whole year, and using groupBy method on collection, so there is only one month.
You need to group by month like this:
$servers = Stat::where('type','servers')
->orderBy('created_at', 'asc')
->whereYear('created_at', '=', date("Y"))
->groupBy(DB::raw("MONTH(created_at)"))
->selectRaw("SUM(amount) as total, create_at")
->get()
->groupBy(function($val) {
return $val->created_at->format('F');
});
and you can use CarbonPeriod to create an initial month array, and then merge to the servers:
$all_month = array();
$period = \Carbon\CarbonPeriod::create('2020-01-01', '1 month', '2021-12-31');
foreach ($period as $p) {
$m = $p->format('F');
if (isset($servers[$m])) {
$all_month []= [$m => $servers[$m]->first()->total];
} else {
$all_month []= [$m => 0];
}
}
I am working on getting all the attendance record by inputting MONTH and YEAR to get all the attendance in that MONTH and YEAR. But I am having a problem that when I input the MONTH and YEAR, it returns the current MONTH and YEAR record. This is my function code below
public function getEmployeeAttendance(){
$month = Carbon::now(request('attendance_date'))->format('m');
$year = Carbon::now(request('attendance_date'))->format('Y');
dump($month);
dump($year);
$emp_attendance = Attendance::whereMonth('attendance_date' , '=' , $month)
->whereYear('attendance_date' , '=' , $year)
->get();
if ($emp_attendance->isEmpty() ) {
return response()->json([
'Error' => 'No record!!!.']);
}
return response()->json(
[
'success' => true,
'data' => $emp_attendance
]
);
}
When I use dd($month) and dd($year) it returns the current MONTH is "11" and YEAR is "2018", but my input in Postman is MONTH = "5" and YEAR = "2015" (the result should return empty record but it returns all current data).
Can you please give me some advises on how to improve this code. I use the same code from another function but it is not running when I write this to get the MONTH and YEAR inputted. Thank you!
Option 1
If your input is like this : 2018-11-12(Y-m-d)
$month = Carbon::createFromFormat('Y-m-d', request('attendance_date'))->format('m');
$year = Carbon::createFromFormat('Y-m-d', request('attendance_date'))->format('Y');
dump($month);
dump($year);
$emp_attendance = Attendance::whereMonth('attendance_date' , '=' , $month)
->whereYear('attendance_date' , '=' , $year)
->get();
Option 2
If your input is like this : 2018-11-12 10:10:59(Y-m-d H:i:s)
$month = Carbon::createFromFormat('Y-m-d H:i:s', request('attendance_date'))->format('m');
$year = Carbon::createFromFormat('Y-m-d H:i:s', request('attendance_date'))->format('Y');
dump($month);
dump($year);
$emp_attendance = Attendance::whereMonth('attendance_date' , '=' , $month)
->whereYear('attendance_date' , '=' , $year)
->get();
for more info : https://carbon.nesbot.com/docs/
Option 3
If your input is like this :
1. Input box-1 >> 10(month)
2. Input box-2 >> 2018(year)
/*
# No need those section.
$month = Carbon::createFromFormat('Y-m-d H:i:s', request('attendance_date'))->format('m');
$year = Carbon::createFromFormat('Y-m-d H:i:s', request('attendance_date'))->format('Y');
dump($month);
dump($year);
# END
*/
$emp_attendance = Attendance::whereRaw("month(attendance_date) = '".request('attendance_month')."'")
->whereRaw("year(attendance_date) = '".request('attendance_year')."'")
->get();
use Carbon::parse instead of Carbon::now
I try to get an average of given dates but I failed when dates are from two different years. I need something like this
given dates:
2017-06-1
2017-06-3
2017-06-4
2017-06-3
2017-06-5
output : 2017-06-4
this is my code:
$total = 0;
foreach ($dates as $date) {
$total+= date('z', strtotime($date))+1;
}
$avg_day = $total/sizeof($dates);
$date = DateTime::createFromFormat('z Y', $avg_day . ' ' . date("Y"));
but my code is not working for
given dates:
2016-12-29
2016-12-31
2017-01-1
2017-01-5
2017-01-3
You can work with timestamp of the date and use avg() method of the Illuminate\Support\Collection
$dates = [
'2016-12-29', '2016-12-31', '2017-01-1', '2017-01-5', '2017-01-3'
];
$dateCollection = collect();
foreach($dates as $date){
$dateCollection->push((new \DateTime($date))->getTimestamp());
}
$averageTimestamp = $dateCollection->avg(); //timestamp value
$averageDate = date('Y-m-d', $average);
Or using Carbon package:
$dateCollection->push(Carbon::parse($date)->timestamp);
...
$averageDate = Carbon::createFromTimestamp($average)->toDateString();
Your code is not working for your base dates. The correct output for
2017-06-1 2017-06-3 2017-06-4 2017-06-3 2017-06-5
is
2017-06-03
According to OpenOffice calc, and overall logic (a date is represented by epoch number)
Check out this script
$dates = ['2017-06-1 ', '2017-06-3', '2017-06-4', '2017-06-3', '2017-06-5'];
$dates = array_map('strtotime', $dates);
$average = date('Y-m-d', array_sum($dates) / count($dates)); // 2017-06-03 (1496490480)
echo $average;
Keep simple tasks simple
I think you have problem with averaging year. So, You can do this to get average.
Just an algorithm:
Find smallest date among your dates at first as $smallest
Initiate a variable $total = 0;
Add difference of each date in days with smallest date.
Find average from total.
Add this total to smallest date.
Here, You have smallest as $smallest = '2016-12-29'
$total = 0;
$dates = ['2016-12-29', '2016-12-31', '2017-01-1', '2017-01-5', '2017-01-3'];
$smallest = min($dates);
$smallest = Carbon::parse($smallest);
foreach($dates as $date){
$d = Carbon::parse($date);
$total = $total+$smallest->diffInDays($d);
}
$average_day = $total/sizeof($dates);
$average_date = $smallest->addDays($average_day);
Hope, This might help you.
I have fields in my table for date, but they contain everything - day, year and month. Can I write a query to get only the records, which has month equal to the current month? I can do this:
$today = new \DateTime();
$month = $today->format('m');
$cat = $em->getRepository('EMBudgetTrackerBundle:Expense')->find(1);
$ex_date = $cat->getDate();
and compare $month and $ex_date, but can I write some kind of query? Something like this:
public function getExpensesByMonth($month)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date = :date')
->setParameter('date', $month);
return $q->getQuery()->getResult();
}
Thank you in advance! :)
If you database column is in DateTime format you can use the DateTime object in your query. As far as I know you can only query for time ranges though.
public function getExpensesByMonth($beginning, $end)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date > :beginning')
->andWhere('e.date < :end')
->setParameter('beginning', $beginning)
->setParameter('end', $end);
return $q->getQuery()->getResult();
}