Workshift class

class timeboard.Workshift(timeboard, location, schedule=None)

A period of time during which a business agent is either on or off duty.

A workshift consists of at least one base unit and may span a number of consecutive base units.

Each workshift has a label. The label is interpreted by a given schedule to determine whether the workshift is on duty or off duty under this schedule. The duty statuses of the same workshift can be different under different schedules.

Parameters:
timeboard : Timeboard
location : int >=0

Position of the workshift on the timeline of the timeboard (zero-based).

schedule : _Schedule, optional

If not given, the timeboard’s default schedule is used.

Raises:
OutOfBoundsError

If location points outside the timeboard or is negative.

See also

Timeboard.get_workshift
provides a convenient way to instantiate a workshift from a point in time instead of calling Workshift() constructor directly.

Examples

>>> clnd = tb.Timeboard('D', '30 Sep 2017', '15 Oct 2017', layout=[0,1])
>>> ws = tb.workshift.Workshift(clnd, 1)
>>> ws
Workshift(1) of 'D' at 2017-10-01
>>> print(ws)
Workshift(1) of 'D' at 2017-10-01
<BLANKLINE>
        ws_ref      start  duration        end  label  on_duty
loc                                                           
1   2017-10-01 2017-10-01         1 2017-10-01    1.0     True
Attributes:
start_time : Timestamp

When the workshift starts (the start time of workshift’s first base unit).

end_time : Timestamp

When the workshift ends (the end time of workshift’s last base unit).

duration : int >0

Number of base units in the workshift.

label

An application-specific label associated with the workshift. Schedule’s selector interprets the label to identify the duty status of the workshift under this schedule.

schedule : _Schedule

Schedule used by workshift’s methods unless explicitly redefined in the method call. Use name attribute of schedule to review its identity.

__add__(self, other)

ws + n is the same as ws.rollforward(n, duty='on')

__sub__(self, other)

ws - n is the same as ws.rollback(n, duty='on')

is_off_duty(self, schedule=None)

True if the workshift is off duty under a specific schedule.

Parameters:
schedule : _Schedule, optional

If schedule is not given, the workshift’s schedule is used.

Returns:
bool
is_on_duty(self, schedule=None)

True if the workshift is on duty under a specific schedule.

Parameters:
schedule : _Schedule, optional

If schedule is not given, the workshift’s schedule is used.

Returns:
bool
rollback(self, steps=0, duty='on', schedule=None)

Find a workshift by taking the specified number of steps to the past.

duty parameter selects which workshifts are counted as steps.

Parameters:
steps : int, optional (default 0)
duty : {'on', 'off', 'same', 'alt', 'any'}, optional
  • 'on' : (default) step on on-duty workshifts only
  • 'off' : step on off-duty workshifts only
  • 'same' : step only on workshifts with the same duty status as self
  • 'alt' : step only on workshifts with the duty status other than that of self
  • 'any' : step on all workshifts
schedule : _Schedule, optional

If schedule is not given, the workshift’s schedule is used.

Returns:
Workshift
Raises:
OutOfBoundsError

If the method attempted to roll outside the timeboard.

See also

__sub__
ws - n is the same as ws.rollback(n, duty='on')
rollforward
Return a workshift which is in the specified number of steps in the future. Methods rollback and rollforward differ in the definition of the zero step workshift and the default direction of stepping.

Notes

The method is executed in two stages. The first stage finds the workshift at step 0. The second stage fulfills the required number of steps (if any) starting from the zero step workshift.

If self has the same duty as specified by duty parameter, then the zero step workshift is self, otherwise, it is the first workshift toward the past which conforms to duty parameter. If `steps`=0, the method terminates here and returns the zero step workshift.

If steps is positive, the method counts workshifts toward the past stepping only on workshifts with the specified duty and returns the last workshift on which it has stepped. For example, with `steps`=1 the method returns the workshift preceding the zero step workshift, subject to duty.

If steps is negative, the method works in the same way but moving toward the future from the zero step workshift. For example, with `steps`=-1 the method returns the workshift following the zero step workshift, subject to duty.

Note that the zero step workshift is sought in the past even if steps is negative.

Examples

>>> clnd = tb.Timeboard('D', '30 Sep 2017', '15 Oct 2017', layout=[0,1])

