LCOV - code coverage report
Current view: top level - vppinfra - time_range.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 196 216 90.7 %
Date: 2023-07-05 22:20:52 Functions: 9 9 100.0 %

          Line data    Source code
       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             : __clib_export void
      19          89 : 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          89 :   clib_memset (tb, 0, sizeof (*tb));
      24             : 
      25          89 :   if (clib_time == 0)
      26             :     {
      27           0 :       tb->clib_time = clib_mem_alloc_aligned
      28             :         (sizeof (*clib_time), CLIB_CACHE_LINE_BYTES);
      29           0 :       memset (tb->clib_time, 0, sizeof (*clib_time));
      30           0 :       clib_time_init (tb->clib_time);
      31             :     }
      32             :   else
      33          89 :     tb->clib_time = clib_time;
      34             : 
      35          89 :   tb->timezone_offset = ((f64) (timezone_offset_in_hours)) * 3600.0;
      36          89 :   tb->daylight_time_type = daylight_type;
      37          89 :   switch (tb->daylight_time_type)
      38             :     {
      39          88 :     case CLIB_TIMEBASE_DAYLIGHT_NONE:
      40          88 :       tb->summer_offset = 0.0;
      41          88 :       break;
      42           1 :     case CLIB_TIMEBASE_DAYLIGHT_USA:
      43           1 :       tb->summer_offset = 3600.0;
      44           1 :       break;
      45           0 :     default:
      46           0 :       clib_warning ("unknown daylight type %d", tb->daylight_time_type);
      47           0 :       tb->daylight_time_type = CLIB_TIMEBASE_DAYLIGHT_NONE;
      48           0 :       tb->summer_offset = 0.0;
      49             :     }
      50          89 : }
      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             : __clib_export void
     104         806 : clib_timebase_time_to_components (f64 now, clib_timebase_component_t * cp)
     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         806 :   year = 1970;
     114         806 :   days_since_epoch = 0;
     115             : 
     116             :   do
     117             :     {
     118       43077 :       days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
     119       43077 :       days_since_epoch += days_in_year;
     120       43077 :       now = now - ((f64) days_in_year) * 86400.0;
     121       43077 :       year++;
     122             :     }
     123       43077 :   while (now > 0.0);
     124             : 
     125         806 :   days_since_epoch -= days_in_year;
     126         806 :   now += ((f64) days_in_year) * 86400;
     127         806 :   year--;
     128             : 
     129         806 :   month = 0;
     130             : 
     131             :   do
     132             :     {
     133        4472 :       days_in_month = days_per_month[month];
     134        4472 :       if (month == 1 && clib_timebase_is_leap_year (year))
     135           0 :         days_in_month++;
     136             : 
     137        4472 :       days_since_epoch += days_in_month;
     138        4472 :       now = now - ((f64) days_in_month) * 86400.0;
     139        4472 :       month++;
     140             :     }
     141        4472 :   while (now > 0.0);
     142             : 
     143         806 :   days_since_epoch -= days_in_month;
     144         806 :   now += ((f64) days_in_month) * 86400;
     145         806 :   month--;
     146             : 
     147         806 :   day_of_month = 1;
     148             :   do
     149             :     {
     150        4369 :       now = now - 86400;
     151        4369 :       day_of_month++;
     152        4369 :       days_since_epoch++;
     153             :     }
     154        4369 :   while (now > 0.0);
     155             : 
     156         806 :   day_of_month--;
     157         806 :   days_since_epoch--;
     158         806 :   now += 86400.0;
     159             : 
     160         806 :   day_name_index = days_since_epoch % 7;
     161             : 
     162         806 :   hours = (u32) (now / (3600.0));
     163         806 :   now -= (f64) (hours * 3600);
     164             : 
     165         806 :   minutes = (u32) (now / 60.0);
     166         806 :   now -= (f64) (minutes * 60);
     167             : 
     168         806 :   seconds = (u32) (now);
     169         806 :   now -= (f64) (seconds);
     170             : 
     171         806 :   nanoseconds = (f64) (now * 1e9);
     172             : 
     173         806 :   cp->year = year;
     174         806 :   cp->month = month;
     175         806 :   cp->day = day_of_month;
     176         806 :   cp->day_name_index = day_name_index;
     177         806 :   cp->hour = hours;
     178         806 :   cp->minute = minutes;
     179         806 :   cp->second = seconds;
     180         806 :   cp->nanosecond = nanoseconds;
     181         806 :   cp->fractional_seconds = now;
     182         806 : }
     183             : 
     184             : __clib_export f64
     185         174 : clib_timebase_components_to_time (clib_timebase_component_t * cp)
     186             : {
     187         174 :   f64 now = 0;
     188             :   u32 year, days_in_year, month, days_in_month;
     189             : 
     190         174 :   year = 1970;
     191             : 
     192        9047 :   while (year < cp->year)
     193             :     {
     194        8873 :       days_in_year = clib_timebase_is_leap_year (year) ? 366 : 365;
     195        8873 :       now += ((f64) days_in_year) * 86400.0;
     196        8873 :       year++;
     197             :     }
     198             : 
     199         174 :   month = 0;
     200             : 
     201         690 :   while (month < cp->month)
     202             :     {
     203         516 :       days_in_month = days_per_month[month];
     204         516 :       if (month == 1 && clib_timebase_is_leap_year (year))
     205           0 :         days_in_month++;
     206             : 
     207         516 :       now += ((f64) days_in_month) * 86400.0;
     208         516 :       month++;
     209             :     }
     210             : 
     211         174 :   now += ((f64) cp->day - 1) * 86400.0;
     212         174 :   now += ((f64) cp->hour) * 3600.0;
     213         174 :   now += ((f64) cp->minute) * 60.0;
     214         174 :   now += ((f64) cp->second);
     215         174 :   now += ((f64) cp->nanosecond) * 1e-9;
     216             : 
     217         174 :   return (now);
     218             : }
     219             : 
     220             : __clib_export f64
     221           1 : clib_timebase_find_sunday_midnight (f64 start_time)
     222             : {
     223           1 :   clib_timebase_component_t _c, *cp = &_c;
     224             : 
     225           1 :   clib_timebase_time_to_components (start_time, cp);
     226             : 
     227             :   /* back up to midnight */
     228           1 :   cp->hour = cp->minute = cp->second = 0;
     229             : 
     230           1 :   start_time = clib_timebase_components_to_time (cp);
     231             : 
     232           4 :   while (cp->day_name_index != 3 /* sunday */ )
     233             :     {
     234             :       /* Back up one day */
     235           3 :       start_time -= 86400.0;
     236           3 :       clib_timebase_time_to_components (start_time, cp);
     237             :     }
     238             :   /* Clean up residual fraction */
     239           1 :   start_time -= cp->fractional_seconds;
     240           1 :   start_time += 1e-6;           /* 1us inside Sunday  */
     241             : 
     242           1 :   return (start_time);
     243             : }
     244             : 
     245             : f64
     246           4 : clib_timebase_offset_from_sunday (u8 * day)
     247             : {
     248             :   int i;
     249             : 
     250          15 :   for (i = 0; i < ARRAY_LEN (day_names_calendar_order); i++)
     251             :     {
     252          15 :       if (!strncmp ((char *) day, day_names_calendar_order[i], 3))
     253           4 :         return ((f64) i) * 86400.0;
     254             :     }
     255           0 :   return 0.0;
     256             : }
     257             : 
     258             : 
     259             : __clib_export u8 *
     260          56 : format_clib_timebase_time (u8 * s, va_list * args)
     261             : {
     262          56 :   f64 now = va_arg (*args, f64);
     263          56 :   clib_timebase_component_t _c, *cp = &_c;
     264             : 
     265          56 :   clib_timebase_time_to_components (now, cp);
     266             : 
     267          56 :   s = format (s, "%s, %u %s %u %u:%02u:%02u",
     268          56 :               day_names_epoch_order[cp->day_name_index],
     269             :               cp->day,
     270          56 :               month_short_names[cp->month],
     271             :               cp->year, cp->hour, cp->minute, cp->second);
     272          56 :   return (s);
     273             : }
     274             : 
     275             : uword
     276           3 : unformat_clib_timebase_range_hms (unformat_input_t * input, va_list * args)
     277             : {
     278           3 :   clib_timebase_range_t *rp = va_arg (*args, clib_timebase_range_t *);
     279           3 :   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           3 :   start_hour = start_minute = start_second
     284           3 :     = end_hour = end_minute = end_second = 0;
     285             : 
     286           3 :   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           3 :   else if (unformat (input, "%u:%u - %u:%u",
     291             :                      &start_hour, &start_minute, &end_hour, &end_minute))
     292             :     ;
     293           3 :   else if (unformat (input, "%u - %u", &start_hour, &end_hour))
     294             :     ;
     295             :   else
     296           0 :     return 0;
     297             : 
     298           3 :   clib_timebase_time_to_components (1e-6, cp);
     299             : 
     300           3 :   cp->hour = start_hour;
     301           3 :   cp->minute = start_minute;
     302           3 :   cp->second = start_second;
     303             : 
     304           3 :   rp->start = clib_timebase_components_to_time (cp);
     305             : 
     306           3 :   cp->hour = end_hour;
     307           3 :   cp->minute = end_minute;
     308           3 :   cp->second = end_second;
     309             : 
     310           3 :   rp->end = clib_timebase_components_to_time (cp);
     311             : 
     312           3 :   return 1;
     313             : }
     314             : 
     315             : __clib_export uword
     316           1 : unformat_clib_timebase_range_vector (unformat_input_t * input, va_list * args)
     317             : {
     318           1 :   clib_timebase_range_t **rpp = va_arg (*args, clib_timebase_range_t **);
     319           1 :   clib_timebase_range_t _tmp, *tmp = &_tmp;
     320             :   clib_timebase_range_t *rp, *new_rp;
     321           1 :   int day_range_match = 0;
     322           1 :   int time_range_match = 0;
     323             :   f64 range_start_time_offset;
     324             :   f64 range_end_time_offset;
     325             :   f64 now;
     326           1 :   u8 *start_day = 0, *end_day = 0;
     327             : 
     328           1 :   rp = *rpp;
     329             : 
     330             :   while (1)
     331             :     {
     332           7 :       if (!day_range_match
     333           4 :           && unformat (input, "%s - %s", &start_day, &end_day))
     334             :         {
     335             :           range_start_time_offset
     336           1 :             = clib_timebase_offset_from_sunday (start_day);
     337           1 :           range_end_time_offset = clib_timebase_offset_from_sunday (end_day);
     338           1 :           vec_free (start_day);
     339           1 :           vec_free (end_day);
     340           1 :           day_range_match = 1;
     341           1 :           time_range_match = 0;
     342             :         }
     343           6 :       else if (!day_range_match && unformat (input, "%s", &start_day))
     344             :         {
     345             :           range_start_time_offset
     346           2 :             = clib_timebase_offset_from_sunday (start_day);
     347           2 :           range_end_time_offset = range_start_time_offset + 86399.0;
     348           2 :           day_range_match = 1;
     349           2 :           vec_free (start_day);
     350           2 :           day_range_match = 1;
     351           2 :           time_range_match = 0;
     352             :         }
     353           7 :       else if (day_range_match &&
     354           3 :                unformat (input, "%U", unformat_clib_timebase_range_hms, tmp))
     355             :         {
     356             :           /* Across the week... */
     357           8 :           for (now = range_start_time_offset; now <= range_end_time_offset;
     358           5 :                now += 86400.0)
     359             :             {
     360           5 :               vec_add2 (rp, new_rp, 1);
     361           5 :               new_rp->start = now + tmp->start;
     362           5 :               new_rp->end = now + tmp->end;
     363             :             }
     364           3 :           day_range_match = 0;
     365           3 :           time_range_match = 1;
     366             :         }
     367           1 :       else if (time_range_match)
     368           1 :         break;
     369             :       else
     370             :         {
     371           0 :           vec_free (rp);
     372           0 :           *rpp = 0;
     373           0 :           return 0;
     374             :         }
     375             :     }
     376             : 
     377           1 :   if (time_range_match)
     378             :     {
     379           1 :       *rpp = rp;
     380           1 :       return 1;
     381             :     }
     382             :   else
     383             :     {
     384           0 :       vec_free (rp);
     385           0 :       *rpp = 0;
     386           0 :       return 0;
     387             :     }
     388             : }
     389             : 
     390             : __clib_export f64
     391          41 : clib_timebase_summer_offset (clib_timebase_t * tb, f64 now)
     392             : {
     393          41 :   clib_timebase_component_t _c, *cp = &_c;
     394             :   f64 second_sunday_march_2am;
     395             :   f64 first_sunday_november_2am;
     396             : 
     397          41 :   if (PREDICT_TRUE
     398             :       (now >= tb->cached_year_start && now <= tb->cached_year_end))
     399             :     {
     400           0 :       if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
     401           0 :         return tb->summer_offset;
     402             :       else
     403           0 :         return (0.0);
     404             :     }
     405             : 
     406          41 :   clib_timebase_time_to_components (now, cp);
     407             : 
     408          41 :   cp->month = 0;
     409          41 :   cp->day = 1;
     410          41 :   cp->hour = 0;
     411          41 :   cp->minute = 0;
     412          41 :   cp->second = 1;
     413             : 
     414          41 :   tb->cached_year_start = clib_timebase_components_to_time (cp);
     415             : 
     416          41 :   cp->year += 1;
     417             : 
     418          41 :   tb->cached_year_end = clib_timebase_components_to_time (cp);
     419             : 
     420          41 :   cp->year -= 1;
     421             : 
     422             :   /* Search for the second sunday in march, 2am */
     423          41 :   cp->month = 2;
     424          41 :   cp->day = 1;
     425          41 :   cp->hour = 2;
     426          41 :   cp->second = 0;
     427          41 :   cp->nanosecond = 1;
     428             : 
     429             :   /* March 1st will never be the second sunday... */
     430          41 :   second_sunday_march_2am = clib_timebase_components_to_time (cp);
     431          41 :   cp->day_name_index = 0;
     432             : 
     433             :   /* Find the first sunday */
     434             :   do
     435             :     {
     436         206 :       clib_timebase_time_to_components (second_sunday_march_2am, cp);
     437         206 :       second_sunday_march_2am += 86400.0;
     438             :     }
     439         206 :   while (cp->day_name_index != 3 /* sunday */ );
     440             : 
     441             :   /* Find the second sunday */
     442             :   do
     443             :     {
     444         287 :       clib_timebase_time_to_components (second_sunday_march_2am, cp);
     445         287 :       second_sunday_march_2am += 86400.0;
     446             :     }
     447         287 :   while (cp->day_name_index != 3 /* sunday */ );
     448             : 
     449          41 :   second_sunday_march_2am -= 86400.0;
     450             : 
     451          41 :   tb->cached_summer_start = second_sunday_march_2am;
     452             : 
     453             :   /* Find the first sunday in November, which can easily be 11/1 */
     454          41 :   cp->month = 10;
     455          41 :   cp->day = 1;
     456             : 
     457          41 :   first_sunday_november_2am = clib_timebase_components_to_time (cp);
     458          41 :   clib_timebase_time_to_components (first_sunday_november_2am, cp);
     459             : 
     460         206 :   while (cp->day_name_index != 3 /* sunday */ )
     461             :     {
     462         165 :       first_sunday_november_2am += 86400.0;
     463         165 :       clib_timebase_time_to_components (first_sunday_november_2am, cp);
     464             :     }
     465             : 
     466          41 :   tb->cached_summer_end = first_sunday_november_2am;
     467             : 
     468          41 :   if (now >= tb->cached_summer_start && now <= tb->cached_summer_end)
     469          40 :     return tb->summer_offset;
     470             :   else
     471           1 :     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             :  */

Generated by: LCOV version 1.14