PHP Carbon Issue modify time on Daylight Saving Time (DST) - php

I have issue with Carbon liblary on PHP when modify the day (end day light saving) at UK timezone,
I'm using Carbon version: 1.31.0, PHP version: 5.6.11 on Laravel 5.5
this is my function convert to startOfHour:
public function getStartHour($timestamp)
{
$carbonDate = Carbon::createFromTimestamp($timestamp, 'Europe/London');
$startHour = $carbonDate->startOfHour()->timestamp;
return $startHour;
}
// Case 1:
// Sunday October 27, 2019 00:00:00 (am) GMT
// Sunday October 27, 2019 01:00:00 (am) (Timezone + 1 , On daylight saving)
$time = $this->getStartHour(1572134400); // 1572138000 (Issue here)
//My expected: 1572134400
// Case 2:
// Sunday October 27, 2019 00:30:00 (am) GMT
// Sunday October 27, 2019 01:30:00 (am) (Timezone + 1 , On daylight saving)
$time = $this->getStartHour(1572136200); // 1572138000 (Issue here)
//My expected: 1572134400
// Case 3:
// Sunday October 27, 2019 01:00:00 (am) UCT
// Sunday October 27, 2019 01:00:00 (am) UK (Timezone + 0)
$time = $this->getStartHour(1572138000); // 1572138000 - 01:00:00 (Ok)
// Case 4:
// Sunday October 27, 2019 01:30:00 (am) UTC
// Sunday October 27, 2019 01:00:00 (am) (Timezone + 0)
$time = $this->getStartHour(1572139800); // 1572138000 - 10:00:00 (Ok)
4 case these return same result (1572138000). It not right on the real case.
But when I use MomentJs library it converts right my expected
Here is my Js code with Moment
function getStartHour (timestamp) {
const m = moment(timestamp * 1000).tz('Europe/London');
startHour = m.clone().startOf('hour').unix()
return startHour;
}
What is different on 2 library and how can I fix PHP code return same JS code.
Thank you very much.

Related

I would like to get a date with strtotime. last fri or sat or sun on a month

I would like to get a date with strtotime.
A last Friday of a month and Saturday and Sunday if the month has sat and Sunday after last Friday.
How should I get it?
e.g. Aug 2021.
LastFriDay = 27 28 =sat 29 = sun.
I want to fetch “29. Aug”
e.g. July 2021.
LastFriday = 30 31 = sat. 1.Sep = sun
Then I want to fetch 31.Aug.
e.g Sep 2022
LastFriday = 30. 1.Oct = sat
Then The date should be 30.sep
$friOrSatOrSun = date("Y-m-d", strtotime("last fri of this month", strtotime($a_certain_day_of_month)));
Is there a good way to do that?

Change UTC0 to UTC +1/+2