In this timeboard odd dates are on duty and even dates are off duty.

>>> ws1 = clnd('05 Oct 2017')
>>> ws1.is_on_duty()
True
>>> ws1.rollback()
Workshift(5) of 'D' at 2017-10-05
>>> ws1.rollback(1)
Workshift(3) of 'D' at 2017-10-03
>>> ws1 - 1
Workshift(3) of 'D' at 2017-10-03
>>> ws1.rollback(-1)
Workshift(7) of 'D' at 2017-10-07
>>> ws1.rollback(duty='off')
Workshift(4) of 'D' at 2017-10-04
>>> ws1.rollback(1, duty='off')
Workshift(2) of 'D' at 2017-10-02
>>> ws1.rollback(-1, duty='off')
Workshift(6) of 'D' at 2017-10-06
>>> ws0 = clnd('06 Oct 2017')
>>> ws0.is_off_duty()
True
>>> ws0.rollback()
Workshift(5) of 'D' at 2017-10-05
>>> ws0.rollback(1)
Workshift(3) of 'D' at 2017-10-03
>>> ws0 - 1
Workshift(3) of 'D' at 2017-10-03
>>> ws0.rollback(-1)
Workshift(7) of 'D' at 2017-10-07
>>> ws0.rollback(duty='off')
Workshift(6) of 'D' at 2017-10-06
>>> ws0.rollback(1, duty='off')
Workshift(4) of 'D' at 2017-10-04
>>> ws0.rollback(-1, duty='off')
Workshift(8) of 'D' at 2017-10-08

Note that ws0.rollback(-1) and ws0 + 1 produce different results:

>>> ws0.rollback(-1)
Workshift(7) of 'D' at 2017-10-07
>>> ws0 + 1
Workshift(9) of 'D' at 2017-10-09

This happens because ws0.rollback(-1) assumes the default duty=’on’ and seeks the zero step on-duty workshift by moving backwards from the off-duty self (October 6). Thus the zero step workshift will be October 5. From that point the method takes one on-duty step to the future and arrives at October 7 which is the result.

On the contrary, ws0 + 1 calls ws0.rollforward(1, duty='on') which seeks the zero step on-duty workshift by moving forward from self. Thus the zero step workshift will be October 7, and one on-duty step to the future from that will be the result, October 9.

rollforward(self, steps=0, duty='on', schedule=None)

Find a workshift by taking the specified number of steps to the future.

duty parameter selects which workshifts are counted as steps.

Parameters:
steps : int, optional (default 0)
duty : {'on', 'off', 'same', 'alt', 'any'}, optional
  • 'on' : (default) step on on-duty workshifts only
  • 'off' : step on off-duty workshifts only
  • 'same' : step only on workshifts with the same duty status as self
  • 'alt' : step only on workshifts with the duty status other than that of self
  • 'any' : step on all workshifts
schedule : _Schedule, optional

If schedule is not given, the workshift’s schedule is used.

Returns:
Workshift
Raises:
OutOfBoundsError

If the method attempted to roll outside the timeboard.

See also

__add__
ws + n is the same as ws.rollforward(n, duty='on')
rollback
Return a workshift which is in the specified number of steps in the past. Methods rollback and rollforward differ in the definition of the zero step workshift and the default direction of stepping.

Notes

The method is executed in two stages. The first stage finds the workshift corresponding to step 0. The second stage fulfills the required number of steps (if any) starting from the zero step workshift.

If self has the same duty as specified by duty parameter, then the zero step workshift is self, otherwise, it is the first workshift toward the future which conforms to duty parameter. If `steps`=0, the method terminates here and returns the zero step workshift.

If steps is positive, the method counts workshifts toward the future stepping only on workshifts with the specified duty and returns the last workshift on which it has stepped. For example, with `steps`=1 the method returns the workshift following the zero step workshift, subject to duty.

If steps is negative, the method works in the same way but moving toward the past from the zero step workshift. For example, with `steps`=-1 the method returns the workshift preceding the zero step workshift, subject to duty.

Note that the zero step workshift is sought toward the future even if steps is negative.

Examples

>>> clnd = tb.Timeboard('D', '30 Sep 2017', '15 Oct 2017', layout=[0,1])

In this timeboard odd dates are on duty and even dates are off duty.

