Repository navigation
Description
Description
I call every Monday a cronjob at 00:01. I want known the year and week from last week.
<?php
$dt = new DateTime('last week monday 00:00:01', new DateTimeZone('Europe/Berlin'));
$year = (int)$dt->format('Y');
$week = (int)$dt->format('W');
// After this, I call a second script with parameters ($year and $week) few times for different tasks
$dto = new DateTime();
$dto->setISODate($year, $week);
$fmt = new IntlDateFormatter('de_DE', IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'Europe/Berlin');
$fmt->setPattern('LLL dd');
// Hint: $dto->getTimestamp() is the date a week ago, but with current time. So its always the time its called.
$week_start = $fmt->format($dto->getTimestamp());
$dto->modify('+6 days'); // for sunday
$week_end = $fmt->format($dto->getTimestamp());
echo $week_start . ' - ' . $week_end;Resulted in this output:
Jan 23 - Jan 29
But I expected this output instead, for Timezone 'Europe/Berlin':
Jan 22 - Jan 28
The parameters $year and $week are only determined once. With these two values, the same script is called several times to create each time a graphic containing the date for the Monday and Sunday of the previous week. The script is called by a cronjob 00:01 every Monday. The graphics were created on the server at 00:01:23 and later. The script needs less than 1 second to create the graphics.
So I remove the images and call the script again ~9 o'clock and its shows me now the correct values "Jan 22 - Jan 28".
Is this a bug or am I doing something wrong here?
Because its worked for many years, but since 2024 its startet with wrong dates (one date shifted). Executed/Generated on:
✗ 03.01. wrong date for last week December.
✗ 08.01. again wrong date for first week January
✓ 15.01. shows the correct dates! "08 - 14"
✓ 22.01. shows the correct dates! "15 - 21"
✗ 29.01. again wrong date "23 - 29" must be "22 - 28"
So its strange.
Server timezone with timedatectl shows:
Local time: Mon 2024-01-29 10:53:00 CET
Universal time: Mon 2024-01-29 09:53:00 UTC
RTC time: Mon 2024-01-29 09:53:00
Time zone: Europe/Berlin (CET, +0100)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
PHP Version
PHP 8.2.15
Operating System
AlmaLinux 8.9
Activity
damianwadley commentedon Jan 29, 2024
Without putting a whole lot of thought into it, being the middle of the night here, I can at least tell you that
is wrong:
Yis the calendar year andWis the ISO week number, so mixing the two is bound to cause problems. You need to be usingofor the year instead.https://www.php.net/manual/en/datetime.format.php
I also suggest rethinking how complicated this is: I count five occurrences of "date math" going on here, and each of those carries a risk of making a mistake. Such as relying on your DST transitions always happening at 2/3am, or that the timezone in PHP always agrees with the timezone on the server, or that the PHP tzdata agrees with the ext/intl tzdata.
Anyway, if I throw a modified version of your code up on 3v4l, it calculates the 8th's "last week" correctly. https://3v4l.org/qmnTA
I suggest you add logging into your script: to see what is the exact value of $dt, of $year and $week, and of the other script's $dto before and after the
modify.Daijobou commentedon Jan 30, 2024
Thank you for the quick response. With update to PHP 8.1 and strftime was deprecated I changed to DateTime() and so from "%V" to "Y". You are right, I must instead change to "o". Thanks for this hint. However, this have nothing to do with my issue. My issue is the shifted day, not wrong years. ;)
I use this script now for 4 years and my issue starts with 2024. At least it appears now. Of course, this could also be a coincidence. In start post you can see its working (for this year) 2 of 5 times. So its not always wrong and never wrong after first call 00:01 by system/server time. Week and year are correct. I can see this because the file names contain the year and week. In summary:
This values for $year and $week are fine
$dto->setISODate($year, $week);
I don't add this line
$dto->setTimezone(new DateTimeZone('Europe/Berlin'));
because the server timezone is already 'Europe/Berlin' and its set as date_default_timezone_set() before. I will now add this as test.
So with 'Europe/Berlin' as timezone how can it be that it then shows me the 23rd as the first day for week 4, instead of 22rd? As I said, the error only seems to happen (server time) on the first day of a new week and only within the first hour. All calls from your script and mine are always correct until then. I unfortunately don't have a test server to reset the server time so I can check Monday at 00:01 several times with this script.
Example today log file was created 00:01 (REQUEST_TIME=1706569261) with correct output:
[1706396461] is $dto->getTimestamp() with "Sun Jan 28 2024 00:01:01 GMT+0100"
I will log it now for every day for hours 23, 0 and 1. I don't expect any errors here until the week changes on monday.
Sorry for the long text. :(
SakiTakamachi commentedon Jan 30, 2024
If you run that code in your environment now, what will be the result?
https://3v4l.org/O4dK7
Daijobou commentedon Jan 30, 2024
Output is
Thats for Europe/Berlin the correct result. As I said, it only makes wrong output when moving from one week to another (Sunday to Monday). The issue only happen when the server time is Monday 00:01. Probably only in the first hour of Monday. Calling the script now will always return the correct result. See start post, 3 of 5 failed. So two times it was correct.
SakiTakamachi commentedon Jan 31, 2024
@Daijobou
Could you please tell me the result of the following code?A similar phenomenon occurred when I intentionally mismatched the time zones.
Sorry, I made some mistakes in the code. I will continue to verify.
SakiTakamachi commentedon Jan 31, 2024
@Daijobou
(Just to be sure) Are you sure that cron runs at 00:01 in your time zone?
Daijobou commentedon Jan 31, 2024
Yes. All files are always created at 00:01:2x, because the script starts 00:01:01 and need ~20-30 seconds to generate a summary. After all data collected the graphics are created. Here a server log from 30.01 to 31.01 and its all fine:
2024-4 = [1705960861 - 1706479261] = Jan 22 23:01:01 - Jan 28 23:01:01 :: 30 23:01:01 [1706652061]
2024-4 = [1705878061 - 1706396461] = Jan 22 00:01:01 - Jan 28 00:01:01 :: 31 00:01:01 [1706655661]
2024-4 = [1705881661 - 1706400061] = Jan 22 01:01:01 - Jan 28 01:01:01 :: 31 01:01:01 [1706659261]
legend:
year-week = [$dto->getTimestamp() ($week_start) - $dto->getTimestamp() ($week_end)] = formated from timestamps :: created day time by REQUEST_TIME
Again:
Sequence of events:
I get (this monday) server time 00:00:01 year=2024 and week=4 and after generated data server time ~00:01:2x its called this line
I use $dto->getTimestamp() in
and get sometimes a whole shifted day. Last time created at 29.01 and get week start with 23, but 22 is right.
It seems that the script/php sometimes uses the wrong timezone when changing from Sunday to Monday? I have added setTimezone() after setISODate() and will have to wait for the coming weekly changes. Maybe this helps. But I wouldn't understand if, because the times are right, just not the days. The issue is a time difference of +24 hours, so its strange.
That's all I can really think of on the subject. If you want to add something to the log, please let me know.
SakiTakamachi commentedon Jan 31, 2024
@Daijobou
OK, I understood.
This is running at 23:01:01 UTC the previous day.
Reproducing this situation in code looks like this:
https://3v4l.org/de5CL
Get a
DateTimeobject for last Monday's 23:01:01 and format its timestamp in your timezone.In your time zone, this would be the next day, so it is moved one day into the future.
(edit)
But the irregular results are strange...
Daijobou commentedon Jan 31, 2024
I use this script since years and its working since years for every week. ;)
Since 2024 its startet with wrong output. The server (AlmaLinux 8.9) is organised by server software plesk, so maybe there is something happen, I don't know.
The server system has timezone 'Europe/Berlin' and set at begin of all scripts date_default_timezone_set($config['timezone']); the value for $config['timezone'] is never UTC and for this URL in cronjob that value is 'Europe/Berlin'.
Output for date_default_timezone_get() result in 'Europe/Berlin'.
kamil-tekiela commentedon Nov 8, 2026
I am going to close this issue. Maybe I am misunderstanding something here but I don't see any problem in the code you showed. As @damianwadley @SakiTakamachi said it's not well-written and it will cause issues like the wrong day or year, but nothing points at a problem in PHP. It's just a math/calendar problem.