time/date calculations - timezone

I have a database of users and each user has its own timezone settings.
For example, user A has GMT-05:00 , user B has GMT+1:00 , etc
I am trying to display the correct current date/time for this users using the simplest way I can find. I got to this code, which although it looks good (imho), it displays a positive difference (+5 hours) instead of negative (minus 5 hours).
Script below:
<?php
// below two lines -- info that I normally take from DB
$row['callstart'] = "1362067791"; // unixtimestamp
$userInfo['timezone'] = 'GMT-5';
echo date('Y-m-d H:i:s',$row['callstart'])."\n"; // original hour
$date = date('Y-m-d H:i:s',$row['callstart']);
$date = new DateTime($date,new DateTimeZone('GMT'));
$date->setTimezone(new DateTimeZone($userInfo['timezone']));
$row['callstart'] = $date->format('Y-m-d H:i:s');
echo $row['callstart']; // converted to GMT-5 hour
?>
Results below:
root#ssw238:/tmp# php /work/yy.php
2013-02-28 16:09:51 // that's the current GMT hour/date
2013-02-28 21:09:51 // should actually be 11:09:51 instead of 21:09:51
root#ssw238:/tmp#
Any idea where and what I am doing wrong?

This is when common sense works against us... From Wikipedia
In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed from what most people expect. In this style, zones west of GMT have a positive sign and those east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead/east of GMT.)
So the solution is
// below two lines -- info that I normally take from DB
$row['callstart'] = "1362067791"; // unixtimestamp
// reversed the sign
$userInfo['timezone'] = 'GMT+5';
echo date('Y-m-d H:i:s',$row['callstart'])."\n"; // original hour
$date = date('Y-m-d H:i:s',$row['callstart']);
$date = new DateTime($date,new DateTimeZone('GMT'));
$date->setTimezone(new DateTimeZone($userInfo['timezone']));
$row['callstart'] = $date->format('Y-m-d H:i:s');
echo $row['callstart']; // converted to GMT-5 hour

hmmm ... i rather youse this
<?php
$row['callstart'] = "1362067791";
$userInfo['timezone'] = 'GMT-5';
$orginal =date('Y-m-d H:i:s',$row['callstart']);
echo $orginal;
echo '<br/>';
$newdate=date('Y-m-d H:i:s',($orginal + strtotime(substr($userInfo['timezone'] ,3).'hours')));
echo $newdate
?>
2013-02-28 17:09:51
2013-02-28 13:22:36

Related

splitting a string into similar elements along with the values

I have a string like
$query = "date=20.10.2007&amount=400+date=11.02.2008&amount=1400+date=12.03.2008&amount=1500";
there are two variables named date and amount containing a value e.g date= 20.10.2007 and amount=400 and these two variables repeat itself with different values and each set (date & amount) are separated by '+' sign. Now i want to display this string like this:
Date Amount
20.10.2007 400
11.02.2008 1400
12.02.2008 1500
Need help
We can make judicious use of explode and preg_split here to get the output you want:
$query = "date=20.10.2007&amount=400+date=11.02.2008&amount=1400+date=12.03.2008&amount=1500";
$array = explode("+", $query);
$counter = 0;
echo "Date Amount\n";
foreach($array as $item) {
if ($counter > 0) echo "\n";
$parts = explode("&", $item);
echo preg_split("/=/", $parts[0])[1] . " ";
echo preg_split("/=/", $parts[1])[1];
$counter = $counter + 1;
}
This prints:
Date Amount
20.10.2007 400
11.02.2008 1400
12.03.2008 1500
The logic here is that we first split the query string on + to obtain components looking like:
date=20.10.2007&amount=400
Then, inside the loop over all such components, we split again by & to obtain the date and amount terms. Finally, each of these are split again on = to get the actual values.
Thanks a lot Tim Biegeleisen for your kind guidance. From your help i did it with this code below:
$str = "date=20.10.2007&amount=400+date=11.02.2008&amount=1400+date=12.03.2008&amount=1500"; $array = explode("+",$str);
$i = 0;
echo nl2br("Date Amount \n");
foreach($array as $item[$i])
{
parse_str($item[$i]);
echo $date;
echo $amount."<br>";
$i++;
}

Testing for out of hours call forwarding

