analyze outlook calendar data in spss - spss

I downloaded Conference Room Usage from outlook.
I want to know
How busy are the conference rooms?
What are the hot times?
Who are the super users?
Who are not the super users?
How many recurrent meetings take place.
This issue i'm having is that I need the duration between the "StartTime" and the "EndTime"; but they are currently strings!
start end starttime endtime
1/1/2014 1/1/2014 5:00:00 PM 5:00:00 PM
Also, it's likely safe to assume that StartTimes and EndTimes do not straddle two days, but perhaps I want to check for this.
Perhaps conversion to a 24-hour clock might help; "Duration" is then "EndTime" - "StartTime". How can i convert back to a 12-hour clock for the uninitiated. Finally, I need the day of the week (Monday, Tuesday, etc) an event falls on.

This can mostly be accomplished through the wizard.
some sudo code that should do the trick would be
COMPUTE Start=number(StartDate, ADATE10).
VARIABLE LEVEL Start (SCALE).
FORMATS Start (ADATE10).
VARIABLE WIDTH Start(10).
EXECUTE.
COMPUTE starttimetest=number(StartTime, TIME8).
VARIABLE LEVEL starttimetest (SCALE).
FORMATS starttimetest (TIME8).
VARIABLE WIDTH starttimetest(8).
EXECUTE.
compute teststartadd=start+starttimetest.
DO if index(starttime,'PM') gt 0 and subs(starttime,1,2) ne '12' .
COMPUTE Realstart=datesum(teststartadd,12,'hours').
ELSE.
COMPUTE REALstart=TESTstartADD.
END IF.
COMPUTE End=number(EndDate, ADATE10).
VARIABLE LEVEL End (SCALE).
FORMATS End (ADATE10).
VARIABLE WIDTH End(10).
EXECUTE.
COMPUTE endtimetest=number(endTime, TIME8).
VARIABLE LEVEL endtimetest (SCALE).
FORMATS endtimetest (TIME8).
VARIABLE WIDTH endtimetest(8).
EXECUTE.
compute testendadd=end+endtimetest.
DO if index(endtime,'PM') gt 0 and subs(endtime,1,2) ne '12' .
COMPUTE RealEnd=datesum(testendadd,12,'hours').
ELSE.
COMPUTE REALEND=TESTENDADD.
END IF.
exe.
delete vars Start
starttimetest
teststartadd
End
endtimetest
testendadd.
exe.
formats RealEnd RealStart(datetime23).
compute Length=datedif(realend,realstart,'hours').
if length > 12 check=1.
freq check.
compute StartWkDay=XDATE.WKDAY(realstart).
compute EndWkDay=XDATE.WKDAY(realEnd).
string StartDayText EndDayText(a8).
you'll have to convert using something like
*if XDATE.WKDAY(realstart)=1 startdaytext="Sunday".

Related

Parse time string to hours, minutes and seconds in Lua

I am currently working on a plugin for grandMA2 lighting control using Lua. I need the current time. The only way to get the current time is the following function:
gma.show.getvar('TIME')
which always returns the current system time, which I then store in a variable. An example return value is "12h54m47.517s".
How can I separate the hours, minutes and seconds into 3 variables?
If os.date is available (and matches gma.show.getvar('TIME')), this is trivial:
If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61, due to leap seconds), wday (weekday, 1–7, Sunday is 1), yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.
local time = os.date('*t')
local hour, min, sec = time.hour, time.min, time.sec
This does not provide you with a sub-second precision though.
Otherwise, parsing the time string is a typical task for tostring and string.match:
local hour, min, sec = gma.show.getvar('TIME'):match('^(%d+)h(%d+)m(%d*%.?%d*)s$')
-- This is usually not needed as Lua will just coerce strings to numbers
-- as soon as you start doing arithmetic on them;
-- it still is good practice to convert the variables to the proper type though
-- (and starts being relevant when you compare them, use them as table keys or call strict functions that check their argument types on them)
hour, min, sec = tonumber(hour), tonumber(min), tonumber(sec)
Pattern explanation:
^ and $ pattern anchors: Match the full string (and not just part of it), making the match fail if the string does not have the right format.
(%d)+h: Capture hours: One or more digits followed by a literal h
(%d)+m: Capture minutes: One or more digits followed by a literal m
(%d*%.?%d*)s: Capture seconds: Zero or more digits followed by an optional dot followed by again zero or more digits, finally ending with a literal s. I do not know the specifics of the format and whether something like .1s, 1.s or 1s is occasionally emitted, but Lua's tonumber supports all of these so there should be no issue. Note that this is slightly overly permissive: It will also match . (just a dot) and an s without any leading digits. You might want (%d+%.?%d+)s instead to force digits appearing before & after the dot.
Lets do it with string method gsub()
local ts = gma.show.getvar('TIME')
local hours = ts:gsub('h.*', '')
local mins = ts:gsub('.*%f[^h]', ''):gsub('%f[m].*', '')
local secs = ts:gsub('.*%f[^m]', ''):gsub('%f[s].*', '')
To make a Timestring i suggest string method format()
-- secs as float
timestring = ('[%s:%s:%.3f]'):format(hours, mins, secs)
-- secs not as float
timestring = ('[%s:%s:%.f]'):format(hours, mins, secs)

