| Title: | Time-Series Management Made Easy |
|---|---|
| Description: | Manage time-series data frames across time zones, resolutions, and date ranges, while filling gaps using weekday/hour patterns or simple fill helpers or plotting them interactively. It is designed to work seamlessly with the tidyverse and dygraphs environments. |
| Authors: | Marc Cañigueral [aut, cre] (ORCID: <https://orcid.org/0000-0001-9724-5829>) |
| Maintainer: | Marc Cañigueral <[email protected]> |
| License: | GPL-3 |
| Version: | 0.1.1 |
| Built: | 2026-06-03 13:56:04 UTC |
| Source: | https://github.com/resourcefully-dev/timefully |
This function adapts the date range of a time series by reusing historical patterns based on the same weekday occurrence within the year and decimal hour of the day. It also can fill gaps in the data based on past data, so it is recommended to use it for time series with weekly or yearly patterns (so for example energy demand but not solar generation). It can also adapt the timezone of the time series, for example if the data was stored in UTC but corresponds to a different timezone.
adapt_timeseries(dtf, start_date, end_date, tzone = NULL, fill_gaps = FALSE)adapt_timeseries(dtf, start_date, end_date, tzone = NULL, fill_gaps = FALSE)
dtf |
data.frame or tibble, first column of name |
start_date |
Date, start date of the output datetime sequence |
end_date |
Date, end date of the output datetime sequence (included) |
tzone |
character, desired time-zone of the datetime sequence.
If NULL, the timezone of |
fill_gaps |
boolean, whether to fill gaps based on
same weekday and hour from past data (See |
tibble
# Example data set print(dtf) # Original date range range(dtf$datetime) dtf2 <- adapt_timeseries( dtf, start_date = as.Date("2021-01-01"), end_date = as.Date("2021-01-31"), tzone = "America/New_York", fill_gaps = FALSE ) # New date range range(dtf2$datetime)# Example data set print(dtf) # Original date range range(dtf$datetime) dtf2 <- adapt_timeseries( dtf, start_date = as.Date("2021-01-01"), end_date = as.Date("2021-01-31"), tzone = "America/New_York", fill_gaps = FALSE ) # New date range range(dtf2$datetime)
Add an extra day at the beginning and the end of datetime sequence using the last and first day of the data
add_extra_days(dtf)add_extra_days(dtf)
dtf |
data.frame or tibble, first column of name |
tibble
The first column datetime will be kept.
aggregate_timeseries(dtf, varname, omit = NULL)aggregate_timeseries(dtf, varname, omit = NULL)
dtf |
data.frame or tibble, first column of name |
varname |
character, name of the aggregation column |
omit |
character, name of columns to not aggregate |
tibble
building_flows <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, building1 = c(2.1, 2.5, 2.3, 2.0), building2 = c(1.0, 1.1, 0.9, 1.2) ) aggregate_timeseries(building_flows, varname = "total_building")building_flows <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, building1 = c(2.1, 2.5, 2.3, 2.0), building2 = c(1.0, 1.1, 0.9, 1.2) ) aggregate_timeseries(building_flows, varname = "total_building")
Change time resolution of a time-series data frame
change_timeseries_resolution(dtf, resolution, method)change_timeseries_resolution(dtf, resolution, method)
dtf |
data.frame or tibble, first column of name |
resolution |
integer, desired interval of minutes between two consecutive datetime values |
method |
character, being |
tibble
fifteen_min <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:7 * 900, load = c(10, 12, 14, 16, 14, 12, 10, 8) ) change_timeseries_resolution( fifteen_min, resolution = 60, method = "average" )fifteen_min <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:7 * 900, load = c(10, 12, 14, 16, 14, 12, 10, 8) ) change_timeseries_resolution( fifteen_min, resolution = 60, method = "average" )
The timezone of the datetime column is changed while
keeping the same date time sequence.
This is useful when the time series data is known to be in a different timezone.
If you just want the same time series in a different timezone,
use lubridate::force_tz function instead.
change_timeseries_tzone(dtf, tzone = "Europe/Amsterdam")change_timeseries_tzone(dtf, tzone = "Europe/Amsterdam")
dtf |
data.frame or tibble, first column of name |
tzone |
character, desired time-zone of the datetime sequence |
tibble
# Example data set get_timeseries_tzone(dtf) range(dtf$datetime) # Change timezone new_dtf <- change_timeseries_tzone(dtf, tzone = "Europe/Paris") get_timeseries_tzone(new_dtf) range(new_dtf$datetime)# Example data set get_timeseries_tzone(dtf) range(dtf$datetime) # Change timezone new_dtf <- change_timeseries_tzone(dtf, tzone = "Europe/Paris") get_timeseries_tzone(new_dtf) range(new_dtf$datetime)
Convert numeric time value to a datetime period (hour-based)
convert_time_num_to_period(time_num)convert_time_num_to_period(time_num)
time_num |
Numeric time value (hour-based) |
lubridate::period vector with hours and minutes corresponding to
the numeric input.
convert_time_num_to_period(1.5) convert_time_num_to_period(c(0.25, 2))convert_time_num_to_period(1.5) convert_time_num_to_period(c(0.25, 2))
Convert date or datetime value to timestamp number
date_to_timestamp(date, tzone = "Europe/Paris", milliseconds = TRUE)date_to_timestamp(date, tzone = "Europe/Paris", milliseconds = TRUE)
date |
date or datetime value |
tzone |
character, time-zone of the current time |
milliseconds |
logical, whether the timestamp is in milliseconds or seconds |
numeric
date_to_timestamp(as.Date("2024-01-01")) date_to_timestamp(as.POSIXct("2024-01-01 08:00:00", tz = "UTC"), milliseconds = FALSE)date_to_timestamp(as.Date("2024-01-01")) date_to_timestamp(as.POSIXct("2024-01-01 08:00:00", tz = "UTC"), milliseconds = FALSE)
Fill down tibble columns until a maximum number of time slots
fill_down_until(dtf, varnames, max_timeslots = 1)fill_down_until(dtf, varnames, max_timeslots = 1)
dtf |
data.frame or tibble, first column of name |
varnames |
character or vector of characters, column names with NA values |
max_timeslots |
integer, maximum number of time slots to fill |
tibble
down_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:5 * 3600, temperature = c(15, 15, NA, NA, NA, 16) ) fill_down_until(down_data, "temperature", max_timeslots = 2)down_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:5 * 3600, temperature = c(15, 15, NA, NA, NA, 16) ) fill_down_until(down_data, "temperature", max_timeslots = 2)
If back index ( NA index - back) is lower than zero then the it is filled with the first value of the data frame.
If the value in the back index is also NA, it iterates backwards until finding a non-NA value.
fill_from_past(dtf, varnames, back = 24)fill_from_past(dtf, varnames, back = 24)
dtf |
data.frame or tibble, first column of name |
varnames |
character or vector of characters, column names with NA values |
back |
integer, number of indices (rows) to go back and get the filling value |
tibble or data.frame
past_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, consumption = c(1.2, NA, NA, 2.5) ) fill_from_past(past_data, "consumption", back = 1)past_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, consumption = c(1.2, NA, NA, 2.5) ) fill_from_past(past_data, "consumption", back = 1)
This is useful when the gaps in a numeric timeseries can be filled with the same number (e.g. zero)
fill_na(dtf, varnames, with = 0)fill_na(dtf, varnames, with = 0)
dtf |
data.frame or tibble, first column of name |
varnames |
character or vector of characters, column names with NA values |
with |
numeric, value to fill NA values |
tibble or data.frame
past_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, consumption = c(1.2, NA, NA, 2.5) ) fill_na(past_data, "consumption", with = 0)past_data <- data.frame( datetime = as.POSIXct("2024-01-01 00:00:00", tz = "UTC") + 0:3 * 3600, consumption = c(1.2, NA, NA, 2.5) ) fill_na(past_data, "consumption", with = 0)
Format datetime axis
format_datetime_axis(format_list, locale = "nl-NL")format_datetime_axis(format_list, locale = "nl-NL")
format_list |
(named list) ORDER matters key and type of output as value |
locale |
(str) locale to use in settings for example nl-NL (default) |
The format_list entries map to the JavaScript toLocaleString options:
| Option | Value | Description | Example (nl-NL) |
| year | "numeric" | Full year | "2023" |
| year | "2-digit" | Last two digits of the year | "23" |
| month | "numeric" | Month as a number | "1" |
| month | "2-digit" | Month as a two-digit number | "01" |
| month | "long" | Full month name | "januari" |
| month | "short" | Abbreviated month name | "jan." |
| day | "numeric" | Day of the month | "5" |
| day | "2-digit" | Day with leading zero | "05" |
| weekday | "long" | Full weekday name | "vrijdag" |
| weekday | "short" | Abbreviated weekday name | "vr." |
| weekday | "narrow" | Single-letter weekday | "V" |
| hour | "numeric" | Hour (24-hour format by default) | "14" |
| hour | "2-digit" | Two-digit hour | "14" |
| minute | "numeric" | Minute | "30" |
| minute | "2-digit" | Two-digit minute | "30" |
| second | "numeric" | Second | "15" |
| second | "2-digit" | Two-digit second | "15" |
js code as a string to change datetime axis
JS function to pass to dyAxis function
## Not run: dyplot <- plot_ts(dtf) xaxis_format <- format_date_axis( list(day = "2-digit", month = "short"), locale = "nl_NL" ) dyplot |> dyAxis("x", axisLabelFormatter = JS(xaxis_format)) ## End(Not run)## Not run: dyplot <- plot_ts(dtf) xaxis_format <- format_date_axis( list(day = "2-digit", month = "short"), locale = "nl_NL" ) dyplot |> dyAxis("x", axisLabelFormatter = JS(xaxis_format)) ## End(Not run)
Date time sequence with time zone and resolution
get_datetime_seq(start_date, end_date, tzone, resolution)get_datetime_seq(start_date, end_date, tzone, resolution)
start_date |
Date, start date of the output datetime sequence |
end_date |
Date, end date of the output datetime sequence (included) |
tzone |
character, desired time-zone of the datetime sequence |
resolution |
integer, interval of minutes between two consecutive datetime values |
vector of datetime values
get_datetime_seq( start_date = as.Date("2024-01-01"), end_date = as.Date("2024-01-03"), tzone = "UTC", resolution = 120 )get_datetime_seq( start_date = as.Date("2024-01-01"), end_date = as.Date("2024-01-03"), tzone = "UTC", resolution = 120 )
Return the time resolution of a datetime sequence
get_time_resolution(dttm_seq, units = "mins")get_time_resolution(dttm_seq, units = "mins")
dttm_seq |
datetime sequence |
units |
character being one of "auto", "secs", "mins", "hours", "days" and "weeks" |
numeric
seq_15m <- as.POSIXct( c("2024-01-01 00:00:00", "2024-01-01 00:15:00", "2024-01-01 00:30:00"), tz = "UTC" ) get_time_resolution(seq_15m, units = "mins")seq_15m <- as.POSIXct( c("2024-01-01 00:00:00", "2024-01-01 00:15:00", "2024-01-01 00:30:00"), tz = "UTC" ) get_time_resolution(seq_15m, units = "mins")
Return the time resolution of a time series dataframe
get_timeseries_resolution(dtf, units = "mins")get_timeseries_resolution(dtf, units = "mins")
dtf |
data.frame or tibble, first column of name |
units |
character being one of "auto", "secs", "mins", "hours", "days" and "weeks" |
numeric
get_timeseries_resolution(dtf, units = "mins")get_timeseries_resolution(dtf, units = "mins")
Get the time zone of a time series dataframe
get_timeseries_tzone(dtf)get_timeseries_tzone(dtf)
dtf |
data.frame or tibble, first column of name |
character
get_timeseries_tzone(dtf)get_timeseries_tzone(dtf)
Week date from datetime value
get_week_from_datetime(dttm)get_week_from_datetime(dttm)
dttm |
datetime vector |
date vector
dttm <- as.POSIXct( c("2024-01-01 08:00:00", "2024-01-02 09:00:00", "2024-01-08 10:00:00"), tz = "UTC" ) get_week_from_datetime(dttm)dttm <- as.POSIXct( c("2024-01-01 08:00:00", "2024-01-02 09:00:00", "2024-01-08 10:00:00"), tz = "UTC" ) get_week_from_datetime(dttm)
Converts the numeric columns of a time-series data frame to total values per week (sum). Note that if the input values are in power units (e.g., kW), the output values will be in energy units (e.g., kWh).
get_week_total(dtf)get_week_total(dtf)
dtf |
data.frame or tibble, first column of name |
tibble
get_week_total(dtf[1:100, ])get_week_total(dtf[1:100, ])
Yearly date time sequence with time zone and resolution
get_yearly_datetime_seq(year, tzone, resolution)get_yearly_datetime_seq(year, tzone, resolution)
year |
integer, year of the datetime sequence |
tzone |
character, desired time-zone of the datetime sequence |
resolution |
integer, interval of minutes between two consecutive datetime values |
vector of datetime values
get_yearly_datetime_seq( year = 2024, tzone = "UTC", resolution = 60 )get_yearly_datetime_seq( year = 2024, tzone = "UTC", resolution = 60 )
Note that timefully considers a full datetime sequence when days are complete.
has_timeseries_gaps(dtf)has_timeseries_gaps(dtf)
dtf |
data.frame or tibble, first column of name |
logical, TRUE when there are missing time slots
has_timeseries_gaps(dtf) dtf_gaps <- dtf[c(1:3, 7:10), ] has_timeseries_gaps(dtf_gaps)has_timeseries_gaps(dtf) dtf_gaps <- dtf[c(1:3, 7:10), ] has_timeseries_gaps(dtf_gaps)
Expands dtf onto the complete datetime sequence that spans the same date
range at the same resolution, inserting the missing time slots as rows with
NA values. Note that timefully considers a full datetime sequence when
days are complete.
pad_timeseries(dtf, verbose = TRUE)pad_timeseries(dtf, verbose = TRUE)
dtf |
data.frame or tibble, first column of name |
verbose |
logical, when |
tibble
# Sample just some hours dtf_gaps <- dtf[c(1:3, 7:10), ] # Note that the full day is provided pad_timeseries( dtf_gaps )# Sample just some hours dtf_gaps <- dtf[c(1:3, 7:10), ] # Note that the full day is provided pad_timeseries( dtf_gaps )
First column of the df tibble must be a datetime or date variable.
The rest of columns must be numeric of the same units. This functions makes
use of dygraphs package to generate an HTML dygraphs plot.
plot_ts( df, title = NULL, xlab = NULL, ylab = NULL, legend_show = "auto", legend_width = 250, group = NULL, width = NULL, height = NULL, ... )plot_ts( df, title = NULL, xlab = NULL, ylab = NULL, legend_show = "auto", legend_width = 250, group = NULL, width = NULL, height = NULL, ... )
df |
data.frame or tibble, first column of name |
title |
character, title of the plot (accepts HTML code) |
xlab |
character, X axis label (accepts HTML code) |
ylab |
character, Y axis label (accepts HTML code) |
legend_show |
character, when to display the legend. Specify "always" to always show the legend. Specify "onmouseover" to only display it when a user mouses over the chart. Specify "follow" to have the legend show as overlay to the chart which follows the mouse. The default behavior is "auto", which results in "always" when more than one series is plotted and "onmouseover" when only a single series is plotted. |
legend_width |
integer, width (in pixels) of the div which shows the legend. |
group |
character, dygraphs group to associate this plot with. The x-axis zoom level of dygraphs plots within a group is automatically synchronized. |
width |
Width in pixels (optional, defaults to automatic sizing) |
height |
Height in pixels (optional, defaults to automatic sizing) |
... |
extra arguments to pass to |
dygraph
plot_ts(dtf, ylab = "kW", legend_show = "onmouseover")plot_ts(dtf, ylab = "kW", legend_show = "onmouseover")
Use this function together with toc() to control time spent by functions
tic()tic()
numeric
Builds the complete datetime sequence that would span the same date range
(full days) at the same resolution as dttm_seq and returns the datetime
values that are missing from it. Note that timefully considers a full
datetime sequence when days are complete.
time_gaps(dttm_seq)time_gaps(dttm_seq)
dttm_seq |
datetime sequence |
vector of datetime values missing from dttm_seq
seq_15m <- get_datetime_seq( start_date = as.Date("2024-01-01"), end_date = as.Date("2024-01-01"), tzone = "UTC", resolution = 15 ) # Drop a couple of slots to create gaps time_gaps(seq_15m[-c(5, 6)])seq_15m <- get_datetime_seq( start_date = as.Date("2024-01-01"), end_date = as.Date("2024-01-01"), tzone = "UTC", resolution = 15 ) # Drop a couple of slots to create gaps time_gaps(seq_15m[-c(5, 6)])
Convert a number of minutes in string format "HH:MM"
to_hhmm(mins)to_hhmm(mins)
mins |
integer, number of minutes (from 0 to 1439) |
character
to_hhmm(75)to_hhmm(75)
Use this function together with tic() to control time spent by functions
toc(units = "secs", digits = 2)toc(units = "secs", digits = 2)
units |
character, one of "auto", "secs", "mins", "hours", "days" and "weeks" |
digits |
integer, number of decimals |
numeric