Week number unique sortable integer id - php

My question is about programming philosophy, I give an example in PHP language but can be asked in any programming language:
If I have to give an unique sortable integer ID to a day, I can use 'Ymd' format
If I have to give an unique sortable integer ID to a month, I can use 'Ym' format
If I have to give an unique sortable integer ID to a week, I cannot use 'YW' format
Because of 2017-01-01 and 2017-12-31 will return the same week ID:
$date1 = DateTime::createFromFormat('Y-m-d', '2017-01-01');
$date2 = DateTime::createFromFormat('Y-m-d', '2017-12-31');
echo $date1->format('YW').' '.$date2->format('YW');
// returns 201752 201752
So I can use the first day ID of the week as unique sortable integer ID week but there is maybe a simpler way to solve it ? A better practice ?

You can use o instead:
echo $date1->format('oW').' '.$date2->format('oW');
//201652 201752
o ISO-8601 week-numbering year. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)
http://php.net/manual/en/function.date.php

You've to be aware when using week numbers with years. There is already a contribution note at php.net for this scenario 6 years back. Have a look here, Hope this will help you understand clearly :)
Reason:
Y is year from the date
o is ISO-8601 year number
W is ISO-8601 week number of year
$date1 = DateTime::createFromFormat('Y-m-d', '2017-01-01');
$date2 = DateTime::createFromFormat('Y-m-d', '2017-12-31');
echo $date1->format('YW').' '.$date2->format('YW');
echo PHP_EOL;
echo $date1->format('oW').' '.$date2->format('oW');
DEMO: https://3v4l.org/sMKAF

Related

How to calculate months between two dates including the starting date month?

I'm trying to apply the straight line deprecation for this, I've two date starting date 2018-09-17 (YYYY-MM-DD) ending date 2018-12-30. I need answer in months which is 4 not 3 because, it give me 3.
I've tried starting date 2018-09-01 and ending date 2019-01-01. It give me correct answer 4 what I want.
It give me answer 4
$d1 = new DateTime("2018-09-01");
$d2 = new DateTime("2019-01-01");
echo $d1->diff($d2)->m . " Months";
I need answer 4 for these two date
2018-17-09 to 2018-30-12
Is there any way to get the answer 4 in months including the starting date. I am getting the answer 4 from these date (2018-09-01) to (2019-01-01). In short, I want to include the current date month.
You can use Carbon:
use \Carbon\Carbon;
$from = Carbon::createFromFormat('Y-d-m', '2018-17-09');
$to = Carbon::createFromFormat('Y-d-m', '2018-30-12')->addMonth();
return $to->diffInMonths($from);
Live demo here
You can easily use format method and pass "n" to it this will get the month as a numeric value then you can define your logic.
An example:
$date1 = (new Datetime("2018-09-17"))->format("n");
$date2 = (new Datetime("2018-12-30"))->format("n");
echo $date2 - $date1 + 1;

PHP: How to know if a date is in the current month?

I need to know if a date is in the current month.
Examples:
If the date is 2018-06-30 and current month is June (06), then true.
If the date is 2018-07-30 and current month is June (06), then false.
I have a list of dates with more than 1000 dates and I want to show or colorize only the dates that belongs to a current month.
You can do it all on one line. Basically convert the date in question to a PHP time, and get the month.
date('m',strtotime('2018-06-30' )) == date('m');
Using the date() function, if you pass in only the format, it'll assume the current date/time. You can pass in a second optional variable of a time() object to use in lieu of the current date/time.
I hope this helps -
$date = "2018-07-31";
if(date("m", strtotime($date)) == date("m"))
{
//if they are the same it will come here
}
else
{
// they aren't the same
}
As an alternative you could use a DateTime and for the format use for example the n to get the numeric representation of a month without leading zeros and use Y to get the full numeric representation of a year in 4 digits.
$d = DateTime::createFromFormat('Y-m-d', '2018-06-30');
$today = new DateTime();
if($d->format('n') === $today->format('n') && $d->format('Y') === $today->format('Y')) {
echo "Months match and year match";
}
Test
PHP doesn't implement a date type. If you are starting with a date/time and you know that your you are only dealing with a single timezone, AND you mean you want the current month in the curent year
$testdate=strtotime('2018-06-31 12:00'); // this will be converted to 2018-07-01
if (date('Ym')==date('Ym', $testdate)) {
// current month
} else {
// not current month
}

how do I add a date with a number?

I have this date: 1348-10-11 and I have this number: 1438438368. Now I want to know how can I plus them ? like this:
(1348-10-11) + 1438438368 = 1394-5-10 = current date as [Solar]
1348-10-11: the base of Solar date in TIMESTAMP. It is also equal with 1970-01-01 (as Gregorian)
1438438368: Total seconds of 1348-10-11 till now.
anyway for converting {Gregorian date} to {Solar date} I need to add a date with a number, Is it possible ?
Use date() and strtotime() to convert date to timestamp then combine both.
$time = strtotime("1348-10-11") + 1438438368;
echo date("Y-m-d", $time); // Current date
Here is a demo.