Plotting time series + offset not working

I want to plot two time series that are in different formats in the
same format, but one of those two doesn't work for me.
So here's the thing:
I have a time series in seconds with a given starting time t0.
So the series looks like this:
Starting time: t0
0 -21.0028
5 -21.0067
10 -21.007
...
17875 -20.9943
I want to plot this time series with the time (e.g. 9:03) instead
of seconds and I want to show another time series where the
data is given in standard time in the same plot.
I can plot the second series just fine.
But when I try to plot the first series, the measured points
start jumping from x=100 back to 0 and then back and forth.
Additionally I can't add the offset t0 to the series.
Here's what I tried (t0 = 32615s) to get at least the first time series plotted:
gnuplot> set xdata time
gnuplot> set timefmt "%S"
gnuplot> set format x "%H:%M"
gnuplot> plot 'measurement.dat' u (timecolumn(1)+32615):2 w l, 'measurement2.dat" u 1:2 w l
Does anyone know how I can plot these time series?
Thanks in advance!
My understanding of your problem is that you have two data sets with different timedata. One in seconds and the other what you call "standard", I assume, e.g. 09:03:00.
And you want to shift the one with seconds by some value.
Internally, dates and times are stored as seconds from January 1st 1970 00:00:00.
Since the first dataset is already in seconds just add your shift-value.
You need to convert ´$Data2´ into seconds via timecolumn(1,"%H:%M:%S").
And the way you display the xtic labels is set via set format x "%H:%M" time. Also check help timecolumn. It also depends if you want to display a time of the day, i.e. 00:00 to 23:59 or if you want to display hours >24h. Then you might want to use "%tH:%tM:%tS"as format. Check help time_specifiers.
Code:
### shifted time data
reset session
# create some test data
set print $Data1
do for [i=1:20000:200] {
print sprintf("%d %.3f",i,sin(i/2000.))
}
set print
set print $Data2
do for [i=30000:50000:200] {
print sprintf("%s %.3f",strftime("%H:%M:%S",i),2*sin(i/2000.-2.5))
}
set print
set format x "%H:%M" time
set key top center
set multiplot layout 2,1
plot $Data1 u 1:2 w lp ti "Data1", \
$Data2 u (timecolumn(1,"%H:%M:%S")):2 w lp ti "Data2"
t0 = 30000
plot $Data1 u ($1+t0):2 w lp ti "shifted Data1", \
$Data2 u (timecolumn(1,"%H:%M:%S")):2 w lp title "Data2"
unset multiplot
### end of code
Result:

why pytz.country_timezones('cn') in centos system have different result?

