Archive by year and month - php

I'm trying to build a year\month archive.
It refuses to output what i want so i'm hoping one of you might push me in the right direction.
I want to sort by year, and show the months for each year ( if exists) and output it like this:
2012
- June
- August
2011
- July
my code is this :
$query = "SELECT * FROM article WHERE full_name ='$safe_name' group by year, month";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
$year = $row['year'];
$month = $row['month'];
echo "<ul class='year'><li><a>{$year}</a>";
echo "<ul class='months'><li><a>{$month}</a></li></ul>
</li></ul>";
}
But it outputs :
2012
- june
2012
- august
2011
- july
When i group only by year, it will output:
2012
- june
2011
- july
i have a "date_posted" row which is datetime (yyyy-mm-dd 00:00:00).
On top of that i have 1 row for month and 1 for year ( i know that's dumb, but i couldnt figure out how to do this by just using the "date_posted" row.
Ive read up on some posts on this topic, but its not doing the trick for me.
Any help is greatly appreciated!

This should work. When fetching results, sometimes it's handy to restructure it to be easily usable in iterating a view.
$query = "SELECT * FROM article WHERE full_name ='$safe_name' group by year, month";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
// Get data
$year = $row['year'];
$month = $row['month']
// Structure it
$archive[$year][] = $month;
}
// Display data
foreach($archive as $year => $months)
{
// Show year
echo "<ul class='year'><li><a>{$year}</a>";
// Month container
echo "<ul class='months'>"
// Get months
foreach($months as $month)
{
echo("<li><a>{$month}</a></li>";
}
// Close Month/Year containers
echo("</ul></li></ul>");
}

You need to use a simple 'state' machine to detect when a year changes:
$previous_year = null;
$frist = true;
echo "<ul>"
while($row = mysql_fetch_assoc($result)) {
if ($row['year'] != $previous_year) {
// got a new year
if (!$frist) {
echo "</ul></li>"; // only close a previous list if there IS a previous list
$frist = false;
}
echo "<li class="year">$row[year]\n<ul>";
$previous_year = $row['year'];
}
echo "<li class="month">$row['month']</li>";
}

$temp_year = 0;
while($row = mysql_fetch_assoc($result)) {
$year = $row['year'];
$month = $row['month'];
if( $temp_year != $year )
{
if( $temp_year > 0 )
echo "</li></ul>";
$temp_year = $year;
echo "<ul class='year'><li><a>{$year}</a>";
}
echo "<ul class='months'><li><a>{$month}</a></li></ul>";
}

Give a shot
$storage_array = array();
while($row = mysql_fetch_assoc($result)) {
$year = $row['year'];
$month = $row['month'];
$storage_array[$year][] = $month;
}
foreach ($storage_array as $year => $month_array){
echo "<ul class='year'><li><a>{$year}</a>";
foreach ($month_array as $month){
echo "<ul class='months'><li><a>{$month}</a></li></ul>";
}
echo "</li></ul>";
}

Related

Get week number for given month of year for presentation on calendar

I'm creating a calendar with Sunday being the start of each week and I want to present the week number of the year before each row of dates.
This is my calendar
my calendar
How can I add week numbers like this:
This is what I need
My code:
<?php
function generate_calendar($month, $year) {
$calendar = array();
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$first_day_of_month = date('w', strtotime("$year-$month-01"));
$week_number = 1;
$week = array();
// Determine the week number offset
$days_from_january_1st = strtotime("$year-01-01");
$days_to_first_day_of_month = strtotime("$year-$month-01");
$week_number_offset = floor(($days_to_first_day_of_month - $days_from_january_1st) / 604800);
// Check if the last week of the previous month is full (7 days)
$last_week_of_previous_month = $week_number_offset;
if ($month > 1) {
$previous_month = $month - 1;
$previous_month_year = $year;
$previous_month_year = date("Y", strtotime("-1 month" , strtotime("$year-$month-01")));
$previous_month = date("n", strtotime("-1 month" , strtotime("$year-$month-01")));
if ($previous_month == 0) {
$previous_month = 12;
$previous_month_year = $year - 1;
}
$days_in_previous_month = cal_days_in_month(CAL_GREGORIAN, $previous_month, $previous_month_year);
$last_day_of_previous_month = date('w', strtotime("$previous_month_year-$previous_month-$days_in_previous_month"));
if ($last_day_of_previous_month == 6) {
$last_week_of_previous_month=$last_week_of_previous_month + 1;
} else {
// Check if the last week of the previous month only has a few days
$last_week_of_previous_month = $last_week_of_previous_month;
}
}
// Generate the previous month's days
for ($i = 1; $i <= $first_day_of_month; $i++) {
array_unshift($week, "");
}
// Generate the current month's days
for ($i = 1; $i <= $days_in_month; $i++) {
$week[] = $i;
if (count($week) == 7) {
$calendar[$week_number + $last_week_of_previous_month] = $week;
$week_number++;
$week = array();
}
}
// Generate the next month's days
$remaining_days = 7 - count($week);
for ($i = 1; $i <= $remaining_days; $i++) {
$week[] = '';
}
if (!empty($week)) {
$calendar[$week_number + $last_week_of_previous_month] = $week;
}
return $calendar;
}
$year = 2022;
echo "<table>\n";
echo " <tr>\n";
echo " <th colspan='3'>$year</th>\n";
echo " </tr>\n";
echo " <tr>\n";
for($i=1; $i<=12; $i++){
$month_name = date('F Y', strtotime("$year-$i-01"));
$calendar = generate_calendar($i, $year);
echo "<td>\n";
echo "<table>\n";
echo " <tr>\n";
echo " <th colspan='8'>$month_name</th>\n";
echo " </tr>\n";
echo " <tr>\n";
echo " <th>Week</th>\n";
echo " <th>Sun</th>\n";
echo " <th>Mon</th>\n";
echo " <th>Tue</th>\n";
echo " <th>Wed</th>\n";
echo " <th>Thu</th>\n";
echo " <th>Fri</th>\n";
echo " <th>Sat</th>\n";
echo " </tr>\n";
foreach ($calendar as $week_number => $week) {
echo " <tr>\n";
echo " <td>$week_number</td>\n";
foreach ($week as $day) {
if (empty($day)) {
echo " <td></td>\n";
} else {
echo " <td>$day</td>\n";
}
}
echo " </tr>\n";
}
echo "</table>\n";
echo "</td>\n";
if($i==3 || $i==6 || $i==9){
echo " </tr>\n";
echo " <tr>\n";
}
}
echo " </tr>\n";
echo "</table>\n";
?>
Trying to add week number which counts from first week of January (if last week of previous month is not full 7 days then first week of current month start from last week of previous month), but my code only count from first week of current month.
I managed to get the right result (as far as I tested) with IntlCalendar and its FIELD_WEEK_OF_YEAR constant instead of counting Sundays.
I did some refactoring of your function, but ran out of time to do a full reduction of the script (there may still be lines that can be simplified/condensed).
Code: (Demo)
function generate_calendar(int $month, int $year) {
$calendar = [];
$week_number = (IntlCalendar::fromDateTime ("$year-$month-01"))->get(IntlCalendar::FIELD_WEEK_OF_YEAR);
$month_start = new DateTime("$year-$month-01");
// Generate the previous month's days
if ($first_day = $month_start->format('w')) {
$week = array_fill(1, $first_day, '');
}
// Generate the current month's days
$days_in_month = $month_start->format('t');
for ($i = 1; $i <= $days_in_month; $i++) {
$week[] = $i;
if (count($week) == 7) {
$calendar[$week_number] = $week;
$week_number++;
$week = [];
}
}
if ($week) {
// Generate empty days for the next month
$calendar[$week_number] = array_pad($week, 7, '');
}
return $calendar;
}
I don't believe there is any way to set the start day of the week in the standard library of PHP without manual calculation, but you can do it easily with the intl library (make sure the intl PHP extension is enabled):
$cal = IntlGregorianCalendar::createInstance();
// Set start of week to Sunday
$cal->setFirstDayOfWeek(IntlGregorianCalendar::DOW_SUNDAY);
// Get week number of the year for the current date
$weekOfYear = intval(IntlDateFormatter::formatObject($cal, 'w'));
// Advance to the next week
$cal->add(IntlGregorianCalendar::FIELD_WEEK_OF_YEAR, 1);
// ect...

Separating a date array to have different output for 1st date in array

Basically I am building a calendar/event booking system on my local PC for personal use, I have the functionality working to get the days from my database that have a booking attached to them, and you recolour the dates in the array accordingly, but I'm trying to work out if I could customise the result of the 1st day in each range, and the following days being the same.
Here is how it looks(if it makes it any easier)
And here is the code I am currently using on the page..
<?php
function date_range($first, $last, $step = '+1 day', $output_format = 'Y-m-d' ) {
$dates = array();
$current = strtotime($first);
$last = strtotime($last);
while( $current <= $last ) {
$dates[] = date($output_format, $current);
$current = strtotime($step, $current);
}
return $dates;
}
?>
<table width="100%" cellspacing="0" cellpadding="0" border="0" style="background-color: #aaaaaa;">
<?php
$cmonth = date('F');
$cyear = date('Y');
$res = mysql_query("SELECT * FROM trips WHERE year(start_date) = '$cyear' ORDER BY start_date ASC");
$array_days = array();
while ($rows = mysql_fetch_array($res)) {
$selected_dates = date_range(date("Y-m-d",strtotime($rows['start_date'])), date("Y-m-d",strtotime($rows['end_date'])));
foreach($selected_dates as $selected_date){
$array_days[$selected_date]['start_end'] = "". $rows['trip_start'] . " to " . $rows['trip_end'];
$array_days[$selected_date]['colour'] = "". $rows['colour'];
$array_days[$selected_date]['booked'] = "". $rows['booked'];
$array_days[$selected_date]['capacity'] = "". $rows['capacity'];
}
}
?>
<tr>
<td> </td>
<?php for($i=1;$i<=31;$i++){?>
<td class="trip-date-cell"><?php echo $i;?></td>
<?php }?>
</tr>
<?php
$current_month = date("m");
$next_6_month = date("m", strtotime("+5 month", strtotime(date("F") . "1")));
for($i=$current_month;$i<=$next_6_month;$i++){ // 12 months in year
?>
<tr>
<td class="trip-month-cell"><?php echo date('M', mktime(0, 0, 0, $i,10, $cyear)); ?></td>
<?php
$days_in_month = cal_days_in_month(CAL_GREGORIAN,$i,$cyear);
foreach (range(1, $days_in_month) as $days) {
$key = date('Y-m-d', mktime(0, 0, 0, $i, $days, $cyear));
if(array_key_exists($key,$array_days)){
$color = $array_days[$key]['capacity'] - $array_days[$key]['booked'] == 0 ? "#303030" : $array_days[$key]['colour'];
echo "<td class='trip-day-book' style='background-color: ".$color."' alt='".$array_days[$key]['start_end']."' title='".$array_days[$key]['start_end']."'> </td>";
} else {
echo "<td class='trip-day-blank'> </td>";
}
}
?>
</tr>
<?php } ?>
</table>
Any suggestions or advice would be appreciated.
You could store the first date information in your array when reading in the date ranges:
while ($rows = mysql_fetch_array($res)) {
$selected_dates = date_range(date("Y-m-d",strtotime($rows['start_date'])), date("Y-m-d",strtotime($rows['end_date'])));
// default to true: first date is first day in range
$firstDate = true;
foreach($selected_dates as $selected_date) {
// store first day info in array
$array_days[$selected_date]['first_day'] = $firstDate;
// set to false for all following days
if ($firstDate) $firstDate = false;
$array_days[$selected_date]['start_end'] = "". $rows['trip_start'] . " to " . $rows['trip_end'];
$array_days[$selected_date]['colour'] = "". $rows['colour'];
$array_days[$selected_date]['booked'] = "". $rows['booked'];
$array_days[$selected_date]['capacity'] = "". $rows['capacity'];
}
}
and then while rendering access the information to achieve your desired result:
$color = $array_days[$key]['capacity'] - $array_days[$key]['booked'] == 0 ? "#303030" : $array_days[$key]['colour'];
// set content of cell according to first day info
$content = $array_days[$key]['first_day'] ? '<strong>1</strong>' : ' ';
echo "<td class='trip-day-book' style='background-color: ".$color."' alt='".$array_days[$key]['start_end']."' title='".$array_days[$key]['start_end']."'>$content</td>";

Group SQL outputs with same value

I'm trying to create a script that shows the openings of a store.
I want this openings to be listed below each others. If for example, Monday, Tuesday and Wednesday has the exact same opening time, I want it to be grouped like this:
Mon-Wed: 12:00-15:00
Thursday: 13:00-15:00
Friday: 10:00-18:00
Saturday: 12:00-18:00
Sunday: 14:00-18:00
It works fine when outputting weekday by weekday, but I cannot figure out, how to 'group' the weekdays, with the same opening time.
I have tried to use if($time == $time) but that didn't worked. I do not have any other ideas how to do it.
I don't want to get the weekday names from the table itself. That's why I've created the $weekdays array so that I can change the weekday name, directly in the code.
I also need to put the weekday names and the opening times in separate spans.
This is my SQL Table:
ID | mon | tue | wed | thu | fri | sat | sun
1 12:00-15:00 12:00-15:00 12:00-15:00 13:00-15:00 10:00-18:00 12:00-18:00 14:00-18:00
This is my current PHP code:
$get_openings = mysql_query("SELECT * FROM openings WHERE NC_Id='1'");
while($days = mysql_fetch_array($get_openings)) {
// Loads time only from database
$mon = $days['mon'];
$tue = $days['tue'];
$wed = $days['wed'];
$thu = $days['thu'];
$fri = $days['fri'];
$sat = $days['sat'];
$sun = $days['sun'];
$weekdays = array('monday','tuesday','wednesday','thuesday','friday','saturday','sunday');
$times = array($mon,$tue,$wed,$thu,$fri,$sat,$sun);
$i = 0;
foreach($times as $time) {
while ($i <= 6) {
if($time == "") {
echo $weekdays[$i++].": "."Closed<br>";
}
else {
echo $weekdays[$i++].": ".$time."<br>";
}
}
}
}
Can someone help me please?
Thanks - Jesper
1) define $weekdays outside the while-loop, since it doesn't change
2) define $mon, $tue ... and then collect them again in $times doesn't make sense. You can directly use the named array from the fetch statement.
$weekdays = array('mon','tue','wed','thu','fri','sat','sun');
$get_openings = mysql_query("SELECT * FROM openings WHERE NC_Id='1'");
while($days = mysql_fetch_array($get_openings)) {
$result = array();
foreach($weekdays as $day){
$time = $days[$day]==''?'closed':$days[$day];
if(count($result)>0 and $result[0][1]==$time){
$result[0][0] = substr($result[0][0],0,3) . '-' . $day;
} else {
array_unshift($result,array($day,$time));
}
}
$result = array_reverse($result);
/* add code to display $result here */
}
In each loop $result is an array of array containing the day names and the openning times. For Example: array(array('mon-wed','12:00-15:00'),array('thu',...),...)
*/
Try it like this:
$previous_time = null;
$previous_day = null;
$consequetive = 0;
while($days = mysql_fetch_assoc($get_openings)) { // loop through your rows
$days[''] = null;
foreach ($days as $day => $time) { // loop through your fields
if ($day != "id") { // skip the `id` field
if ($previous_time !== $time) {
echo $consequetive > 0 ? $previous_day : "";
echo $previous_day ? ": " : "";
echo $previous_time === "" ? "Closed" : $previous_time;
echo $previous_day && $day ? "<br>" : "";
echo $day;
$consequetive = 0;
}
else {
echo ++$consequetive == 1 ? " - " : "";
}
$previous_time = $time;
$previous_day = $day;
}
}
}