>>> ws1 = clnd('05 Oct 2017')
>>> ws1.is_on_duty()
True
>>> ws1.rollforward()
Workshift(5) of 'D' at 2017-10-05
>>> ws1.rollforward(1)
Workshift(7) of 'D' at 2017-10-07
>>> ws1 + 1
Workshift(7) of 'D' at 2017-10-07
>>> ws1.rollforward(-1)
Workshift(3) of 'D' at 2017-10-03
>>> ws1.rollforward(duty='off')
Workshift(6) of 'D' at 2017-10-06
>>> ws1.rollforward(1, duty='off')
Workshift(8) of 'D' at 2017-10-08
>>> ws1.rollforward(-1, duty='off')
Workshift(4) of 'D' at 2017-10-04
>>> ws0 = clnd('06 Oct 2017')
>>> ws0.is_off_duty()
True
>>> ws0.rollforward()
Workshift(7) of 'D' at 2017-10-07
>>> ws0.rollforward(1)
Workshift(9) of 'D' at 2017-10-09
>>> ws0 + 1
Workshift(9) of 'D' at 2017-10-09
>>> ws0.rollforward(-1)
Workshift(5) of 'D' at 2017-10-05
>>> ws0.rollforward(duty='off')
Workshift(6) of 'D' at 2017-10-06
>>> ws0.rollforward(1, duty='off')
Workshift(8) of 'D' at 2017-10-08
>>> ws0.rollforward(-1, duty='off')
Workshift(4) of 'D' at 2017-10-04

Note that ws0.rollforward(-1) and ws0 - 1 produce different results:

>>> ws0.rollforward(-1)
Workshift(5) of 'D' at 2017-10-05
>>> ws0 - 1
Workshift(3) of 'D' at 2017-10-03

This happens because ws0.rollforward(-1) assumes the default duty=’on’ and seeks the zero step on-duty workshift by moving forward from the off-duty self (October 6). Thus the zero step workshift will be October 7. From that point the method takes one on-duty step to the past and arrives at October 5 which is the result.

On the contrary, ws0 - 1 calls ws0.rollback(1, duty='on') which seeks the zero step on-duty workshift by moving backward from self. Thus the zero step workshift will be October 5, and one on-duty step to the past from that will be the result, October 3.

to_timestamp(self)

The characteristic time used to represent the workshift.

The rule to calculate the timestamp is defined by workshift_ref parameter of the timeboard.

Returns:
Timestamp
worktime(self, duty='on', schedule=None)

Return the work time for the worker with the specified duty.

The source for the work time value is determined by Timeboard.worktime_source.

Parameters:
duty : {'on', 'off', 'any'} , optional (default 'on')

Specify the duty of the worker.

schedule : _Schedule, optional

If schedule is not given, the interval’s schedule is used to determine the duty.

Returns:
int or float

Either workshift’s duration or label, depending on the value of worktime_source. However, if the workshift’s duty is not the same as worker’s duty, zero is returned.

Raises:
TypeError

If `worktime_source`=’labels’ but the workshift’s label is not a number.

Examples

By default, the work time equals to workshift’s duration:

>>> clnd = tb.Timeboard('D', '30 Sep 2017', '11 Oct 2017', 
...                     layout=[4, 8, 4, 8],
...                     default_selector = lambda label: label>4)
>>> ws = tb.Workshift(clnd, 3)
>>> ws.label
8.0
>>> ws.duration
1
>>> ws.is_on_duty()
True
>>> ws.worktime()
1
>>> ws.worktime(duty='off')
0
>>> ws.worktime(duty='any')
1

In the example below, the work time is taken from the labels:

>>> clnd = tb.Timeboard('D', '30 Sep 2017', '11 Oct 2017', 
...                     layout=[4, 8, 4, 8],
...                     default_selector = lambda label: label>4,
...                     worktime_source = 'labels')
>>> ws = tb.Workshift(clnd, 3)
>>> ws.worktime()
8.0
>>> ws.worktime(duty='off')
0
>>> ws.worktime(duty='any')
8.0
>>> ws = tb.Workshift(clnd, 2)
>>> ws.label
4.0
>>> ws.is_off_duty()
True
>>> ws.worktime()
0
>>> ws.worktime(duty='off')
4.0
>>> ws.worktime(duty='any')
4.0