populating multidimensional array from timestamp - php

I have a list of mysql timestamps.
I want to produce an html menu, which has got years as first LI and months as nested LI.
for example:
2012 ->
december,
may,
april.
2011 ->
november,
january.
2010 ->
april,
march,
february.
as you see, I want the menu to be an array of years and within months, just the months (and years) which I have in my database.
It's simple for sure, but I can't realize how to perform this.
I'm querying all my timestamps and cycling them, but then when I have to fill the array I can't manage.

The SQL you want is probably something like this:
SELECT YEAR(date) AS year, MONTH(date) AS month, COUNT(*) AS entries FROM my_table
GROUP BY year,month ORDER BY year ASC, month ASC;
And the code would be:
$previous_year = null;
foreach ($result_rows as $row) {
if ($previous_year == null || $row['year'] != $previous_year) {
if ($previous_year != null) {
echo '</ul>/li>';
}
echo '<li><span class="year">'.$row['year'].'</span><ul>';
$previous_year = $row['year'];
}
echo '<li>'.$row['month'].' ('.$row['entries'].')</li>';
}
if ($previous_year != null) {
echo '</ul></li>';
}
Edit:
Alternative PHP based on another answer, this is tidier:
$grouped = array();
foreach ($result_rows as $row) {
$grouped[$row['year']][$row['month']] = $row;
}
foreach ($grouped as $year => $months) {
echo "<li>$year";
echo "<ul>";
foreach ($months as $month => $row) {
echo "<li>$month (".$row['entries'].")</li>";
}
echo "</ul></li>";
}

Have you tried something like this?
<?php
// this would've been pulled from mysql
$data = array(
array('date' => "2010-11-12 12:34:56", 'some' => 'data'),
array('date' => "2010-12-12 12:34:56", 'some' => 'data'),
array('date' => "2010-12-13 12:34:56", 'some' => 'data'),
array('date' => "2011-01-01 12:34:56", 'some' => 'data'),
);
$grouped = array();
foreach ($data as $row) {
$year = substr($row['date'], 0, 4);
$month = substr($row['date'], 6, 2);
$grouped[$year][$month][] = $row;
}
var_dump($grouped);

You must group your queries using GROUP BY , and use loop in PHP which create suitable structure.

In slight peusdo code.
$r = query(SELECT * FROM TBL_WHATEVER ORDER BY TS ASC);
$last_year = null;
while($row as mysql_fetch_assoc($r)){
$year = date('Y', $r['ts']);
if($year != $last_year){
echo $year;
$last_year = $year;
}else{
$month = 1;
while($month < 12){
echo date('F', $r['ts']);
}
}
}
There are many posts about it like this one:
PHP: Loop through all months in a date range?

Related

Get all months from a query including zero counts

