Unoffical empeg BBS

Quick Links: Empeg FAQ | RioCar.Org | Hijack | BigDisk Builder | jEmplode | emphatic
Repairs: Repairs

Topic Options
#367762 - 22/10/2016 03:09 PHP: Extract the timezone offset that is baked into a string
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
I could do this myself with string parsing, but I don't wanna. Seeing all the timezone functions in PHP makes me think that there has gotta be a built-in function for this. But all my google searches are pointing me to the things that don't work (see below of list of things I tried).

I have a string I obtained from someplace. String is in the following format:

2016-11-05T16:00:00-0400

This string will always represent a calender event that might occur anywhere on the planet. For example, the one above occurs in Ohio at 4pm.

The part I am concerned about is that "-0400" offset that is baked into the string already. I wanna take this string and do the necessary conversion which converts that string above into a valid GMT string with no offset at all. In other words:
- That string above is saying "Event is at 4pm Ohio time". Ohio time, at that time of year, is 4 hours short of GMT time."
- In the end I want to convert that time to GMT but the standard functions are all ignoring that baked-in offset and instead they are all using the PHP server's local timzone offset instead.
Examples of things that did NOT work when I tried them:
$timeZoneOffsetString = date("O", strtotime($datetime));
$timeZoneOffsetSeconds = (int)date("Z", strtotime($datetime));
$timezoneAbbr = date("T", strtotime($datetime));
$timezoneString = date("e", strtotime($datetime));

All of those thing gave me the local server offset, not the -4hour offset that was baked into the string.

Is there a one-liner to either do the conversion entirely, or at the very least, will extract that offset so that I can do the conversion myself without having to do a string parse?

I've experimented with timezone_offset_get but that requires I know the timezone already. I've looked at "GMTDATE" but that seems just like "date" above but assuming the server is in GMT or something. I could be using that one wrong though.

Anyone know the solution to this?
_________________________
Tony Fabris

Top
#367763 - 22/10/2016 04:41 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
Hm. If nobody knows, I may resort to string parsing. I managed to look up some data which tells me (I think) that if the string matches GMT exactly that it will then display +0000 at the end. Meaning, the string format will always be a certain way and will be relatively reliable. So I could always check the -5th spot for a + or a -, and then get spots -4-3 for the hour and -1 -2 for the minute, and I'd have it.

So this is do-able with parsing, but it's just nagging me that PHP should have a built-in function for it and I'm just not getting the google-fu right on it.
_________________________
Tony Fabris

Top
#367764 - 22/10/2016 07:27 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
I'm trying to do the string parsing thing but it's getting super weird. I have all the values and calculations correct but then shit it comes time to actually USE the values then things get wonky, like the integer I'm adding won't add and says that its GETTYPE is NULL even though I can literally print out its (correct) value on the prior line.
_________________________
Tony Fabris

Top
#367765 - 22/10/2016 07:30 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
Awfuck I just found my bug.

$timezoneOffsetSeconds
$timeZoneOffsetSeconds

Both of those things highlight green when I double-click on either one in Notepad++ so I was assuming it was only highlighting case sensitivity matches. It wasn't. The syntax highlight is case insensitive.
_________________________
Tony Fabris

Top
#367766 - 22/10/2016 07:37 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
But still I'm having this weird issue:

This line of code:
Code:
strftime("%Y%m%dT%H%M%SZ", strtotime($datetime));


Produces unexpected output based on inputs:
Code:
$datetime:    2016-11-05T16:00:00-0400
Output:       20161105T130000Z

$datetime:    2017-01-27T18:00:00-0800
Output:       20170127T180000Z

$datetime:    2017-09-22T17:00:00-0500
Output:       20170922T150000Z
_________________________
Tony Fabris

Top
#367767 - 22/10/2016 08:12 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
My final working code. You will see why I wanted a PHP one-liner for this:



Code:
				// Use SongKick's fucked up DateTime field, which is NOT GMT time but rather the local concert time followed by a UTC OFFSET value.
				$datetime = $fullShowDetail->start["datetime"];
				
				// Fail out if there isn't a show time at all.
				if ("" == $datetime) 
				{
					if ($debugprints==true) { echo("No datetime found in show information. Fill out your event times! Failing out of program.<br>"); }
					die(" ");
				}
				
				// Obtain the timezone offset number out of the datetime string.
				// Datetime string will resemble this, with the offset baked in at the end (always 4 digits, always with a + or -, even if the number is 0000):
				//          2016-11-05T16:00:00-0400
				// TODO: Find out if there is a PHP one-liner that does all this crap below without me having to do the bullshit parsing.
				// I tried to find one but they all gave me the local server's timezone offset rather than the offset baked into the sting.
				$timezoneOffsetString = substr($datetime, -5);
				// (Last 5 characters of string are the sign and the time offset in HHMM format such as -0400 or +1200 or +0000)

				// Make sure we actually got 5 characters
				if ( 5 != strlen($timezoneOffsetString) )
				{
					if ($debugprints==true) { echo("Problem parsing timezone offset out of DateTime string. Length of string was not 5. Failing out of program.<br>"); }
					die(" ");
				}
				
				// Get the sign character of the offset and validate it.
				$timezoneOffsetSign = substr($timezoneOffsetString, 0, 1);
				if ($timezoneOffsetSign != "-" and $timezoneOffsetSign != "+")
				{
					if ($debugprints==true) { echo("Problem parsing timezone offset out of DateTime string. Couldn't find plus or minus sign. Failing out of program.<br>"); }
					die(" ");
				}
				
				//Validate each of the digits to make sure it's the kind of string we want (last 4 characters of the offset string must all be digits)
				if (false==ctype_digit(substr($timezoneOffsetString, -4)))
				{
					if ($debugprints==true) { echo("Problem parsing timezone offset out of DateTime string. Offset string was not all digits. Failing out of program.<br>"); }
					die(" ");
				}

				// Now we know for sure we have a string such as "-0400" or "+1200" or "-0130" or "+0000" and we need to convert it into SECONDS.
				$timezoneOffsetSeconds = 0; // start with 0
				$timezoneOffsetSeconds +=  (int)substr($timezoneOffsetString, 1, 2) * 60 * 60;  // Hours is digit pos 1,2 times 60 minutes times 60 seconds.
				$timezoneOffsetSeconds +=  (int)substr($timezoneOffsetString, 3, 2) * 60 ;  // minutes is digit pos 3,4 times times 60 seconds.
			
				// Now if the sign was positive then flip the seconds to negative.
				// For instance an offset of -0400 means that we need to ADD 4 hours to our time to get back to a GMT number
				// whereas with an offset of +0400 means that we need to SUBTRACT 4 hours to our time to get back to a GMT number
				if ($timezoneOffsetSign == "+") { $timezoneOffsetSeconds = 0 - $timezoneOffsetSeconds; }
				



(Some time later...)

Code:

				// Peel the time offset off the datetime which was screwing up the strtotime function
				$strippedDatetime = substr($datetime, 0, strlen($datetime) - 5);
					
				// Use GMT time by calculating my own offset based on the offset value in the SongKick string
				$ics_file_contents .= "DTSTART:" . strftime("%Y%m%dT%H%M%SZ", $timezoneOffsetSeconds + strtotime($strippedDatetime)  ) . "\r\n";
								
				// DTEND is the time and date stampe for the end of the event.
				// Since SongKick doesn't have a show length, just add three hours to the existing
				// timestamp for the length. Since strtotime is in epoch-seconds, three hours is
				// 10800 seconds (60*60=3600 seconds in an hour, 3600*3 hours is 10800 seconds.)
				$ics_file_contents .= "DTEND:" . strftime("%Y%m%dT%H%M%SZ", $timezoneOffsetSeconds + 10800 + strtotime($strippedDatetime) ) . "\r\n";
	
_________________________
Tony Fabris

Top
#367768 - 22/10/2016 13:10 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
K447
old hand

Registered: 29/05/2002
Posts: 798
Loc: near Toronto, Ontario, Canada
Is daylight savings time a factor is this, for your purposes?

Top
#367770 - 22/10/2016 22:33 Re: PHP: Extract the timezone offset that is baked into a string [Re: tfabris]
peter
carpal tunnel

Registered: 13/07/2000
Posts: 4172
Loc: Cambridge, England
But strtotime *already* parses the timezone part of ISO8601 dates. Your problem is that strftime then formats the time using your local timezone. You want to use gmdate instead:

echo gmdate('c', strtotime("2016-11-05T16:00:00-0400"));

This actually formats the date with +00:00 for GMT, but if you were desperate to have Z instead of +00:00 (both are valid ISO8601) then just use a more complete format argument to gmdate:

echo gmdate('Ymd\THis\Z', strtotime("2016-11-05T16:00:00-0400"));

Peter

Top
#367773 - 23/10/2016 08:39 Re: PHP: Extract the timezone offset that is baked into a string [Re: peter]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31565
Loc: Seattle, WA
Gah, so is that what was happening to mangle the times all along?

I didn't know strftime was changing the time to my local time zone.

I didn't know about GMDate.

Hm. I'll experiment with this and see if it results in the exact same output as my convoluted string parsing code.
_________________________
Tony Fabris

Top