Bonkers PHP Months? - php

Here is a basic proof-of-concept script:
<?php
for($i = 1; $i < 13; $i++)
{
echo 'Using ' . $i . ' | ';
echo date('F', mktime(0,0,0,$i)) . " | ";
echo date('F', strtotime('2011-' . $i . '-01')) . "<br />";
}
And the output I get is:
Using 1 | January | January
Using 2 | March | February
Using 3 | March | March
Using 4 | April | April
Using 5 | May | May
Using 6 | June | June
Using 7 | July | July
Using 8 | August | August
Using 9 | September | September
Using 10 | October | October
Using 11 | November | November
Using 12 | December | December
What happened to February??
This is killing me as it just stopped showing February and started showing March.

You are using mktime() incorrectly.
int mktime ([ int $hour = date("H")
[, int $minute = date("i")
[, int $second = date("s")
[, int $month = date("n")
[, int $day = date("j") <------------ here
[, int $year = date("Y") <------------ and here
[, int $is_dst = -1 ]]]]]]] )
If you don't specify $day and $year, they will default to today's date.
Today is the 30th, which doesn't exist in February.
This will work:
echo date('F', mktime(0,0,0,$i,1,2011)) . " | ";

Quite simple - you're running this on the 29th, 30th, or 31st of the month. mktime(0,0,0,2) is really mktime(0,0,0,2,date('j'),date('Y')), which in the case of today would try to create February 30th 2011, which is March 2nd.

From the manual:
Arguments may be left out in order
from right to left; any arguments thus
omitted will be set to the current
value according to the local date and
time.
Thus, it sets the fifth argument to the current day (30 here). Which means it adds to the date, since 30 is an invalid day in February, and makes it march.

See this: http://www.php.net/manual/en/function.mktime.php#77490

Related

php first week number every month

Don,t think I can find this answer in this forum.
How to get the first week number in every month where month start by Monday. This month first week is 36 how to get that? Having this code. But don't work.
//get first week number in month
$month = 9;
$year = 2018;
$day = 1;
$firstday = new DateTime("$year-$month-1");
$dow = (int)$firstday->format('w');
$firstday->add(new DateInterval('P' . ((8 - $dow) % 7) . 'D'));
$weeknumber = $firstday->format('W');
echo $weeknumber ;
I think this code will do what you want. It first creates a DateTime object for the first of the month, then it moves that date forward to make it a Monday. Finally it prints the week of the year using format('W').
Edit
Updated code to print first Monday and week number for whole year
$year = 2018;
echo "Month | First Monday | Week\n";
for ($month = 1; $month <= 12; $month++) {
$firstday = DateTime::createFromFormat('Y-n-j', "$year-$month-1");
$dow = (int)$firstday->format('w');
// update to a monday (day 1)
$firstday->add(new DateInterval('P' . ((8 - $dow) % 7) . 'D'));
echo sprintf("%5d | %s | %4d\n", $month, $firstday->format('Y-m-d'), $firstday->format('W'));
}
Output:
Month | First Monday | Week
1 | 2018-01-01 | 1
2 | 2018-02-05 | 6
3 | 2018-03-05 | 10
4 | 2018-04-02 | 14
5 | 2018-05-07 | 19
6 | 2018-06-04 | 23
7 | 2018-07-02 | 27
8 | 2018-08-06 | 32
9 | 2018-09-03 | 36
10 | 2018-10-01 | 40
11 | 2018-11-05 | 45
12 | 2018-12-03 | 49

Select and Group by fixed date interval