I need to get a call forwarding number in place so that outside of uk office hours all incoming calls redirect to our out of hours service.
I've written this which returns a $status = 'closed';
<?php
// set the timezone
date_default_timezone_set ('Europe/London');
function checkDateValue($val, $args) {
if (($val) >= $args['min'] && ($val) <= $args['max'] ) :
return true;
else :
return false;
endif ;
}
// set min and max valuesfor hours, minutes and seconds - format HH:MM:SS
$hours = array(
'min' => '09:00:00',
'max' => '17:30:00'
);
// set min and max values bwtween 0 nd 6. 0 = sunday
$days = array(
'min' => 1,
'max' => 5
);
// store current time
$currentTime = time();
// test if the current time is in opening hours or is a weekday
$status = 'open';
if (checkDateValue(date('H:i:s', $currentTime), $hours) === false || checkDateValue(date('w', $currentTime), $days) === false) {
$status = 'closed';
}
I'm wondering if there is anything in the the php-sdk or in twiml that can handle conditional dialing based on detecting the time of day and day of the week and that also accounts for current callers timezone.
Thanks.
Twilio developer evangelist here.
There's nothing within Twilio's PHP SDK or TwiML that will do this time detection for you, you will need to write your own method (as you have done) to detect the current time and then use that to return different TwiML to perform the in hours or out of hours response.
So, you could add to your current script something like:
use Twilio\TwiML;
$response = new TwiML;
if ($status == 'closed') {
$response->say("Sorry, the office is closed right now");
} else {
$response->dial($officePhone);
}
echo $response;
I'm not sure why you would need to account for the current caller's time zone, your UK hours won't change if someone calls from France. Perhaps you could comment or update your question with a bit more detail. Otherwise, hope this helps.

Parse and change the output of a system through Powershell

initially I have to state, that I have little to no experience with powershell so far. A previous system generates the wrong output for me. So I want to use PowerShell to change this. From the System I get an output looking like this:
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^...^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')^|^N^|^LIKE^|^('6','7','8','9')^|^...^|^Y^|^NOT IN^|^('1','2','15','16','17')^|^Y^|^NOT IN^|^('18','19','20','21','22')
When you look at it, there is a starting part for each line (TEST1^|^9999^|^) followed by a1 to a-n tuples (example: Y^|^NOT IN^|^('1','2','3')^|^).
The way I want this to look like is here:
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')
TEST1^|^9999^|^N^|^LIKE^|^('4','5','6','7')
TEST1^|^9999^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')
TEST2^|^9998^|^N^|^LIKE^|^('6','7','8','9')
TEST2^|^9998^|^Y^|^NOT IN^|^('1','2','15','16','17')
TEST2^|^9998^|^Y^|^NOT IN^|^('18','19','20','21','22')
So the tuples shall be printed out per line, with the starting part attached in front.
My solution approach is the AWK equivalent in Powershell, but to date I lack the understanding of how to tackle the issue of how to deal with an indetermined number of tuples and to repeat the starting block.
I thank you so much in advance for your help!
I'd split the lines at ^|^ and recombine the fields of the resulting array in a loop. Something like this:
$sp = '^|^'
Get-Content 'C:\path\to\input.txt' | % {
$a = $_ -split [regex]::Escape($sp)
for ($i=2; $i -lt $a.length; $i+=3) {
"{0}$sp{1}$sp{2}$sp{3}$sp{4}" -f $a[0,1,$i,($i+1),($i+2)]
}
} | Set-Content 'C:\path\to\output.txt'
The data looks quite regular so you could loop over it using | as the delimiter and counting the following cells in 3s:
$data = #"
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^Y^|^NOT IN^|^('8','9','10','11','12')
TEST2^|^9998^|^Y^|^NOT IN^|^('4','5','6')^|^N^|^LIKE^|^('6','7','8','9')^|^Y^|^NOT IN^|^('1','2','15','16','17')^|^Y^|^NOT IN^|^('18','19','20','21','22')
"#
$data.split("`n") | % {
$ds = $_.split("|")
$heading = "$($ds[0])|$($ds[1])"
$j = 0
for($i = 2; $i -lt $ds.length; $i += 1) {
$line += "|$($ds[$i])" -replace "\^(\((?:'\d+',?)+\))\^?",'$1'
$j += 1
if($j -eq 3) {
write-host $heading$line
$line = ""
$j = 0
}
}
}
Parsing an arbitary length string record to row records is quite error prone. A simple solution would be processing the data row-by-row and creating output.
Here is a simple illustration how to process a single row. Processing the whole input file and writing output is left as trivial an exercise to the reader.
$s = "TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')^|^N^|^LIKE^|^('4','5','6','7')^|^Y^|^NOT IN^|^('8','9','10','11','12')"
$t = $s.split('\)', [StringSplitOptions]::RemoveEmptyEntries)
$testNum = ([regex]::match($t[0], "(?i)(test\d+\^\|\^\d+)")).value # Hunt for 1st colum values
$t[0] = $t[0] + ')' # Fix split char remove
for($i=1;$i -lt $t.Length; ++$i) { $t[$i] = $testNum + $t[$i] + ')' } # Add 1st colum and split char remove
$t
TEST1^|^9999^|^Y^|^NOT IN^|^('1','2','3')
TEST1^|^9999^|^N^|^LIKE^|^('4','5','6','7')
TEST1^|^9999^|^Y^|^NOT IN^|^('8','9','10','11','12')

