aboutsummaryrefslogtreecommitdiffstats
path: root/src/vppinfra/time_range.c
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2018-06-06 10:52:08 -0400
committerFlorin Coras <florin.coras@gmail.com>2018-06-08 23:19:09 +0000
commita98c40305deedc58860722fb9710075028c8b9f8 (patch)
tree4485e999df9e2e8113395f7d3843d664c387fc01 /src/vppinfra/time_range.c
parentf12dad658d03030d1a61ba970e27c8f01763f2e0 (diff)
Time range support for vppinfra
Change-Id: I2356b1e05fd868b46b4d26ade760900a5739ca4d Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'src/vppinfra/time_range.c')
-rw-r--r--src/vppinfra/time_range.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/src/vppinfra/time_range.c b/src/vppinfra/time_range.c
new file mode 100644
index 00000000000..e502ca358db
--- /dev/null
+++ b/src/vppinfra/time_range.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vppinfra/time_range.h>
+
+void
+clib_timebase_init (clib_timebase_t * tb, i32 timezone_offset_in_hours,
+ clib_timebase_daylight_time_t daylight_type)
+{
+ memset (tb, 0, sizeof (*tb));
+
+ clib_time_init (&tb->clib_time);
+ tb->time_zero = unix_time_now ();
+
+ tb->timezone_offset = ((f64) (timezone_offset_in_hours)) * 3600.0;
+ tb->daylight_time_type = daylight_type;
+ switch (tb->daylight_time_type)
+ {
+ case CLIB_TIMEBASE_DAYLIGHT_NONE:
+ tb->summer_offset = 0.0;
+ break;
+ case CLIB_TIMEBASE_DAYLIGHT_USA:
+ tb->summer_offset = 3600.0;
+ break;
+ default:
+ clib_warning ("unknown daylight type %d", tb->daylight_time_type);
+ tb->daylight_time_type = CLIB_TIMEBASE_DAYLIGHT_NONE;
+ tb->summer_offset = 0.0;
+ }
+}
+
+const static u32 days_per_month[] = {
+ 31, /* Jan */
+ 28, /* Feb */
+ 31, /* Mar */
+ 30, /* Apr */
+ 31, /* May */
+ 30, /* Jun */
+ 31, /* Jul */
+ 31, /* Aug */
+ 30, /* Sep */
+ 31, /* Oct */
+ 30, /* Nov */
+ 31, /* Dec */
+};
+
+const static char *month_short_names[] = {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+};
+
+const static char *day_names_epoch_order[] = {
+ "Thu",
+ "Fri",
+ "Sat",
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+};
+
+const static char *day_names_calendar_order[] = {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+};
+
+
+void
+clib_timebase_time_to_components (f64 now, clib_timebase_component_t * cp)
+{
+ u32 year, month, hours, minutes, seconds, nanoseconds;
+ u32 days_in_year, days_in_month, day_of_month;
+ u32 days_since_epoch;
+ u32 day_name_index;
+
+ /* Unix epoch is 1/1/1970 00:00:00.00, a Thursday */
+
+ year = 1970;
+ days_since_epoch = 0;
+
+ do
+ {
+ days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
+ days_since_epoch += days_in_year;
+ now = now - ((f64) days_in_year) * 86400.0;
+ year++;
+ }
+ while (now > 0.0);
+
+ days_since_epoch -= days_in_year;
+ now += ((f64) days_in_year) * 86400;
+ year--;
+
+ month = 0;
+
+ do
+ {
+ days_in_month = days_per_month[month];
+ if (month == 1 && clib_timebase_is_leap_year (year))
+ days_in_month++;
+
+ days_since_epoch += days_in_month;
+ now = now - ((f64) days_in_month) * 86400.0;
+ month++;
+ }
+ while (now > 0.0);
+
+ days_since_epoch -= days_in_month;
+ now += ((f64) days_in_month) * 86400;
+ month--;
+
+ day_of_month = 1;
+ do
+ {
+ now = now - 86400;
+ day_of_month++;
+ days_since_epoch++;
+ }
+ while (now > 0.0);
+
+ day_of_month--;
+ days_since_epoch--;
+ now += 86400.0;
+
+ day_name_index = days_since_epoch % 7;
+
+ hours = (u32) (now / (3600.0));
+ now -= (f64) (hours * 3600);
+
+ minutes = (u32) (now / 60.0);
+ now -= (f64) (minutes * 60);
+
+ seconds = (u32) (now);
+ now -= (f64) (seconds);
+
+ nanoseconds = (f64) (now * 1e9);
+
+ cp->year = year;
+ cp->month = month;
+ cp->day = day_of_month;
+ cp->day_name_index = day_name_index;
+ cp->hour = hours;
+ cp->minute = minutes;
+ cp->second = seconds;
+ cp->nanosecond = nanoseconds;
+ cp->fractional_seconds = now;
+}
+
+f64
+clib_timebase_components_to_time (clib_timebase_component_t * cp)
+{
+ f64 now = 0;
+ u32 year, days_in_year, month, days_in_month;
+
+ year = 1970;
+
+ while (year < cp->year)
+ {
+ days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
+ now += ((f64) days_in_year) * 86400.0;
+ year++;
+ }
+
+ month = 0;
+
+ while (month < cp->month)
+ {
+ days_in_month = days_per_month[month];
+ if (month == 1 && clib_timebase_is_leap_year (year))
+ days_in_month++;
+
+ now += ((f64) days_in_month) * 86400.0;
+ month++;
+ }
+
+ now += ((f64) cp->day - 1) * 86400.0;
+ now += ((f64) cp->hour) * 3600.0;
+ now += ((f64) cp->minute) * 60.0;
+ now += ((f64) cp->second);
+ now += ((f64) cp->nanosecond) * 1e-9;
+
+ return (now);
+}
+
+f64
+clib_timebase_find_sunday_midnight (f64 start_time)
+{
+ clib_timebase_component_t _c, *cp = &_c;
+
+ clib_timebase_time_to_components (start_time, cp);
+
+ /* back up to midnight */
+ cp->hour = cp->minute = cp->second = 0;
+
+ start_time = clib_timebase_components_to_time (cp);
+
+ while (cp->day_name_index != 3 /* sunday */ )
+ {
+ /* Back up one day */
+ start_time -= 86400.0;
+ clib_timebase_time_to_components (start_time, cp);
+ }
+ /* Clean up residual fraction */
+ start_time -= cp->fractional_seconds;
+ start_time += 1e-6; /* 1us inside Sunday */
+
+ return (start_time);
+}
+
+f64
+clib_timebase_offset_from_sunday (u8 * day)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LEN (day_names_calendar_order); i++)
+ {
+ if (!strncmp ((char *) day, day_names_calendar_order[i], 3))
+ return ((f64) i) * 86400.0;
+ }
+ return 0.0;
+}
+
+
+u8 *
+format_clib_timebase_time (u8 * s, va_list * args)
+{
+ f64 now = va_arg (*args, f64);
+ clib_timebase_component_t _c, *cp = &_c;
+
+ clib_timebase_time_to_components (now, cp);
+
+ s = format (s, "%s, %u %s %u %u:%02u:%02u",
+ day_names_epoch_order[cp->day_name_index],
+ cp->day,
+ month_short_names[cp->month],
+ cp->year, cp->hour, cp->minute, cp->second);
+ return (s);
+}
+
+uword
+unformat_clib_timebase_range_hms (unformat_input_t * input, va_list * args)
+{
+ clib_timebase_range_t *rp = va_arg (*args, clib_timebase_range_t *);
+ clib_timebase_component_t _c, *cp = &_c;
+ u32 start_hour, start_minute, start_second;
+ u32 end_hour, end_minute, end_second;
+
+ start_hour = start_minute = start_second
+ = end_hour = end_minute = end_second = 0;
+
+ if (unformat (input, "%u:%u:%u - %u:%u:%u",
+ &start_hour, &start_minute, &start_second,
+ &end_hour, &end_minute, &end_second))
+ ;
+ else if (unformat (input, "%u:%u - %u:%u",
+ &start_hour, &start_minute, &end_hour, &end_minute))
+ ;
+ else if (unformat (input, "%u - %u", &start_hour, &end_hour))
+ ;
+ else
+ return 0;
+
+ clib_timebase_time_to_components (1e-6, cp);
+
+ cp->hour = start_hour;
+ cp->minute = start_minute;
+ cp->second = start_second;
+
+ rp->start = clib_timebase_components_to_time (cp);
+
+ cp->hour = end_hour;
+ cp->minute = end_minute;
+ cp->second = end_second;
+
+ rp->end = clib_timebase_components_to_time (cp);
+
+ return 1;
+}
+
+uword
+unformat_clib_timebase_range_vector (unformat_input_t * input, va_list * args)
+{
+ clib_timebase_range_t **rpp = va_arg (*args, clib_timebase_range_t **);
+ clib_timebase_range_t _tmp, *tmp = &_tmp;
+ clib_timebase_range_t *rp, *new_rp;
+ int day_range_match = 0;
+ int time_range_match = 0;
+ f64 range_start_time_offset;
+ f64 range_end_time_offset;
+ f64 now;
+ u8 *start_day = 0, *end_day = 0;
+
+ rp = *rpp;
+
+ while (1)
+ {
+ if (!day_range_match
+ && unformat (input, "%s - %s", &start_day, &end_day))
+ {
+ range_start_time_offset
+ = clib_timebase_offset_from_sunday (start_day);
+ range_end_time_offset = clib_timebase_offset_from_sunday (end_day);
+ vec_free (start_day);
+ vec_free (end_day);
+ day_range_match = 1;
+ time_range_match = 0;
+ }
+ else if (!day_range_match && unformat (input, "%s", &start_day))
+ {
+ range_start_time_offset
+ = clib_timebase_offset_from_sunday (start_day);
+ range_end_time_offset = range_start_time_offset + 86399.0;
+ day_range_match = 1;
+ vec_free (start_day);
+ day_range_match = 1;
+ time_range_match = 0;
+ }
+ else if (day_range_match &&
+ unformat (input, "%U", unformat_clib_timebase_range_hms, tmp))
+ {
+ /* Across the week... */
+ for (now = range_start_time_offset; now <= range_end_time_offset;
+ now += 86400.0)
+ {
+ vec_add2 (rp, new_rp, 1);
+ new_rp->start = now + tmp->start;
+ new_rp->end = now + tmp->end;
+ }
+ day_range_match = 0;
+ time_range_match = 1;
+ }
+ else if (time_range_match)
+ break;
+ else
+ {
+ vec_free (rp);
+ *rpp = 0;
+ return 0;
+ }
+ }
+
+ if (time_range_match)
+ {
+ *rpp = rp;
+ return 1;
+ }
+ else
+ {
+ vec_free (rp);
+ *rpp = 0;
+ return 0;
+ }
+}
+
+f64
+clib_timebase_summer_offset (clib_timebase_t * tb, f64 now)
+{
+ clib_timebase_component_t _c, *cp = &_c;
+ f64 second_sunday_march_2am;
+ f64 first_sunday_november_2am;
+
+ if (PREDICT_TRUE
+ (now >= tb->cached_year_start && now <= tb->cached_year_end))
+ {
+ if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
+ return tb->summer_offset;
+ else
+ return (0.0);
+ }
+
+ clib_timebase_time_to_components (now, cp);
+
+ cp->month = 0;
+ cp->day = 1;
+ cp->hour = 0;
+ cp->minute = 0;
+ cp->second = 1;
+
+ tb->cached_year_start = clib_timebase_components_to_time (cp);
+
+ cp->year += 1;
+
+ tb->cached_year_end = clib_timebase_components_to_time (cp);
+
+ cp->year -= 1;
+
+ /* Search for the second sunday in march, 2am */
+ cp->month = 2;
+ cp->day = 1;
+ cp->hour = 2;
+ cp->second = 0;
+ cp->nanosecond = 1;
+
+ /* March 1st will never be the second sunday... */
+ second_sunday_march_2am = clib_timebase_components_to_time (cp);
+ cp->day_name_index = 0;
+
+ /* Find the first sunday */
+ do
+ {
+ clib_timebase_time_to_components (second_sunday_march_2am, cp);
+ second_sunday_march_2am += 86400.0;
+ }
+ while (cp->day_name_index != 3 /* sunday */ );
+
+ /* Find the second sunday */
+ do
+ {
+ clib_timebase_time_to_components (second_sunday_march_2am, cp);
+ second_sunday_march_2am += 86400.0;
+ }
+ while (cp->day_name_index != 3 /* sunday */ );
+
+ second_sunday_march_2am -= 86400.0;
+
+ tb->cached_summer_start = second_sunday_march_2am;
+
+ /* Find the first sunday in November, which can easily be 11/1 */
+ cp->month = 10;
+ cp->day = 1;
+
+ first_sunday_november_2am = clib_timebase_components_to_time (cp);
+ clib_timebase_time_to_components (first_sunday_november_2am, cp);
+
+ while (cp->day_name_index != 3 /* sunday */ )
+ {
+ first_sunday_november_2am += 86400.0;
+ clib_timebase_time_to_components (first_sunday_november_2am, cp);
+ }
+
+ tb->cached_summer_end = first_sunday_november_2am;
+
+ if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
+ return tb->summer_offset;
+ else
+ return (0.0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */