time
time
Functions and classes for handling time
Hierarchy of TimePars: TimePar # All time parameters ├── dur # All durations, units of time │ ├── days # Duration with units of days │ ├── weeks │ ├── months │ ├── years │ └── datedur # Calendar durations └── Rate # All rates, units of per (e.g. per time or per event) ├── per # Probability rates over time (e.g., death rate per year) │ ├── perday │ ├── perweek │ ├── permonth │ └── peryear ├── prob # Unitless probability (e.g., probability of death per infection) │ ├── probperday │ ├── probperweek │ ├── probpermonth │ └── probperyear └── freq # Number of events (e.g., number of acts per year) ├── freqperday ├── freqperweek ├── freqpermonth └── freqperyear
Classes
Name | Description |
---|---|
DateArray | Lightweight wrapper for an array of dates |
Rate | Store a value per unit time e.g., 2 per day |
TimePar | Parent class for all TimePars – dur, Rate, etc. |
date | Define a point in time, based on pd.Timestamp |
datedur | Date based duration e.g., if requiring a week to be 7 calendar days later |
dur | Base class for durations |
freq | Class for the number of events (rather than probability) in a specified period |
per | A per represents an instantaneous rate of an event occurring. Rates |
prob | prob represents the probability of an event occurring during a |
DateArray
time.DateArray()
Lightweight wrapper for an array of dates
Attributes
Name | Description |
---|---|
subdaily | Check if the array has sub-daily timesteps |
years | Represent the dates as floating point years |
Methods
Name | Description |
---|---|
is_ | Checks if the DateArray is comprised of ss.date objects |
to_array | Force conversion to an array |
to_date | Convert to ss.date |
to_float | Convert to a float, returning a new DateArray unless inplace=True |
to_human | Return the most human-friendly (i.e. plotting-friendly) version of the dates, |
is_
time.DateArray.is_(which)
Checks if the DateArray is comprised of ss.date objects
to_array
*args, **kwargs) time.DateArray.to_array(
Force conversion to an array
to_date
=False, day_round=None, die=True) time.DateArray.to_date(inplace
Convert to ss.date
Parameters
Name | Type | Description | Default |
---|---|---|---|
inplace | bool | whether to modify in place | False |
round | bool | whether to round dates to the nearest day (otherwise, keep timestamp); if None, round if and only if the span of the first timestep is at least one day | required |
die | bool | if False, then fall back to float if conversion to date fails (e.g. year 0) | True |
to_float
=False, to_numpy=False) time.DateArray.to_float(inplace
Convert to a float, returning a new DateArray unless inplace=True
to_human
time.DateArray.to_human()
Return the most human-friendly (i.e. plotting-friendly) version of the dates, i.e. ss.date if possible, float otherwise
Rate
self, value, unit=None) time.Rate(
Store a value per unit time e.g., 2 per day - self.value - the numerator (e.g., 2) - a scalar float - self.unit - the denominator (e.g., 1 day) - a dur object
Methods
Name | Description |
---|---|
set_default_dur | Set the default duration, e.g. module.dt, so .to_prob() can be used with no input |
to_events | Simple multiplication: calculate the number of events over the time period |
to_prob | Convert from one time probability to another |
set_default_dur
time.Rate.set_default_dur(dur)
Set the default duration, e.g. module.dt, so .to_prob() can be used with no input
to_events
=None) time.Rate.to_events(dur
Simple multiplication: calculate the number of events over the time period
to_prob
=None, scale=1.0) time.Rate.to_prob(dur
Convert from one time probability to another
Parameters
Name | Type | Description | Default |
---|---|---|---|
dur | ss.dur |
the duration over which to convert the probability to | None |
scale | float | an optional additional mutliplicative scale factor to incorporate in the calculation | 1.0 |
Example:
p_month = ss.probpermonth(0.05)
p_year = p_month.to_prob(ss.year) # Slightly less than 0.05*12
TimePar
time.TimePar()
Parent class for all TimePars – dur, Rate, etc.
Methods
Name | Description |
---|---|
to | Convert this TimePar to one of a different class |
to_array | Force conversion to an array |
to_base | Class method to convert another TimePar object to this TimePar’s base units; in most cases |
to
time.TimePar.to(unit)
Convert this TimePar to one of a different class
to_array
*args, **kwargs) time.TimePar.to_array(
Force conversion to an array
to_base
time.TimePar.to_base(other)
Class method to convert another TimePar object to this TimePar’s base units; in most cases
date
time.date()
Define a point in time, based on pd.Timestamp
Parameters
Name | Type | Description | Default |
---|---|---|---|
date | int / float / str / datetime | Any type of date input (ints and floats will be interpreted as years) | required |
allow_zero | bool | if True, allow a year 0 by creating a datedur instead; if False, raise an exception; if None, give a warning | required |
kwargs | dict | passed to pd.Timestamp() | required |
Examples:
ss.date(2020) # Returns <2020-01-01>
ss.date(year=2020) # Returns <2020-01-01>
ss.date(year=2024.75) # Returns <2024-10-01>
ss.date('2024-04-04') # Returns <2024-04-04>
ss.date(year=2024, month=4, day=4) # Returns <2024-04-04>
Attributes
Name | Description |
---|---|
years | Return the date as a number of years |
Methods
Name | Description |
---|---|
arange | Construct an array of dates |
disp | Show the full object |
from_array | Convert an array of float years into an array of date instances |
from_json | Reconstruct a date from a JSON; reverse of to_json() |
from_year | Convert an int or float year to a date. |
replace | Returns a new ss.date(); pd.Timestamp is immutable |
round | Round to a given interval (by default a day |
subdaily | Check if a subdaily timestep is used |
to_json | Returns a JSON representation of the date |
to_pandas | Convert to a standard pd.Timestamp instance |
to_year | Convert a date to a floating-point year |
arange
time.date.arange(
start,
stop,=1.0,
step=True,
inclusive=None,
day_round=True,
allow_zero )
Construct an array of dates
Functions similarly to np.arange, but returns date objects
Example usage:
date.arange(2020, 2025) array([<2020.01.01>, <2021.01.01>, <2022.01.01>, <2023.01.01>, <2024.01.01>, <2025.01.01>], dtype=object)
Parameters
Name | Type | Description | Default |
---|---|---|---|
start | float / ss .date / ss .dur |
Lower bound - can be a date or a numerical year | required |
stop (float/ss.date/ss.dur): Upper bound - can be a date or a numerical year step (float/ss.dur): Assumes 1 calendar year steps by default inclusive (bool): Whether to include “stop” in the output day_round (bool): Whether to round to the nearest day (by default, True if step > 1 day) allow_zero (bool): if True, allow a year 0 by creating a datedur instead; if False, raise an exception; if None, give a warning
Returns
Name | Type | Description |
---|---|---|
An array of date instances |
disp
**kwargs) time.date.disp(
Show the full object
from_array
=True, allow_zero=True, date_type=None) time.date.from_array(array, day_round
Convert an array of float years into an array of date instances
Parameters
Name | Type | Description | Default |
---|---|---|---|
array | array | An array of float years | required |
day_round | bool | Whether to round to the nearest day | True |
allow_zero | bool | if True, allow a year 0 by creating a datedur instead; if False, raise an exception; if None, give a warning | True |
date_type | type | Optionally convert to a class other than ss.date (e.g. ss.datedur ) |
None |
Returns
Name | Type | Description |
---|---|---|
An array of date instances |
from_json
time.date.from_json(json)
Reconstruct a date from a JSON; reverse of to_json()
from_year
=True, allow_zero=None) time.date.from_year(year, day_round
Convert an int or float year to a date.
Parameters
Name | Type | Description | Default |
---|---|---|---|
year | float | the year to round | required |
day_round | bool | whether to round to the nearest day | True |
allow_zero | bool | whether to allow year 0 (if so, return ss.datedur instead) | None |
Examples:
ss.date.from_year(2020) # Returns <2020-01-01>
ss.date.from_year(2024.75) # Returns <2024-10-01>
replace
*args, **kwargs) time.date.replace(
Returns a new ss.date(); pd.Timestamp is immutable
round
round(to='d') time.date.
Round to a given interval (by default a day
subdaily
time.date.subdaily(years)
Check if a subdaily timestep is used
A date has no concept of a timestep, but add this as a convienence method since this is required by other methods (e.g. ss.date.arange()
).
to_json
time.date.to_json()
Returns a JSON representation of the date
to_pandas
time.date.to_pandas()
Convert to a standard pd.Timestamp instance
to_year
time.date.to_year()
Convert a date to a floating-point year
Examples:
ss.date('2020-01-01').to_year() # Returns 2020.0
ss.date('2024-10-01').to_year() # Returns 2024.7486
datedur
self, *args, **kwargs) time.datedur(
Date based duration e.g., if requiring a week to be 7 calendar days later
Attributes
Name | Description |
---|---|
days | Shortcut to datedur.to(‘days’) |
months | Shortcut to datedur.to(‘months’) |
weeks | Shortcut to datedur.to(‘weeks’) |
years | Shortcut to datedur.to(‘years’) |
Methods
Name | Description |
---|---|
round_duration | Round a dictionary of duration values by overflowing remainders |
scale | Scale a pd.DateOffset by a factor |
to | Return approximate conversion into the provided quantity |
to_array | Convert to a Numpy array (NB, different than to_numpy() which converts to fractional years |
to_dict | Convert to a dictionary |
to_dur | Convert to the smallest non-zero value, e.g. ss.datedur(years=1, days=10).to_dur() = ss.days(375) |
round_duration
=None, **kwargs) time.datedur.round_duration(vals
Round a dictionary of duration values by overflowing remainders
The input can be - A numpy array of length ss.time.factors
containing values in key order - A pd.DateOffset instance - A dictionary with keys from ss.time.factors
The output will be a pd.DateOffset with integer values, where non-integer values have been handled by overflow using the factors in ss.time.factors
. For example, 2.5 weeks would first become 2 weeks and 0.57 = 3.5 days, and then become 3 days + 0.524 = 12 hours.
Negative values are supported - -1.5 weeks for example will become (-1w, -3d, -12h)
Returns
Name | Type | Description |
---|---|---|
A pd.DateOffset |
scale
time.datedur.scale(dateoffset, scale)
Scale a pd.DateOffset by a factor
This function will automatically cascade remainders to finer units using ss.time.factors
so for example 2.5 weeks would first become 2 weeks and 0.57 = 3.5 days, and then become 3 days + 0.524 = 12 hours.
Parameters
Name | Type | Description | Default |
---|---|---|---|
dateoffset | A pd.DateOffset instance | required | |
scale | A float scaling factor (must be positive) | required |
Returns
Name | Type | Description |
---|---|---|
A pd.DateOffset instance scaled by the requested amount |
to
time.datedur.to(unit)
Return approximate conversion into the provided quantity
This allows interoperability with years objects (which would typically be expected to occur if module parameters have been entered with datedur
durations, but the simulation timestep is in years
units).
The conversion is based on ss.time.factors
which defines the conversion from each time unit to the next.
Parameters
Name | Type | Description | Default |
---|---|---|---|
unit | str |
the unit to convert to: years, months, weeks, or days | required |
Returns
Name | Type | Description |
---|---|---|
A float representing the duration in that unit |
to_array
*args, **kwargs) time.datedur.to_array(
Convert to a Numpy array (NB, different than to_numpy() which converts to fractional years
to_dict
time.datedur.to_dict()
Convert to a dictionary
to_dur
time.datedur.to_dur()
Convert to the smallest non-zero value, e.g. ss.datedur(years=1, days=10).to_dur() = ss.days(375)
dur
self, value=1, base=None) time.dur(
Base class for durations
Note: this class should not be used by the user directly; instead, use ss.years(), ss.days(), etc. These classes can be interconverted using .to()
, e.g. ss.years(3).to('days')
.
Methods
Name | Description |
---|---|
arange | Construct an array of dur instances |
arange
=1.0, inclusive=True) time.dur.arange(start, stop, step
Construct an array of dur instances
Parameters
Name | Type | Description | Default |
---|---|---|---|
start | float / ss .dur |
Starting point, e.g., ss.years(0) | required |
stop | float / ss .dur |
Ending point, e.g. ss.years(20) | required |
step | float / ss .dur |
Step size, e.g. ss.years(2) | 1.0 |
freq
self, value, unit=None) time.freq(
Class for the number of events (rather than probability) in a specified period
Identical to ss.per
, except by default multiplication returns a number of events rather than a probability. Use ss.freq
for events (e.g., number of acts per year) and ss.per
for probabilities (e.g., probability of death per year).
Attributes
Name | Description |
---|---|
rate | Alias to self.value |
per
self, value, unit=None) time.per(
A per
represents an instantaneous rate of an event occurring. Rates must be non-negative, but need not be less than 1.
Through multiplication, rate can be modified or converted to a probability, depending on the data type of the object being multiplied.
When a per
is multiplied by a scalar or array, the rate is simply scaled. Such multiplication occurs frequently in epidemiological models, where the base rate is multiplied by “rate ratio” or “relative rate” to represent agents experiencing higher (multiplier > 1) or lower (multiplier < 1) event rates.
Alternatively, when a per
is multiplied by a duration (type ss.dur), a probability is calculated. The conversion from rate to probability on multiplication by a duration is 1 - np.exp(-rate/factor)
, where factor
is the ratio of the multiplied duration to the original period (denominator).
For example, consider >>> p = ss.per(0.8, ss.years(1)) When multiplied by a duration of 1 year, the calculated probability is 1 - np.exp(-0.8)
, which is approximately 55%. >>> p*ss.years(1)
When multiplied by a scalar, the rate is simply scaled. >>> p*2
The difference between prob
and per
is subtle, but important. per
works directly with the instantaneous rate of an event occurring. In contrast, prob
starts with a probability and a duration, and the underlying rate is calculated. On multiplication by a duration, * per: rate -> probability * prob: probability -> rate -> probability
The behavior of both classes is depending on the data type of the object being multiplied.
ss.per
is identical to ss.freq
, except by default multiplication returns a probability rather than a number of events. Use ss.per
for probabilities (e.g., probability of death per year), and ss.freq
for events (e.g., number of acts per year).
Attributes
Name | Description |
---|---|
rate | Alias to self.value |
prob
self, value=None, unit=None, rate=None) time.prob(
prob
represents the probability of an event occurring during a specified period of time.
The class is designed to allow conversion of a probability from one duration to another through multiplication. However, the behavior of this conversion depends on the data type of the the object being multiplied.
When multiplied by a duration (type ss.dur), the underlying constant rate is calculated as rate = -np.log(1 - self.value)
. Then, the probability over the new duration is p = 1 - np.exp(-rate/factor)
, where factor
is the ratio of the new duration to the original duration.
For example, >>> p = ss.prob(0.8, ss.years(1)) indicates a 80% chance of an event occurring in one year.
p*ss.years(1) When multiplied by the original denominator, 1 year in this case, the probability remains unchanged, 80%.
p * ss.years(2) Multiplying
p
byss.years(2)
does not simply double the probability to 160% (which is not possible), but rather returns a new probability of 96% representing the chance of the event occurring at least once over the new duration of two years.
However, the behavior is different when a prob
object is multiplied by a scalar or array. In this case, the probability is simply scaled. This scaling may result in a value greater than 1, which is not valid. For example, >>> p * 2 raises an AssertionError because the resulting probability (160%) exceeds 100%.
Use per
instead if prob
if you would prefer to directly specify the instantaneous rate.
Methods
Name | Description |
---|---|
to_prob | Convert from one time probability to another |
to_prob
=None, scale=1.0) time.prob.to_prob(dur
Convert from one time probability to another
Parameters
Name | Type | Description | Default |
---|---|---|---|
dur | ss.dur |
the duration over which to convert the probability to | None |
scale | float | an optional additional mutliplicative scale factor to incorporate in the calculation | 1.0 |
Example:
p_month = ss.probpermonth(0.05)
p_year = p_month.to_prob(ss.year) # Slightly less than 0.05*12
Functions
Name | Description |
---|---|
rate | Backwards compatibility function for Rate |
rate_prob | Backwards compatibility function for per |
time_prob | Backwards compatibility function for prob |
rate
=None) time.rate(value, unit
Backwards compatibility function for Rate
rate_prob
=None) time.rate_prob(value, unit
Backwards compatibility function for per
time_prob
=None) time.time_prob(value, unit
Backwards compatibility function for prob