Two computer install centos 6.5, kernel is 3.10.44, have different result.
one result is [u'Asia/Shanghai', u'Asia/Urumqi'], and the other is ['Asia/Shanghai', 'Asia/Harbin', 'Asia/Chongqing', 'Asia/Urumqi', 'Asia/Kashgar'].
Is there any config that make the first result same as the second result?
I have following python code:
def get_date():
date = datetime.utcnow()
from_zone = pytz.timezone("UTC")
to_zone = pytz.timezone("Asia/Urumqi")
date = from_zone.localize(date)
date = date.astimezone(to_zone)
return date
def get_curr_time_stamp():
date = get_date()
stamp = time.mktime(date.timetuple())
return stamp
cur_time = get_curr_time_stamp()
print "1", time.strftime("%Y %m %d %H:%M:%S", time.localtime(time.time()))
print "2", time.strftime("%Y %m %d %H:%M:%S", time.localtime(cur_time))
When use this code to get time, the result of one computer(have 2 results) is:
1 2016 04 20 08:53:18
2 2016 04 20 06:53:18
and the other(have 5 results) is:
1 2016 04 20 08:53:18
2 2016 04 20 08:53:18
I don't know why?
You probably just have an outdated version of pytz on the system returning five time zones (or perhaps on both systems). You can find the latest releases here. It's important to stay on top of time zone updates, as the various governments of the world change their time zones often.
Like most systems, pytz gets its data from the tz database. The five time zones for China were reduced to two in version 2014f (corresponding to pytz 2014.6). From the release notes:
China's five zones have been simplified to two, since the post-1970
differences in the other three seem to have been imaginary. The
zones Asia/Harbin, Asia/Chongqing, and Asia/Kashgar have been
removed; backwards-compatibility links still work, albeit with
different behaviors for time stamps before May 1980. Asia/Urumqi's
1980 transition to UTC+8 has been removed, so that it is now at
UTC+6 and not UTC+8. (Thanks to Luther Ma and to Alois Treindl;
Treindl sent helpful translations of two papers by Guo Qingsheng.)
Also, you may wish to read Wikipedia's Time in China article, which explains that the Asia/Urumqui entry is for "Ürümqi Time", which is used unofficially in some parts of the Xinjiang region. This zone is not recognized by the Chinese government, and is considered a politically charged issue. As such, many systems choose to omit the Urumqi time zone, despite it being in listed in the tz database.

How to find if range is contained in an array of ranges?