Get the "Right" Year of a Certain Date with PHP DateTime

I was trying to transform a date "YYYY/MM/DD" into "YYYY/WW" format, so I can store the weekly aggregation data, which has a structure below
aggre_date(YYYY/WW) value id
But I found a nasty problem
$dateTime = new DateTime("2014-12-30");
echo $dateTime->format("Y-W")."\n";
$dateTime = new DateTime("2014-01-01");
echo $dateTime->format("Y-W")."\n";
The result is exactly same 2014-01, but the former should be 2015-01.
Is there any way to improve my weekly aggregation data design or to get the "right" year?
You need to use o for the ISO year:
ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)
$dateTime = new DateTime("2014-12-30");
echo $dateTime->format("o-W")."\n";
$dateTime = new DateTime("2014-01-01");
echo $dateTime->format("o-W")."\n";
2015-01
2014-01
Demo

Can't get previous month from DateTime in PHP- Is this a (pretty big) bug?

I need to create functions in PHP that let me step up/down given datetime units. Specifically, I need to be able to move to the next/previous month from the current one.
I thought I could do this using DateTime::add/sub(P1M). However, when trying to get the previous month, it messes up if the date value = 31- looks like it's actually trying to count back 30 days instead of decrementing the month value!:
$prevMonth = new DateTime('2010-12-31');
Try to decrement the month:
$prevMonth->sub(new DateInterval('P1M')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('-1 month')); // = '2010-12-01'
$prevMonth->sub(DateInterval::createFromDateString('+1 month')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('previous month')); // = '2010-12-01'
This certainly seems like the wrong behavior. Anyone have any insight?
Thanks-
NOTE: PHP version 5.3.3
(Credit actually belongs to Alex for pointing this out in the comments)
The problem is not a PHP one but a GNU one, as outlined here:
Relative items in date strings
The key here is differentiating between the concept of 'this date last month', which, because months are 'fuzzy units' with different numbers of dates, is impossible to define for a date like Dec 31 (because Nov 31 doesn't exist), and the concept of 'last month, irrespective of date'.
If all we're interested in is the previous month, the only way to gaurantee a proper DateInterval calculation is to reset the date value to the 1st, or some other number that every month will have.
What really strikes me is how undocumented this issue is, in PHP and elsewhere- considering how much date-dependent software it's probably affecting.
Here's a safe way to handle it:
/*
Handles month/year increment calculations in a safe way,
avoiding the pitfall of 'fuzzy' month units.
Returns a DateTime object with incremented month/year values, and a date value == 1.
*/
function incrementDate($startDate, $monthIncrement = 0, $yearIncrement = 0) {
$startingTimeStamp = $startDate->getTimestamp();
// Get the month value of the given date:
$monthString = date('Y-m', $startingTimeStamp);
// Create a date string corresponding to the 1st of the give month,
// making it safe for monthly/yearly calculations:
$safeDateString = "first day of $monthString";
// Increment date by given month/year increments:
$incrementedDateString = "$safeDateString $monthIncrement month $yearIncrement year";
$newTimeStamp = strtotime($incrementedDateString);
$newDate = DateTime::createFromFormat('U', $newTimeStamp);
return $newDate;
}
Easiest way to achieve this in my opinion is using mktime.
Like this:
$date = mktime(0,0,0,date('m')-1,date('d'),date('Y'));
echo date('d-m-Y', $date);
Greetz Michael
p.s mktime documentation can be found here: http://nl2.php.net/mktime
You could go old school on it and just use the date and strtotime functions.
$date = '2010-12-31';
$monthOnly = date('Y-m', strtotime($date));
$previousMonth = date('Y-m-d', strtotime($monthOnly . ' -1 month'));
(This maybe should be a comment but it's to long for one)
Here is how it works on windows 7 Apache 2.2.15 with PHP 5.3.3:
<?php $dt = new DateTime('2010-12-31');
$dt->sub(new DateInterval('P1M'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('-1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->sub(DateInterval::createFromDateString('+1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('previous month'));
print $dt->format('Y-m-d').'<br>'; ?>
2010-12-01
2010-11-01
2010-10-01
2010-09-01
So this does seem to confirm it's related to the GNU above.
Note: IMO the code below works as expected.
$dt->sub(new DateInterval('P1M'));
Current month: 12
Last month: 11
Number of Days in 12th month: 31
Number of Days in 11th month: 30
Dec 31st - 31 days = Nov 31st
Nov 31st = Nov 1 + 31 Days = 1st of Dec (30+1)

Categories