Timestamp pattern

Let's assume I have the following reminder timestamp
local reminder_timestamp = "2013-12-13T00:00:00+01:00"
And I'm using the below function to return time in UTC
local function makeTimeStamp(dateString)
local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%d%d)"
local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = dateString:match(pattern)
local timestamp = os.time( {year=year, month=month, day=day, hour=hour, min=minute, sec=seconds} )
local offset = 0
if ( tzoffset ) then
if ( tzoffset == "+" or tzoffset == "-" ) then -- we have a timezone!
offset = offsethour * 60 + offsetmin
if ( tzoffset == "-" ) then
offset = offset * -1
end
timestamp = timestamp + offset
end
end
return timestamp
end
What should be the pattern above to match the reminder timestamp I mentioned earlier?
You need to use Lua's string parsing capabilities. Try a few of the techniques mentioned in the following, and if you still have issues, post specifically what is not working:
Question about splitting string and saving in several variables
Question about extracting data from a string, very similar to yours (although problem domain is GPS coordinates instead of date/time)
Question about how to do pattern matching in Lua, several good examples and links to docs
Here is the answer and the function actually works fine
pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%p])(%d%d)%:?(%d%d)"
reminder_timestamp = "2013-12-23T08:00:00+01:00"
local year, month, day, hour, minute, seconds, tzoffset, offsethour, offsetmin = reminder_timestamp:match(pattern)
Resource: http://www.lua.org/manual/5.1/manual.html#5.4.1

Parse name value pairs in csv line using shell script