I'm working on a big MySQL time based statistic table.
I have a fixed time range (start and end date time objects) and get an interval string in ISO-8601 interval string like P1DT6H as PHP object where the start date in the range is also the start point of the interval and also defines the timezone used for the interval.
Now I want to select all data within the given time range grouped by this interval but I can't make it work even after lot of hours :(
For example I get a time range of 2015-09-01/2015-09-06 and an interval of P1DT6H and the following example table:
TIMESTAMP | count
2015-09-01 00:00:00 | 1
2015-09-01 02:00:00 | 1
2015-09-01 04:00:00 | 1
2015-09-01 06:00:00 | 1
2015-09-01 08:00:00 | 1
2015-09-01 10:00:00 | 1
2015-09-01 12:00:00 | 1
2015-09-01 14:00:00 | 1
2015-09-01 16:00:00 | 1
2015-09-01 18:00:00 | 1
2015-09-01 20:00:00 | 1
2015-09-01 22:00:00 | 1
2015-09-03 00:00:00 | 1
2015-09-03 02:00:00 | 1
2015-09-03 04:00:00 | 1
2015-09-03 06:00:00 | 1
2015-09-03 08:00:00 | 1
2015-09-03 10:00:00 | 1
2015-09-03 12:00:00 | 1
2015-09-03 14:00:00 | 1
2015-09-03 16:00:00 | 1
2015-09-03 18:00:00 | 1
2015-09-03 20:00:00 | 1
2015-09-03 22:00:00 | 1
2015-09-05 00:00:00 | 1
2015-09-05 02:00:00 | 1
2015-09-05 04:00:00 | 1
2015-09-05 06:00:00 | 1
2015-09-05 08:00:00 | 1
2015-09-05 10:00:00 | 1
2015-09-05 12:00:00 | 1
2015-09-05 14:00:00 | 1
2015-09-05 16:00:00 | 1
2015-09-05 18:00:00 | 1
2015-09-05 20:00:00 | 1
2015-09-05 22:00:00 | 1
With that I want to have the following result:
TIMESTAMP | count
2015-09-01 00:00:00 | 12
2015-09-02 06:00:00 | 6
2015-09-03 12:00:00 | 6
2015-09-04 18:00:00 | 12
For sure the interval can be more complicated, the time range can be very big and the data table is also a big table.
This needs to handle months where nearly every month have a different amount of days incl. leap year and also dst changes where a day can have 23, 24 or 25 hours. (Means a one day interval is different than a 24 hours interval)
It would be really really helpful if someone has a solution or can me point to the right direction for that kind of problem.
Thanks!
PS: I have a script that creates SQL an expression in base of a given db column, the start, end and interval objects but it only works for very simple intervals like P1D. I don't past it here as I don't want to ping all great brains into a non working direction that I already have ;)
What I have right now but it doesn't work with mixed intervals.
Examples:
Timezone handling:
if ($db->getTimezone()->getName() !== $start->getTimezone()->getName()) {
$col = 'CONVERT_TZ(' . $col
. ', ' . $this->quote($this->getTimezone()->getName())
. ', ' . $this->quote($start->getTimezone()->getName())
. ')';
}
P1M:
$m = ($interval->y * 12) + $interval->m;
if ($m) {
if ($m > 1) {
$mod = $start->format('Ym') % $m;
$mod = $mod ? ' + ' . $mod : '';
$expr = 'EXTRACT(YEAR_MONTH FROM ' . $col . ')';
$expr = $mod ? '(' . $expr . $mod . ')' : $expr;
$expr = ' - INTERVAL ' . $expr . ' % ' . $m . ' MONTH';
$sqlIntervalMonth = $expr;
}
$sqlIntervalDay = ' - INTERVAL DAY(' . $col . ') - 1 DAY';
if ($start->format('d') > 1) {
$sqlIntervalDay .= ' + INTERVAL ' . ($start->format('d') - 1) . ' DAY';
}
}
P1D:
$d = $interval->d;
if ($d) {
$days = $start->diff(new DateTime('0000-00-00'))->days;
$mod = $days % $d;
$mod = $mod ? ' + ' . $mod : '';
$expr = 'TO_DAYS(' . $col . ')';
$expr = $mod ? '(' . $expr . $mod . ')' : $expr;
$expr = ' - INTERVAL ' . $expr . ' % ' . $d . ' DAY';
$sqlIntervalDay = $expr;
}
EDIT 1: pointed out timezone, dst and leap year requirement.
EDIT 2: added PHP snippets
One idea is to convert the value of the time stamp to seconds and then round that value to the appropriate interval (36 hours in your case). Something like this:
select min(timestamp) as timestamp, sum(count)
from t
group by floor(to_seconds(timestamp) / 60 * 60 * 36) -- * 60 * 60 * 36
order by timestamp;
This uses the min() of the datetime value, because you seem to have that value in the table. Alternatively, you can convert the rounded seconds back to a datetime value.
This is the closest I could get. Though time periods without any data will not be represented (don't know if that is a problem or not):
select yourTimestamp,sum(yourCount)
from
(
select t.yourTimestamp,t.yourCount,
'2015-09-01' + interval (36*60)*(floor(timestampdiff(MINUTE,'2015-09-01',t.yourTimestamp)/(36*60))) minute as recordGrpTime
from t
where t.yourTimestamp between '2015-09-01' and '2015-09-06'
) t
group by recordGrpTime;

retrieve mysql data using 3 columns

for example i have 3 fields in my search DAY, MONTH, YEAR
the user must select it independently or all together like
DAY/MONTH
DAY/YEAR
MONTH/YEAR
DAY/MONTH
DAY/MONTH/YEAR
inputs: day month year
method: GET
select must search in any column with all combinations
table
id | day | month | year
---------------------------------------
1 | 10 | jan | 2013
2 | 25 | jun | 2013
3 | 02 | jan | 2015
SELECT * FROM mytable WHERE day = $day or month = $month or year = $year;
if my month = jan should return 1 and 3
if my my day = 10 and year = 2013 should return 1
and so on
it doesn't work... it only matches with one column
You are probably facing a problem with NULL values. This may be what you want:
SELECT *
FROM mytable
WHERE ($day is null or day = $day) and
($month is null or month = $month) and
($year is null oryear = $year);
This assumes that "missing" values are NULL. You may have some other representation (say an empty string), in which case change the logic accordingly.

How to insert an irregular calendar events in mysql using PHP

I'm trying to enter events that occur over the same interval (Weekly, Bi-Monthly, Quarterly, Yearly). The script I'm showing is that of monthly..(If I can get that right, I can make an adaptation for the other intervals).
Events are entered along with the correct Week Number in which they occur.. But the following problem occur:
--- How can I make sure that months that has less than 31 days do not have events entered for them ?
----- If an event occurs on every 1st and 3rd friday (or whichever one), or last thursday of the month. How can I tweak the script below do do that.
Thank you.
A Sample of what I'm getting from mysql, when I insert...
+----+------+------+------------------+-----------+------------+----------+
| day| month| year | eventname | eventtime | eventplace | eventweek|
+----+------+------+------------------+-----------+------------+-----------
| 1 | 2 | 2011 | Social Gathering | 12PM | Room | 05 |
| 8 | 2 | 2011 | Social Gathering | 12PM | Room | 06 |
| 15| 2 | 2011 | Social Gathering | 12PM | Room | 07 |
| 22| 2 | 2011 | Social Gathering | 12PM | Room | 08 |
| 29| 2 | 2011 | Social Gathering | 12PM | Room | 09 |
+----+------+------+------------------+-----------+------------+----------+
PHP Code
<?php
if(isset($_POST['myform'])){
$day = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31');
$month = array('1','2','3','4','5','6','7','8','9','10','11','12');
$year = array('2011', '2012','2013', '2014', '2015', '2016');
$startday = mysql_real_escape_string($_POST['day']);
$eventplace = mysql_real_escape_string($_POST['eventplace']);
$eventname = mysql_real_escape_string($_POST['eventname']);
$eventtime = mysql_real_escape_string($_POST['eventtime']);
for($i=0; $i<count($year); $i++){
for($j=0; $j<count($month); $j++){
for($k=$startday; $k<count($day); $k = $k + 7){
$date = mktime(0,0,0,$month[$j],$k,$year[$i]);
$week = date('W', $date) ;
$query = mysql_query(" INSERT INTO caldemo(day, month, year, eventname, eventtime, eventplace, eventweek)
VALUES ('".intval($k)."', '".intval($month[$j])."', '".intval($year[$i])."', '".$eventname."', '".$eventtime."', '".$eventplace."', '".intval($week)."' )")or die(mysql_error()) ;
}
}
}
}
?>
Simple php solution:
function setDatePeriod($months=1, $date='')
{
if(!$date) $date = date('Y-m-d');
$d = new DateTime( $date );
$d->modify( "+{$months} months" );
return $d->format('Y-m-d');
}
echo setDatePeriod(3);

How come certain values are not being displayed using PHP foreach loop?

I am working on a website using a PHP script to display information formatted a certain way from a MySQL database. I want the date values from the database (which are formatted as YYYY-MM-DD) to be displayed as Month YYYY. The perhaps-not-efficient-enough code I'm using to display the months as words is below:
foreach($monthstart as $monthnext)
{
preg_match("/[[0-9][0-9]]*/", $monthnext, $startmonthfull);
}
echo "<b>Duration: </b>";
foreach($startmonthfull as $which)
{
if($which == 01)
{
echo "January ";
}
elseif($which == 02)
{
echo "February ";
}
elseif($which == 03)
{
echo "March ";
}
elseif($which == 04)
{
echo "April ";
}
elseif($which == 05)
{
echo "May ";
}
elseif($which == 06)
{
echo "June ";
}
elseif($which == 07)
{
echo "July ";
}
elseif($which == 08)
{
echo "August ";
}
elseif($which == 09)
{
echo "September ";
}
elseif($which == 10)
{
echo "October ";
}
elseif($which == 11)
{
echo "November ";
}
elseif($which == 12)
{
echo "December ";
}
}
foreach($year as $printyear)
{
echo $printyear;
}
This code displays the month and year for the first part. This displays perfectly on the webpage, unless the month is August or September. If the month is August or September, nothing gets printed for that part, so instead of "August 2005") you'd get "2005".
The August and September elseif statements are formatted (from what I can tell) exactly the same as the others so I have no idea why these values are not printing. If I simply ask it to print the $which value, it prints as either 08 or 09 and the values look proper in the database. I'm really hoping there is something simple I am overlooking that someone will quickly point out because I have been banging my head against the wall for quite some time with this issue.
(I'm not sure if it makes any difference, but I am using the Jumi plugin in Joomla which allows users to add custom code in a Joomla page to develop this section of the website.)
EDIT: I just removed the 0s from 08 and 09 and now they all display properly. So I guess now the question is why did this fix the problem when in the variable that is being checked the values are 08 and 09?
Also, sorry for solving it so shortly after posting a question.
You're using Joomla! 1.5, right? Why not letting Joomla! do that work:
if (!defined('MY_DATE_FORMAT'))
define('MY_DATE_FORMAT', '%B %Y');
jimport('joomla.utilities.date');
$mysql_date = '2009-08-01';
$jdate = new JDate($mysql_date);
echo $jdate->toFormat(JText::_(MY_DATE_FORMAT));
As a side benefit, he will even translate the month into the right/used language if you ever choose to translate your website.
Let MySQL format the date with date_format and return it to PHP in the way you want. This way, you don't need to do any manipulation with PHP.
Here is an example query you would make to MySQL:
select date_format(date_column, '%M %Y') as formatted_date from table;
Where:
date_column is the original table column that stores the date you want to format,
%M means you want the month name spelled out in full ('January', 'February', 'March', etc), and
%Y means you want the 4-digit year.
A field in date_column with value of '2009-09-17' will return as 'September 2009'
For example, the following output displays the original date_column values along with the date_format() values:
+-------------+----------------+
| date_column | formatted_date |
+-------------+----------------+
| 2009-09-11 | September 2009 |
| 2009-09-02 | September 2009 |
| 2009-09-01 | September 2009 |
| 2009-08-31 | August 2009 |
| 2009-08-04 | August 2009 |
| 2009-08-01 | August 2009 |
| 2009-07-11 | July 2009 |
| 2009-07-01 | July 2009 |
| 2009-06-30 | June 2009 |
| 2009-06-20 | June 2009 |
| 2009-06-09 | June 2009 |
| 2009-05-26 | May 2009 |
| 2009-05-09 | May 2009 |
| 2009-05-08 | May 2009 |
| 2009-04-22 | April 2009 |
| 2009-04-20 | April 2009 |
| 2009-04-19 | April 2009 |
| 2009-03-05 | March 2009 |
| 2009-03-04 | March 2009 |
| 2009-03-03 | March 2009 |
+-------------+----------------+
yes you have to erase the leading 0 on your condition or php would interpret it as octal, you code in better way
foreach($monthstart as $monthnext){
preg_match("/[[0-9][0-9]]*/", $monthnext, $startmonthfull);
}
echo "<b>Duration: </b>";
$monthArray = array(
1 => 'January',
2 => 'February',
3 => 'March',
4 => 'April',
5 => 'May',
6 => 'June',
7 => 'July',
8 => 'August',
9 => 'September',
10 => 'October',
11 => 'November',
12 => 'December');
foreach($startmonthfull as $which){
echo($monthArray[$which] . " ");
}
foreach($year as $printyear)
{
echo $printyear;
}
Numbers in php starting with a 0 are considerd octal. This could be the reason why. Put "" around them.
But please read the link in the comment to your question. This is considered to be an anti-pattern.
This way ensures it works for all locales and it uses things that were written for you a long, long time ago.
mysql:
select UNIX_TIMESTAMP(time) as unixtime from table;
php:
$formatted_time = date('F Y', $row['unixtime']);
It also allows you to reuse the $row['unixtime'] variable so you can format it different ways or reuse it without calling mysql again in the same script. You could even provide a different string from a constant or from some user configurable options to the date function.
PHP has several functions (and as of PHP 5.3, the DateTime type) to deal with times and dates.
For instance, in PHP 5.x:
$mytime = strtotime($monthstart);
// $output_date = date("F Y", $mytime);
$output_date = strftime("%B %Y", $mytime);
(strftime is included because it's generally portable across programming languages)

Categories