Example
business_hours['monday'] = [800..1200, 1300..1700]
business_hours['tuesday'] = [900..1100, 1300..1700]
...
I then have a bunch of events which occupy some of these intervals, for example
event = { start_at: somedatetime, end_at: somedatetime }
Iterating over events from a certain date to a certain date, I create another array
busy_hours['monday'] = [800..830, 1400..1415]
...
Now my challenges are
Creating an available_hours array that contains business_hours minus busy_hours
available_hours = business_hours - busy_hours
Given a certain duration say 30 minutes, find which time slots are available in available_hours. In the examples above, such a method would return
available_slots['monday'] = [830..900, 845..915, 900..930, and so on]
Not that it checks available_hours in increments of 15 minutes for slots of specified duration.
Thanks for the help!
I think this is a job for bit fields. Unfortunately this solution will rely on magic numbers, conversions helpers and a fair bit of binary logic, so it won't be pretty. But it will work and be very efficient.
This is how I'd approach the problem:
Atomize your days into reasonable time intervals. I'll follow your example and treat each 15 minute block of time as considered one time chunk (mostly because it keeps the example simple). Then represent your availability per hour as a hex digit.
Example:
0xF = 0x1111 => available for the whole hour.
0xC = 0x1100 => available for the first half of the hour.
String 24 of these together together to represent a day. Or fewer if you can be sure that no events will occur outside of the range. The example continues assuming 24 hours.
From this point on I've split long Hex numbers into words for legibility
Assuming the day goes from 00:00 to 23:59 business_hours['monday'] = 0x0000 0000 FFFF 0FFF F000 0000
To get busy_hours you store events in a similar format, and just & them all together.
Exmample:
event_a = 0x0000 0000 00F0 0000 0000 0000 # 10:00 - 11:00
event_b = 0x0000 0000 0000 07F8 0000 0000 # 13:15 - 15:15
busy_hours = event_a & event_b
From busy_hours and business_hours you can get available hours:
available_hours = business_hours & (busy_hours ^ 0xFFFF FFFF FFFF FFFF FFFF FFFF)
The xor(^) essentialy translates busy_hours into not_busy_hours. Anding (&) not_busy_hours with business_hours gives us the available times for the day.
This scheme also makes it simple to compare available hours for many people.
all_available_hours = person_a_available_hours & person_b_available_hours & person_c_available_hours
Then to find a time slot that fits into available hours. You need to do something like this:
Convert your length of time into a similar hex digit to the an hour where the ones represent all time chunks of that hour the time slot will cover. Next right shift the digit so there's no trailing 0's.
Examples are better than explanations:
0x1 => 15 minutes, 0x3 => half hour, 0x7 => 45 minutes, 0xF => full hour, ... 0xFF => 2 hours, etc.
Once you've done that you do this:
acceptable_times =[]
(0 .. 24 * 4 - (#of time chunks time slot)).each do |i|
acceptable_times.unshift(time_slot_in_hex) if available_hours & (time_slot_in_hex << i) == time_slot_in_hex << i
end
The high end of the range is a bit of a mess. So lets look a bit more at it. We don't want to shift too many times or else we'll could start getting false positives at the early end of the spectrum.
24 * 4 24 hours in the day, with each represented by 4 bits.
- (#of time chunks in time slot) Subtract 1 check for each 15 minutes in the time slot we're looking for. This value can be found by (Math.log(time_slot_in_hex)/Math.log(2)).floor + 1
Which starts at the end of the day, checking each time slot, moving earlier by a time chunk (15 minutes in this example) on each iteration. If the time slot is available it's added to the start of acceptable times. So when the process finishes acceptable_times is sorted in order of occurrence.
The cool thing is this implementation allows for time slots that incorporate so that your attendee can have a busy period in their day that bisects the time slot you're looking for with a break, where they might be otherwise busy.
It's up to you to write helper functions that translate between an array of ranges (ie: [800..1200, 1300..1700]) and the hex representation. The best way to do that is to encapsulate the behaviour in an object and use custom accessor methods. And then use the same objects to represent days, events, busy hours, etc. The only thing that's not built into this scheme is how to schedule events so that they can span the boundary of days.
To answer your question's title, find if a range of arrays contains a range:
ary = [800..1200, 1300..1700]
test = 800..830
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => true
test = 1245..1330
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => false
which could be written as
class Range
def include_range?(r)
self.include?(r.first) and self.include?(r.last)
end
end
Okay, I don't have time to write up a full solution, but the problem does not seem too difficult to me. I hacked together the following primitive methods you can use to help in constructing your solution (You may want to subclass Range rather than monkey patching, but this will give you the idea):
class Range
def contains(range)
first <= range.first || last >= range.last
end
def -(range)
out = []
unless range.first <= first && range.last >= last
out << Range.new(first, range.first) if range.first > first
out << Range.new(range.last, last) if range.last < last
end
out
end
end
You can iterate over business hours and find the one that contains the event like so:
event_range = event.start_time..event.end_time
matching_range = business_hours.find{|r| r.contains(event_range)}
You can construct the new array like this (pseudocode, not tested):
available_hours = business_hours.dup
available_hours.delete(matching_range)
available_hours += matching_range - event_range
That should be a pretty reusable approach. Of course you'll need something totally different for the next part of your question, but this is all I have time for :)

ruby on rails int to minutes::seconds::milliseconds

I have this line, which shows the minutes and seconds. But I have to add milliseconds to it as well for greater accuracy. How do I add that in this line, or is there an easier way to get the desired result?
#duration = [cd.ExactDuration/60000000, cd.ExactDuration/1000000 % 60].map{|t| t.to_s.rjust(2, '0') }.join(':'))
The exact duration type is saved in microseconds. So the first converts to microseconds to minutes, the second part is microseconds to seconds. Now I need to add milliseconds.
cd.ExactDuration/1000 % 1000 should do the trick.
Of course you may also want to tweak the formatting, since that's a datum you don't want to right-justify in a 2-wide field;-). I'd suggest sprintf for string-formatting, though I realize its use is not really intuitive unless you come from a C background.

Resources