I got a timestamp from my SQL-database: $DBdata = '2019-10-10 12:25:59', this date is UTC+0. Well i live in Denmark where we have the following UTC.
Central EU time winter (UTC+1)
Central EU summertime (UTC+2)
These UTC's changes from summer to winter different dates each year.
Summer time
• 2019 - The night between Saturday 30 March and Sunday 31 March
• 2020 - The night between Saturday 28 March and Sunday 29 March
• 2021 - The night between Saturday, March 27 and Sunday, March 28
• 2022 - The night between Saturday 26 March and Sunday 27 March
• 2023 - The night between Saturday, March 25 and Sunday, March 26
Winter time
• 2019 - The night between Saturday, October 26 and Sunday, October 27
• 2020 - The night between Saturday, October 24 and Sunday, October 25
• 2021 - The night between Saturday, October 30 and Sunday, October 31
• 2022 - The night between Saturday 29 October and Sunday 30 October
• 2023 - The night between Saturday 28 October and Sunday 29 October
Would it be possible to make an if-statement that changes these UTC's, with the right +1/+2?
Maybe something like this:
$Winter= gmdate('Y-m-d H:i:s', strtotime("WinterUTC"));
$Summer= gmdate('Y-m-d H:i:s', strtotime("SummerUTC"));
if (($$DBdata>= $Winter) && ($$DBdata<= $Summer)){
$gmt_dateWinter = gmdate('Y-m-d H:i:s', strtotime($date + '+ 2 hours') );
}else{
$gmt_dateSummer = gmdate('Y-m-d H:i:s', strtotime($date + '+ 1 hours') );
}
I don't know if this even is a smart way to do this. If there is another more smart way to do it please lead me in another direction.
Thanks!
With the DateTime class you can easy convert a date/time to any other time zone.
function convertTimeZone($strDateTime, $sourceTimeZone, $targetTimeZone){
return date_create($strDateTime, new DateTimeZone($sourceTimeZone))
->setTimeZone(new DateTimeZone($targetTimeZone))
->format('Y-m-d H:i:s');
}
example with a daylight saving time
$localTime = convertTimeZone('2019-10-10 12:25:59', 'UTC', 'Europe/Copenhagen');
echo $localTime."<br>";
returns:
2019-10-10 14:25:59
example wintertime
$localTime = convertTimeZone('2019-02-10 12:25:59', 'UTC', 'Europe/Copenhagen');
echo $localTime."<br>";
returns:
2019-02-10 13:25:59
Note: Solutions based on stringtotime are not recommended because of known issues and limitations on some systems.
You can use gmdate and date("I") to generate the date considering the timezone:
gmdate: Format a GMT/UTC date/time
$DBdata = '2019-10-10 12:25:59';
$timezone = +2; // (GMT +2:00) CEST (European Summer Time)
$GMdate = gmdate("Y-m-d H:i:s", strtotime($DBdata) + 3600*($timezone + date("I")));
echo $GMdate;
returns:
2019-10-10 22:25:59
From the date documentation:
I (capital i) Whether or not the date is in daylight saving time: 1
if Daylight Saving Time, 0 otherwise.
Thats simple change in php script default timezone and then display time:
https://www.php.net/manual/en/function.date-default-timezone-set.php
$time = date('H:i:s', time());
$ok = date_default_timezone_set('America/Los_Angeles');
echo $tz = date_default_timezone_get();
$h = new DateTime();
echo $h->format('H:i:s'); // curr time
$o = new DateTime($time);
echo $o->format('H:i:s'); // time

Php unix timestamp with strtotime

I start learn PHP and is very clear I make some error here, I try obtain Unix timestamp of specific hour and minutes of the day:
<?php
date_default_timezone_set('America/Argentina/Buenos_Aires');
$data = new DateTime();
$datafmt = $data->format('Y-m-d');
echo strtotime($datafmt,'18:30:00');
?>
The code return 1554951600 and is equal to:
GMT: Thursday, April 11, 2019 3:00:00 AM
Your time zone: Thursday, April 11, 2019 12:00:00 AM GMT-03:00
This is wrong, timestamp should be:
1555018200 is equal to:
GMT: Thursday, April 11, 2019 9:30:00 PM
Your time zone: Thursday, April 11, 2019 6:30:00 PM GMT-03:00
What I doing wrong?
Fixed!
echo strtotime($datafmt. '18:30:00');
, instead . that is my error!
You do not need strtotime() at all. DateTime class is a replacement and is more powerful. Just pass the time to the constructor or set it with the method setTime()
<?php
date_default_timezone_set('America/Argentina/Buenos_Aires');
$data = new DateTime('18:30:00');
// Alternative ways to set the time of the DateTime object
// $data->setTime('18', '30', '00');
// $data->setTime(...explode(':', '18:30:00'));
$datafmt = $data->format('U'); // U means UNIX timestamp
echo $datafmt;

Round Timestamp to a specific hour