I have this query now:
SELECT DATE_FORMAT(`dataNl`, \'%Y%m\') AS `Ym`, COUNT(*) AS `totale`
FROM `noleggio`
GROUP BY `Ym`
This help to get data for each month, but if a month with 0 value, this doesn't exist in the database, so I can't get it. I need a query that add remaining month setting the COUNT field to 0.
I made a PHP code to add months with 0 value into the array, but it only works if the year is only one, if I want to get more, this needs a lot of tricky code, I think there could be a solution with SQL.
This is the PHP code:
$t = array();
$m = array();
foreach ($months as $val) {
$t[] = $val['totale'];
$m[] = $val['Ym'];
}
for ($i = 0; $i < 12; ++$i) {
if (in_array($i + 201801, $m) == false) {
array_splice($t, $i, 0, 0);
}
}
Here is a PHP solution which requires min and max dates from the database:
// use the query SELECT MIN(dataNl), MAX(dataNl) FROM ... to
// find the first and last date in your data and use them below
$dates = new DatePeriod(
DateTime::createFromFormat('Y-m-d|', '2018-01-15')->modify('first day of this month'),
new DateInterval('P1M'),
DateTime::createFromFormat('Y-m-d|', '2018-12-15')->modify('first day of next month')
);
// assuming $rows contain the result of the GROUP BY query...
foreach ($dates as $date) {
$datestr = $date->format('Ym');
$index = array_search($datestr, array_column($rows, 'Ym'));
if ($index === false) {
echo $datestr . ' -> 0' . PHP_EOL;
} else {
echo $datestr . ' -> ' . $months[$index]['totale'] . PHP_EOL;
}
}
Try the below query:
SELECT DATE_FORMAT(`dataNl`, \'%Y%m\') AS `Ym`, COUNT(*) AS `totale`
FROM `noleggio`
GROUP BY MONTH(`dataNl`)

Order results of a query by values

I'm trying to create a function to populate an ajax calendar with events.
I'm querying a date (format Ymd) from custom field in my wordpress database.
$metakey2 = 'jour';
$jours = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s ORDER BY meta_value ASC", $metakey2) );
if ($jours) {
$years = substr($jours, 0, 4); // OUTPUT YEAR FROM DATE
$months = substr($jours, 5, 2); // OUTPUT MONTH FROM DATE
$days = substr($jours, 7, 2); // OUTPUT DAY FROM DATE
foreach $years as $year {
foreach $months as $month {
if ($y == $year AND $m == $month) {
$events = array(
foreach $days as $day {
$day => array(
0 => array(
"0" => "Lorem ipsum dolor 111",
)
);
}
);
}
}
}
}
`
I'm definitely no expert and I've been trying to make this work for hours now... Can someone point me towards the right direction please?
Thank you,
Manue
$metakey2 = 'jour';
$jours = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s ORDER BY meta_value ASC", $metakey2) );
// Chaeck the data returned isn't null, blank, 0-length array, etc.
if (!empty($jours)) {
// Initialize events array
$events = array();
// Loop through the data
foreach ($jours as $jour) {
$year = substr($jour, 0, 4); // OUTPUT YEAR FROM DATE
$month = substr($jour, 5, 2); // OUTPUT MONTH FROM DATE
$day = substr($jour, 7, 2); // OUTPUT DAY FROM DATE
// PROCESS YOUR DATA HERE
...
}
}
The key is the foreach loop after the empty check. You need to loop through the data that is returned from the db as an array.

Archives for Blog

I am creating an archives navigation on my website and have found a few posts regarding how to do it and have pulled together some code, but can't seem to get it to work.
I want it to display like:
January 2015 (9)
December 2014 (8)
November 2014 (10)
October 2014 (15)
...
Here's the code :
$sql = "SELECT YEAR(timestamp_published) AS 'year', Month(timestamp_published) AS 'month', COUNT(id) AS 'count' FROM table GROUP BY YEAR(timestamp_published), MONTH(timestamp_published) DESC";
$data = $db->query($sql);
while($row = $db->fetch_assoc()) {
$data[$row['year']][$row['month']] = $row['count'];
}
foreach ($data as $year => $months) {
echo archive_date($month).' ';
foreach ($months as $month => $count) {
echo $year.' ('.$count.') (' . $data->id . ')<br/>';
}
}
}
Thank you! I ended up solving my own issue. I was building this in a class and there were a couple of issues. I've got the code working now, here it is for anyone in the future.
$sql = "SELECT YEAR(timestamp_published) AS 'year', MONTH(timestamp_published) AS 'month', COUNT(`publish`) AS 'count' FROM ".static::$table_name." GROUP BY YEAR(timestamp_published) DESC, MONTH(timestamp_published) ASC";
$result = $db->query($sql);
$data = array();
while($row = $result->fetch_assoc()) {
$data[$row['year']][$row['month']] = $row['count'];
}
foreach ($data as $year => $months) {
echo '<strong>'.$year.'</strong><br/><br/>';
foreach ($months as $month => $count) {
$dateObj = DateTime::createFromFormat('!m', $month);
$monthName = $dateObj->format('F'); // March
echo $monthName . ' ('.$count.')<br/>';
}
echo '<hr/>';
}
It actually comes out looking like this:
2015
January (3)
February (5)
March (6)
...
2014
January (7)
February (9)
...
I think you are looking to get the string representation of the month (bit unclear) but that can be achieved by using date() like so
date ("F", $month)
so in your case
echo date ("F", $month) . ' ' . $year.' ('.$count.')<br/>';

comparing dates in php

In the following php code, I am trying to show only those products from products.xml file that are stored in the last month. But my code does not work. Please help me in getting correct output. I also need to show products that are stored in the last 24 hours and last week.
$current_month = date("m");
$last_month = date('m', strtotime(date('-m')." -1 month"));
$xml = simplexml_load_file("products.xml");
$products = array();
foreach ($xml->product as $product) {
if ($product->date('m') == $last_month) {
$products[] = array( 'name' => (string)$product->name,
'details' => (string)$video->details );
}
}
Strtotime is nicer than you might think. For instance, this code;
if (date('m') > date('m', strtotime('last month')))
echo true;
else
echo false;
Will currently output "true" - because last month is 09, and this month is 10.
But what if this month is 01, and last month is 12? Then it would be false. I'd recommend you compare on years as well.
Edit: If this isn't a problem, and you only want to evaluate this for the most recent additions, then that should be fine. But you'll run into problems the year after if you only compare from last month, unless your import data only contains stuff from this year.
try
$last_month = date('m', strtotime("-1 month"));
$xml = simplexml_load_file("products.xml");
$products = array();
foreach ($xml->product as $product)
{
if ($product->date('m') == $last_month)
{
$products[] = array(
'name'=>(string)$product->name,
'details'=>(string)$video->details,
);
}
}

creating archive for my blog website

my database table is something like :
id year month
1 2011 november
2 2011 november
3 2011 october
i need to create a query so it return something like that :
2011
november
november
october
What is the correct query syntax to do it in php script ?
Here is the code i used :
<?php
$uid = $_SESSION['uid'];
$sql = "SELECT year, GROUP_CONCAT(month) AS months FROM articles GROUP BY year";
$res = mysql_query ($sql) or die (mysql_error());
if (mysql_num_rows($res) > 0) {
while ($rows = mysql_fetch_assoc($res)) {
foreach ($rows AS $row) {
echo $row['year'] . "<br>";
$months = explode(",", $row['months']);
foreach ($months AS $m) {
echo $m . "<br>";
}
}
}
}
?>
You can use GROUP_CONCAT() to return a comma-separated list of months:
SELECT year, GROUP_CONCAT(month) AS months GROM tbl GROUP BY year
Returns:
2011 november,november,october
Or just select both columns and handle the display/presentation in your code:
SELECT year, month FROM tbl WHERE year = 2011
Returns
2011 november
2011 november
2011 october
In code, loop and only display the year when it changes.
Update Since a code example seems warranted...
// Results from above GROUP_CONCAT() query already fetched & stored in `$rowset`:
while ($row = mysql_fetch_assoc($res)) {
$rowset[] = $row;
}
// Now $rowset is a 2D array containing all rows.
foreach ($rowset as $row) {
// Output the year
echo $row['year'] . "\n";
// months are comma-separated via GROUP_CONCAT()
// explode them into an array
$months = explode(",", $row['months']);
foreach ($months as $m) {
// Output the months
echo $m . "\n";
}
}
If I understood your question correctly, I think a simple "ORDER BY" clause would do the trick for you, something similar to:
SELECT * FROM table_name ORDER BY year DESC
Then, use your scripting language to display the data, a good idea could be (maybe) to fetch the year of the first row, store it in a temporal variable, then loop through the rows and check if the year has changed, if it has, change the value of the aforementioned variable, something like this:
$current_year = $data_set[0]['year'];
foreach ( $data_set as $data_row )
{
$current_year = ( $data_row['year'] != $current_year) ? $data_row['year'] : $current_year;
//Do something with it and/or the rest of the data
}
Hope this was of any help.
Cheers.

Categories