I have input which looks like the following 2 lines:
TASK1,6,INITIAL,2013-01-15 19:20:40,PREPARING,2013-01-15 19:21:12,SCHEDULED,2013-01-15 19:21:13,TRANSLATING,2013-01-15 19:21:13,LOADING,2013-01-15 19:36:37,COMPLETE,2013-01-15 19:36:42
TASK2,5,INITIAL,2013-01-15 19:20:44,PREPARING,2013-01-15 19:21:13,SCHEDULED,2013-01-15 19:21:14,TRANSLATING,2013-01-15 19:36:37,TERMINAL,2013-01-15 20:28:10
I need to loop through a file with these lines and for each line calculate several time differences... i'm fine on the calculations and such, but i'm having a devil of a time trying to figure out how to parse this "variable length" string of name value pairs...
Basically the # after the Task# is the count of "statuses" followed by those statuses and their occuring time.
What i'd like to do is get one of the lines and end up with something like this having the values assigned to their respective variables. (using first line as example):
$TASK_ID=TASK1
$STATUS_COUNT=6
$INITIAL=2013-01-15 19:20:40
$PREPARING=2013-01-15 19:21:12
$SCHEDULED=2013-01-15 19:21:12
$TRANSLATING=2013-01-15 19:21:13
$LOADING=2013-01-15 19:36:37
$COMPLETE=2013-01-15 19:36:42
$TERMINAL=<NULL>
Compounding the problem is that if a task is submitted more than once it will simply append the next round of statuses to the first set meaning i could end up with an input line like:
TASK1,11,INITIAL,2013-01-15 19:20:40,PREPARING,2013-01-15 19:21:12,SCHEDULED,2013-01-15 19:21:13,TRANSLATING,2013-01-15 19:21:13,LOADING,2013-01-15 19:36:37,COMPLETE,2013-01-15 19:36:42,INITIAL,2013-01-15 20:20:40,PREPARING,2013-01-15 20:21:12,SCHEDULED,2013-01-15 20:21:13,TRANSLATING,2013-01-15 20:21:13,TERMINAL,2013-01-15 20:36:42
I this case i would want my output to be:
$TASK_ID=TASK1
$STATUS_COUNT=11
$INITIAL=2013-01-15 20:20:40
$PREPARING=2013-01-15 20:21:12
$SCHEDULED=2013-01-15 20:21:12
$TRANSLATING=2013-01-15 20:21:13
$LOADING=<NULL>
$COMPLETE=<NULL>
$TERMINAL=2013-01-15 20:36:42
I'm pretty stumped on this, can anyone help?
Thanks in advance
#!/bin/bash
# Splitting on commas, read the task ID and status count followed by all of the statuses,
# which we'll parse later.
while IFS=, read -r TASK_ID STATUS_COUNT STATUSES; do
(
# Subtly, but importantly, we put the loop body inside parentheses so each loop
# iteration runs in a sub-shell. This ensures that the $LOADING, $COMPLETE, etc.
# variables we set don't leak into future iterations.
echo "TASK_ID = $TASK_ID"
echo "STATUS_COUNT = $STATUS_COUNT"
# Convert the comma-separated string $STATUSES into an array using `read -a'.
IFS=, read -ra STATUSES <<< "$STATUSES"
# Assign the statuses to named variables. A side benefit of this is that only the
# last value of each status type is used.
for ((i = 0; i < ${#STATUSES[#]}; i += 2)); do
declare "${STATUSES[$i]}=${STATUSES[$((i+1))]}"
done
# Print each of the statuses, or <NULL> if that stage wasn't listed.
echo "INITIAL = ${INITIAL:-<NULL>}"
echo "PREPARING = ${PREPARING:-<NULL>}"
echo "SCHEDULED = ${SCHEDULED:-<NULL>}"
echo "TRANSLATING = ${TRANSLATING:-<NULL>}"
echo "LOADING = ${LOADING:-<NULL>}"
echo "COMPLETE = ${COMPLETE:-<NULL>}"
echo "TERMINAL = ${TERMINAL:-<NULL>}"
echo
)
done
Output:
$ ./tasks < tasks.txt
TASK_ID = TASK1
STATUS_COUNT = 6
INITIAL = 2013-01-15 19:20:40
PREPARING = 2013-01-15 19:21:12
SCHEDULED = 2013-01-15 19:21:13
TRANSLATING = 2013-01-15 19:21:13
LOADING = 2013-01-15 19:36:37
COMPLETE = 2013-01-15 19:36:42
TERMINAL = <NULL>
TASK_ID = TASK2
STATUS_COUNT = 5
INITIAL = 2013-01-15 19:20:44
PREPARING = 2013-01-15 19:21:13
SCHEDULED = 2013-01-15 19:21:14
TRANSLATING = 2013-01-15 19:36:37
LOADING = <NULL>
COMPLETE = <NULL>
TERMINAL = 2013-01-15 20:28:10
TASK_ID = TASK1
STATUS_COUNT = 11
INITIAL = 2013-01-15 20:20:40
PREPARING = 2013-01-15 20:21:12
SCHEDULED = 2013-01-15 20:21:13
TRANSLATING = 2013-01-15 20:21:13
LOADING = 2013-01-15 19:36:37
COMPLETE = 2013-01-15 19:36:42
TERMINAL = 2013-01-15 20:36:42
(Glenn Jackman adding edit based on new requirement)
events=(INITIAL PREPARING SCHEDULED TRANSLATING LOADING COMPLETE TERMINAL)
while IFS=, read -r TASK_ID STATUS_COUNT rest; do
IFS=, read -ra STATUSES <<< "$rest"
for (( i=0; i < ${#STATUSES[#]}; i+=2 )); do
# if this this the initial event, reset all statuses
if [[ ${STATUSES[i]} == ${events[0]} ]]; then
for event in "${events[#]}"; do
declare "$event="
done
fi
declare "${STATUSES[i]}=${STATUSES[i+1]}"
done
for var in TASK_ID STATUS_COUNT "${events[#]}"; do
printf "$%s = %s\n" $var "${!var:-<NULL>}"
done
done

Resources