I have a timestamp say 1512070200 which translates to November 30, 2017 7:30:00 PM GMT or December 1, 2017 01:00:00 AM GMT+05:30 in IST.
I want to be able to subtract the time that has passed on that day and revert back to the time at 12:00:00 AM.
For example
If i get a timestamp of 1512978955 which is December 11, 2017 7:55:55 AM GMT I want the output to be 1512950400 which is December 11, 2017 12:00:00 AM GMT.
There is no fixed amount of hours that can be subtracted from the timestamp, instead it would be a variable amount depending on the time that has passed for that particular day so it could be 1 millisecond or 1 second or 1 minute or 1 hour since 12:00:00 AM.
One way would be to convert the timestamp to a date and then break into it's constituent parts so that you can use mktime to generate the date at midday
$ts=1512070200;
$y=date('Y',$ts);
$m=date('m',$ts);
$d=date('d',$ts);
$date=date('Y-m-d H:i:s',mktime(12,0,0,$m,$d,$y));
echo date('Y-m-d H:i:s',$ts).' -> '.$date;
which outputs
2017-11-30 19:30:00 -> 2017-11-30 12:00:00
or, if the output date needs to be as shown use
$format=DATE_COOKIE;
$ts=1512070200;
$y=date('Y',$ts);
$m=date('m',$ts);
$d=date('d',$ts);
$date=date($format,mktime(12,0,0,$m,$d,$y));
echo date($format,$ts).' -> '.$date;
#Thursday, 30-Nov-17 19:30:00 GMT -> Thursday, 30-Nov-17 12:00:00 GMT
Even easier is to use noon as shown by #splash58
echo date( $format, strtotime( 'noon', $ts ) );
You can set noon time to DateTime object
$ts=1512070200;
$date = new DateTime();
$date->setTimestamp($ts);
$date->modify('noon');
echo $date->format(DATE_COOKIE); // Thu, 30 Nov 2017 12:00:00 +0000
demo

Parsing dates with inconsistent formats in PHP

I have two queries, both related to dates.
1) I have dates in these formats, which I'm looking to normalise into the same format before saving into a database:
Saturday 26 July
Monday 28 - Wednesday 30 July
July 24th, 2014
Thu 4 Sep
Thu 28 Aug — Fri 19 Sep
24-07-2014
Single days are quite easy to work out using strtotime(), but ranges of dates are a bit more tricky.
This, for example, doesn't work:
$dateString = "Monday 28 - Wednesday 30 July";
if (strpos($dateString, "-")) {
$datePieces = explode("-", $dateString);
$startDate = strtotime($datePieces[0]);
$endDate = strtotime($datePieces[1]);
} else {
$startDate = strtotime($dateString);
$endDate = strtotime($dateString);
}
echo '<pre>';
echo date('d F Y', $startDate);
echo '<br/>';
echo date('d F Y', $endDate);
Because the month is only on one side of the explode(), doing it this way returns:
01 January 1970
30 July 2014
2) I need a way of working out what year the date is (it will always be in the future). Something along the lines of:
if (the month in the date string has elapsed) {
the year of the date is this year + 1
}
As long as each source provides you with a consistent format you can use DateTime() and DateTime::createFromFormat() to process the dates for you.
//Saturday 26 July
$date = DateTime::createFromFormat('l j F', 'Saturday 26 July');
//July 24th, 2014
$date = new DateTime('July 24th, 2014');
//Thu 4 Sep
$date = DateTime::createFromFormat('D j M', 'Thu 4 Sep');
//Thu 28 Aug — Fri 19 Sep
list($start, $end) = explode(' - ', 'Thu 28 Aug — Fri 19 Sep');
$start = DateTime::createFromFormat('D j M', $start);
$end = DateTime::createFromFormat('D j M', $end);
//24-07-2014
$date = new DateTime('24-07-2014');
I'm going to leave handling Monday 28 - Wednesday 30 July to you since you'll need to do a little more work to get the month from the second date and apply it to the first. But this should show you how to go about this.

Categories