displaying the dates in a particular format php

I have a date array sorted in asc order. I want to display the date as
Oct 10,12,24 2012
Dec 12,20,24 2012
Jan 02,10,25 2013
I have got the dates as the month ie.Oct,Dec,Jan.. and the dates and year, but i want it to be displayed in the above mentioned format. I have tried the below code, but it is not giving the desired result. Can someone pls help me with this?
$CruiseDetailsSailing is the array containing the date in an ascending order.
if (count($CruiseDetailsSailing) > 0) {
$date = array();
$month = array();
$Year = array();
for ($n = 0; $n < count($CruiseDetailsSailing); $n++) {
if ($CruiseDetailsSailing[$n] != "") {
$date[] = date('Y-m-d', strtotime($CruiseDetailsSailing[$n]));
}
}
}
sort($date);
if (count($date) > 0) {
$temp = "";
$yeartemp = "";
for ($p = 0; $p < count($date); $p++) {
$month = date("M", strtotime($date[$p]));
$day = date("d", strtotime($date[$p]));
$year = date("Y", strtotime($date[$p]));
if ($month != $temp) {
$temp = $month;
?>
<li> <?php
echo $temp . " " . $day . ", ";
} else {
echo $day . ", ";
}
if (($p != 0) && ((date("M", strtotime($date[$p]))) == (date("M", strtotime($date[$p - 1])))) && ((date("Y", strtotime($date[$p]))) == (date("Y", strtotime($date[$p - 1]))))) {
echo $year;
}
if (($p != 0) && ((date("M", strtotime($date[$p]))) != (date("M", strtotime($date[$p - 1])))) && ((date("Y", strtotime($date[$p]))) != (date("Y", strtotime($date[$p - 1]))))) {
echo $year;
}
}
Oct is the month and 10,12,24 are the months and 2012 is the year. I got the the dates as Oct 10 2012,Oct 12 2012,Oct 24 2012. I just want to display the results as Oct only once and then the dates and the year just once.
Thanks,
this should do:
sort($date); // sorted input array containing dates
$result_dates = Array();
// bring dates in correct format
foreach($date as $current_date) {
$month = date("M", strtotime($current_date));
$day = date("d", strtotime($current_date));
$year = date("Y", strtotime($current_date));
$result_dates[$year][$month][] = $day;
}
// output dates
foreach($result_dates as $year => $months) {
foreach($months as $month => $days) {
echo $month . " " . implode(",", $days) . " " . $year . "\n";
}
}
the following input:
$date = Array('10/03/2012', '10/10/2012', '10/17/2012', '11/04/2012', '11/05/2012', '11/23/2012');
results in:
Oct 03,10,17 2012
Nov 04,05,23 2012
You can do it simply like this
/* Array to pass the function
$date_array = array(
'2012-10-10',
'2012-12-10',
'2012-24-10'
);
*/
function getMyDateFormat($date_array){
$days = array();
$year = '';
$month = '';
sort($date_array);
if(count($date_array)>0){
foreach($date_array as $row)
{
$days[] = date('d',strtotime($row));
$year = date('Y',strtotime($row));
$month = date('M',strtotime($row));
}
$new_date = $month .' '. implode(',',$days) .' '. $year;
return $new_date;
}
}

PHP Blog, need to make a good looking archives section

So! Basically I have a database with a load of blog posts, these are all sorted by a UNIX timestamp, and what I need is a way to make this code spit out headers when appropriate, so that it will output something like this:
2008
November
Title 1 - Date Goes Here
Title 2 - Date Goes Here
December
Title 3 - Date Goes Here
2009
January
Title 4 - Date Goes Here
etcetera
Here's my code so far, it works until the comparison of the year, and I still need to come up with a good way of how to make it compare months in a sensible fashion, so that January indeed comes after December, and not some ludicrous 13th month.
[code]
<?php
if ($db = new PDO('sqlite:./db/blog.sqlite3')) {
$stmt = $db->prepare("SELECT * FROM news ORDER BY date DESC");
if ($stmt->execute()) {
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
$current_year = date("Y", $row[1]);
$current_month = date("m", $row[1]);
if ($current_year > $last_year) {
echo "<h1>" . $current_year . "</h1>";
$last_year = $current_year;
}
echo "<tr>";
echo "<td align='left'><a href='view_post.php?post_id=". $row[1] ."'>" . $row['0'] . " - " . date("Y-m-d, H:i:s", $row[1]) . "</a></td>";
echo "</tr>";
}
}
} else {
die($sqliteerror);
}
?>
[/code]
With unix timestamps you could do something like (pseudo code obviously)
prev_month = null
prev_year = null
foreach results as r
new_month = date('F', r[timestamp]);
new_year = date('Y', r[timestamp]);
if(prev_month != new_month)
//display month
/if
if(prev_year != new_year)
//display year
/if
// display other info
prev_month = new_month
prev_year = new_year
/foreach
<?php
if ($db = new PDO('sqlite:./db/blog.sqlite3')) {
$stmt = $db->prepare("SELECT * FROM news ORDER BY date DESC");
if ($stmt->execute()) {
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
$current_year = date("Y", $row[1]);
$current_month = date("n", $row[1]); # n instead of m
if ($current_year > $last_year) {
echo "<h1>" . $current_year . "</h1>";
echo "<h2>" . $current_month . "</h2>";
$last_year = $current_year;
$last_month = $current_month;
}
elseif ($current_month > $last_month) {
echo "<h2>" . $current_month . "</h2>";
$last_month = $current_month;
}
echo "<tr>";
echo "<td align='left'><a href='view_post.php?post_id=". $row[1] ."'>" . $row['0'] . " - " . date("Y-m-d, H:i:s", $row[1]) . "</a></td>";
echo "</tr>";
}
}
} else {
die($sqliteerror);
}
?>
I did not test it.
Idea:
If the year changes, also the month changes.
The check for the next month happens only if there is not a change of the year, which is the only case where lastmonth might be bigger than currentmonth.
I would be tempted to do this in two steps, separating the database fetching from the display/html logic, for example:
<?php
//snip
//make big array of archive
$archive = array();
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
$year = date("Y", $row[1]);
$month = date("m", $row[1]);
if (!isset($archive[$year])) {
$archive[$year] = array();
}
if (!isset($archive[$year][$month])) {
$archive[$year][$month] = array();
}
$archive[$year][$month][] = $row;
}
//snip
//loop over array and display items
?>
<?php foreach ($achive as $year => $months): ?>
<h1><?php echo $year; ?></h1>
<?php foreach ($months as $month => $posts): ?>
<h2><?php echo $month; ?></h2>
<ul>
<?php foreach ($posts as $post): ?>
<li><?php echo $post[0]; ?> etc...</li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>
<?php endforeach; ?>
You should get the years and the months in reverse order as per your SQL query. I haven't tested this, but it should be vaguely correct.

Categories