FD.io VPP  v19.08.1-401-g8e4ed521a
Vector Packet Processing
time_range.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vppinfra/time_range.h>
17 
18 void
19 clib_timebase_init (clib_timebase_t * tb, i32 timezone_offset_in_hours,
20  clib_timebase_daylight_time_t daylight_type)
21 {
22  clib_memset (tb, 0, sizeof (*tb));
23 
25  tb->time_zero = unix_time_now ();
26 
27  tb->timezone_offset = ((f64) (timezone_offset_in_hours)) * 3600.0;
28  tb->daylight_time_type = daylight_type;
29  switch (tb->daylight_time_type)
30  {
32  tb->summer_offset = 0.0;
33  break;
35  tb->summer_offset = 3600.0;
36  break;
37  default:
38  clib_warning ("unknown daylight type %d", tb->daylight_time_type);
40  tb->summer_offset = 0.0;
41  }
42 }
43 
44 const static u32 days_per_month[] = {
45  31, /* Jan */
46  28, /* Feb */
47  31, /* Mar */
48  30, /* Apr */
49  31, /* May */
50  30, /* Jun */
51  31, /* Jul */
52  31, /* Aug */
53  30, /* Sep */
54  31, /* Oct */
55  30, /* Nov */
56  31, /* Dec */
57 };
58 
59 const static char *month_short_names[] = {
60  "Jan",
61  "Feb",
62  "Mar",
63  "Apr",
64  "May",
65  "Jun",
66  "Jul",
67  "Aug",
68  "Sep",
69  "Oct",
70  "Nov",
71  "Dec",
72 };
73 
74 const static char *day_names_epoch_order[] = {
75  "Thu",
76  "Fri",
77  "Sat",
78  "Sun",
79  "Mon",
80  "Tue",
81  "Wed",
82 };
83 
84 const static char *day_names_calendar_order[] = {
85  "Sun",
86  "Mon",
87  "Tue",
88  "Wed",
89  "Thu",
90  "Fri",
91  "Sat",
92 };
93 
94 
95 void
97 {
98  u32 year, month, hours, minutes, seconds, nanoseconds;
99  u32 days_in_year, days_in_month, day_of_month;
100  u32 days_since_epoch;
101  u32 day_name_index;
102 
103  /* Unix epoch is 1/1/1970 00:00:00.00, a Thursday */
104 
105  year = 1970;
106  days_since_epoch = 0;
107 
108  do
109  {
110  days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
111  days_since_epoch += days_in_year;
112  now = now - ((f64) days_in_year) * 86400.0;
113  year++;
114  }
115  while (now > 0.0);
116 
117  days_since_epoch -= days_in_year;
118  now += ((f64) days_in_year) * 86400;
119  year--;
120 
121  month = 0;
122 
123  do
124  {
125  days_in_month = days_per_month[month];
126  if (month == 1 && clib_timebase_is_leap_year (year))
127  days_in_month++;
128 
129  days_since_epoch += days_in_month;
130  now = now - ((f64) days_in_month) * 86400.0;
131  month++;
132  }
133  while (now > 0.0);
134 
135  days_since_epoch -= days_in_month;
136  now += ((f64) days_in_month) * 86400;
137  month--;
138 
139  day_of_month = 1;
140  do
141  {
142  now = now - 86400;
143  day_of_month++;
144  days_since_epoch++;
145  }
146  while (now > 0.0);
147 
148  day_of_month--;
149  days_since_epoch--;
150  now += 86400.0;
151 
152  day_name_index = days_since_epoch % 7;
153 
154  hours = (u32) (now / (3600.0));
155  now -= (f64) (hours * 3600);
156 
157  minutes = (u32) (now / 60.0);
158  now -= (f64) (minutes * 60);
159 
160  seconds = (u32) (now);
161  now -= (f64) (seconds);
162 
163  nanoseconds = (f64) (now * 1e9);
164 
165  cp->year = year;
166  cp->month = month;
167  cp->day = day_of_month;
168  cp->day_name_index = day_name_index;
169  cp->hour = hours;
170  cp->minute = minutes;
171  cp->second = seconds;
172  cp->nanosecond = nanoseconds;
173  cp->fractional_seconds = now;
174 }
175 
176 f64
178 {
179  f64 now = 0;
180  u32 year, days_in_year, month, days_in_month;
181 
182  year = 1970;
183 
184  while (year < cp->year)
185  {
186  days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
187  now += ((f64) days_in_year) * 86400.0;
188  year++;
189  }
190 
191  month = 0;
192 
193  while (month < cp->month)
194  {
195  days_in_month = days_per_month[month];
196  if (month == 1 && clib_timebase_is_leap_year (year))
197  days_in_month++;
198 
199  now += ((f64) days_in_month) * 86400.0;
200  month++;
201  }
202 
203  now += ((f64) cp->day - 1) * 86400.0;
204  now += ((f64) cp->hour) * 3600.0;
205  now += ((f64) cp->minute) * 60.0;
206  now += ((f64) cp->second);
207  now += ((f64) cp->nanosecond) * 1e-9;
208 
209  return (now);
210 }
211 
212 f64
214 {
215  clib_timebase_component_t _c, *cp = &_c;
216 
217  clib_timebase_time_to_components (start_time, cp);
218 
219  /* back up to midnight */
220  cp->hour = cp->minute = cp->second = 0;
221 
222  start_time = clib_timebase_components_to_time (cp);
223 
224  while (cp->day_name_index != 3 /* sunday */ )
225  {
226  /* Back up one day */
227  start_time -= 86400.0;
228  clib_timebase_time_to_components (start_time, cp);
229  }
230  /* Clean up residual fraction */
231  start_time -= cp->fractional_seconds;
232  start_time += 1e-6; /* 1us inside Sunday */
233 
234  return (start_time);
235 }
236 
237 f64
239 {
240  int i;
241 
242  for (i = 0; i < ARRAY_LEN (day_names_calendar_order); i++)
243  {
244  if (!strncmp ((char *) day, day_names_calendar_order[i], 3))
245  return ((f64) i) * 86400.0;
246  }
247  return 0.0;
248 }
249 
250 
251 u8 *
252 format_clib_timebase_time (u8 * s, va_list * args)
253 {
254  f64 now = va_arg (*args, f64);
255  clib_timebase_component_t _c, *cp = &_c;
256 
258 
259  s = format (s, "%s, %u %s %u %u:%02u:%02u",
261  cp->day,
263  cp->year, cp->hour, cp->minute, cp->second);
264  return (s);
265 }
266 
267 uword
269 {
270  clib_timebase_range_t *rp = va_arg (*args, clib_timebase_range_t *);
271  clib_timebase_component_t _c, *cp = &_c;
272  u32 start_hour, start_minute, start_second;
273  u32 end_hour, end_minute, end_second;
274 
275  start_hour = start_minute = start_second
276  = end_hour = end_minute = end_second = 0;
277 
278  if (unformat (input, "%u:%u:%u - %u:%u:%u",
279  &start_hour, &start_minute, &start_second,
280  &end_hour, &end_minute, &end_second))
281  ;
282  else if (unformat (input, "%u:%u - %u:%u",
283  &start_hour, &start_minute, &end_hour, &end_minute))
284  ;
285  else if (unformat (input, "%u - %u", &start_hour, &end_hour))
286  ;
287  else
288  return 0;
289 
291 
292  cp->hour = start_hour;
293  cp->minute = start_minute;
294  cp->second = start_second;
295 
297 
298  cp->hour = end_hour;
299  cp->minute = end_minute;
300  cp->second = end_second;
301 
303 
304  return 1;
305 }
306 
307 uword
309 {
310  clib_timebase_range_t **rpp = va_arg (*args, clib_timebase_range_t **);
311  clib_timebase_range_t _tmp, *tmp = &_tmp;
312  clib_timebase_range_t *rp, *new_rp;
313  int day_range_match = 0;
314  int time_range_match = 0;
315  f64 range_start_time_offset;
316  f64 range_end_time_offset;
317  f64 now;
318  u8 *start_day = 0, *end_day = 0;
319 
320  rp = *rpp;
321 
322  while (1)
323  {
324  if (!day_range_match
325  && unformat (input, "%s - %s", &start_day, &end_day))
326  {
327  range_start_time_offset
328  = clib_timebase_offset_from_sunday (start_day);
329  range_end_time_offset = clib_timebase_offset_from_sunday (end_day);
330  vec_free (start_day);
331  vec_free (end_day);
332  day_range_match = 1;
333  time_range_match = 0;
334  }
335  else if (!day_range_match && unformat (input, "%s", &start_day))
336  {
337  range_start_time_offset
338  = clib_timebase_offset_from_sunday (start_day);
339  range_end_time_offset = range_start_time_offset + 86399.0;
340  day_range_match = 1;
341  vec_free (start_day);
342  day_range_match = 1;
343  time_range_match = 0;
344  }
345  else if (day_range_match &&
346  unformat (input, "%U", unformat_clib_timebase_range_hms, tmp))
347  {
348  /* Across the week... */
349  for (now = range_start_time_offset; now <= range_end_time_offset;
350  now += 86400.0)
351  {
352  vec_add2 (rp, new_rp, 1);
353  new_rp->start = now + tmp->start;
354  new_rp->end = now + tmp->end;
355  }
356  day_range_match = 0;
357  time_range_match = 1;
358  }
359  else if (time_range_match)
360  break;
361  else
362  {
363  vec_free (rp);
364  *rpp = 0;
365  return 0;
366  }
367  }
368 
369  if (time_range_match)
370  {
371  *rpp = rp;
372  return 1;
373  }
374  else
375  {
376  vec_free (rp);
377  *rpp = 0;
378  return 0;
379  }
380 }
381 
382 f64
384 {
385  clib_timebase_component_t _c, *cp = &_c;
386  f64 second_sunday_march_2am;
387  f64 first_sunday_november_2am;
388 
389  if (PREDICT_TRUE
390  (now >= tb->cached_year_start && now <= tb->cached_year_end))
391  {
392  if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
393  return tb->summer_offset;
394  else
395  return (0.0);
396  }
397 
399 
400  cp->month = 0;
401  cp->day = 1;
402  cp->hour = 0;
403  cp->minute = 0;
404  cp->second = 1;
405 
407 
408  cp->year += 1;
409 
411 
412  cp->year -= 1;
413 
414  /* Search for the second sunday in march, 2am */
415  cp->month = 2;
416  cp->day = 1;
417  cp->hour = 2;
418  cp->second = 0;
419  cp->nanosecond = 1;
420 
421  /* March 1st will never be the second sunday... */
422  second_sunday_march_2am = clib_timebase_components_to_time (cp);
423  cp->day_name_index = 0;
424 
425  /* Find the first sunday */
426  do
427  {
428  clib_timebase_time_to_components (second_sunday_march_2am, cp);
429  second_sunday_march_2am += 86400.0;
430  }
431  while (cp->day_name_index != 3 /* sunday */ );
432 
433  /* Find the second sunday */
434  do
435  {
436  clib_timebase_time_to_components (second_sunday_march_2am, cp);
437  second_sunday_march_2am += 86400.0;
438  }
439  while (cp->day_name_index != 3 /* sunday */ );
440 
441  second_sunday_march_2am -= 86400.0;
442 
443  tb->cached_summer_start = second_sunday_march_2am;
444 
445  /* Find the first sunday in November, which can easily be 11/1 */
446  cp->month = 10;
447  cp->day = 1;
448 
449  first_sunday_november_2am = clib_timebase_components_to_time (cp);
450  clib_timebase_time_to_components (first_sunday_november_2am, cp);
451 
452  while (cp->day_name_index != 3 /* sunday */ )
453  {
454  first_sunday_november_2am += 86400.0;
455  clib_timebase_time_to_components (first_sunday_november_2am, cp);
456  }
457 
458  tb->cached_summer_end = first_sunday_november_2am;
459 
460  if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
461  return tb->summer_offset;
462  else
463  return (0.0);
464 }
465 
466 /*
467  * fd.io coding-style-patch-verification: ON
468  *
469  * Local Variables:
470  * eval: (c-set-style "gnu")
471  * End:
472  */
#define PREDICT_TRUE(x)
Definition: clib.h:112
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
uword unformat_clib_timebase_range_vector(unformat_input_t *input, va_list *args)
Definition: time_range.c:308
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:560
int i
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
clib_timebase_daylight_time_t
Definition: time_range.h:22
f64 clib_timebase_offset_from_sunday(u8 *day)
Definition: time_range.c:238
f64 clib_timebase_components_to_time(clib_timebase_component_t *cp)
Definition: time_range.c:177
static f64 unix_time_now(void)
Definition: time.h:255
unsigned int u32
Definition: types.h:88
void clib_timebase_time_to_components(f64 now, clib_timebase_component_t *cp)
Definition: time_range.c:96
clib_timebase_daylight_time_t daylight_time_type
Definition: time_range.h:39
static const char * day_names_calendar_order[]
Definition: time_range.c:84
struct _unformat_input_t unformat_input_t
u8 * format_clib_timebase_time(u8 *s, va_list *args)
Definition: time_range.c:252
void clib_time_init(clib_time_t *c)
Definition: time.c:207
static const char * month_short_names[]
Definition: time_range.c:59
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
#define clib_warning(format, args...)
Definition: error.h:59
f64 clib_timebase_find_sunday_midnight(f64 start_time)
Definition: time_range.c:213
#define ARRAY_LEN(x)
Definition: clib.h:62
void clib_timebase_init(clib_timebase_t *tb, i32 timezone_offset_in_hours, clib_timebase_daylight_time_t daylight_type)
Definition: time_range.c:19
signed int i32
Definition: types.h:77
f64 cached_year_start
Definition: time_range.h:40
uword unformat_clib_timebase_range_hms(unformat_input_t *input, va_list *args)
Definition: time_range.c:268
f64 cached_summer_end
Definition: time_range.h:43
static int clib_timebase_is_leap_year(u32 year)
Definition: time_range.h:104
static const char * day_names_epoch_order[]
Definition: time_range.c:74
u64 uword
Definition: types.h:112
static const u32 days_per_month[]
Definition: time_range.c:44
f64 clib_timebase_summer_offset(clib_timebase_t *tb, f64 now)
Definition: time_range.c:383
f64 cached_summer_start
Definition: time_range.h:42
clib_time_t clib_time
Definition: time_range.h:31
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978