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