Skip to content

Commit

Permalink
leap seconds handling
Browse files Browse the repository at this point in the history
  • Loading branch information
exander77 committed Sep 8, 2023
1 parent 246eff4 commit 7918c19
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 6 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ This reference is based on:
```
Field name Mandatory? Allowed values Allowed special characters
---------- ---------- -------------- -------------------------
Second No 0-59 * / , -
Second No 0-59 * / , - L
Minute Yes 0-59 * / , -
Hour Yes 0-23 * / , -
Day of month Yes 1-31 * / , - L W
Expand Down Expand Up @@ -77,6 +77,8 @@ The character `L` stands for "last". In the 'Day of week' field, `5L` denotes th

- If followed by a negative number in the 'Day of month' field, such as `L-3`, it indicates the third-to-last day of the month.

- If `L` is present in the beginning of 'Second' field, it turns on non standard leap second functionality. Unless timezone specifies leap seconds, it will segfault, because it will not be able to find any leap second!

When using 'L', avoid specifying lists or ranges to prevent ambiguous results.

#### `W`
Expand Down
20 changes: 15 additions & 5 deletions ccronexpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "ccronexpr.h"

#define CRON_MAX_SECONDS 60
#define CRON_MAX_LEAP_SECONDS 2
#define CRON_MAX_MINUTES 60
#define CRON_MAX_HOURS 24
#define CRON_MAX_DAYS_OF_MONTH 32
Expand Down Expand Up @@ -595,10 +596,13 @@ static int do_nextprev(
}

second = calendar->tm_sec;
update_second = find(expr->seconds, CRON_MAX_SECONDS, second, calendar, CRON_CF_SECOND, CRON_CF_MINUTE, empty_list, &res);
update_second = find(expr->seconds, CRON_MAX_SECONDS+CRON_MAX_LEAP_SECONDS, second, calendar, CRON_CF_SECOND, CRON_CF_MINUTE, empty_list, &res);
if (0 != res) goto return_result;
if (second == update_second) {
push_to_fields_arr(resets, CRON_CF_SECOND);
} else {
res = do_(expr, calendar, dot);
if (0 != res) goto return_result;
}

minute = calendar->tm_min;
Expand Down Expand Up @@ -1146,6 +1150,7 @@ void cron_parse_expr(const char* expression, cron_expr* target, const char** err
const char* err_local;
size_t len = 0;
char** fields = NULL;
char* field;
int ret;
int pos = 0;
if (!error) {
Expand Down Expand Up @@ -1190,14 +1195,19 @@ void cron_parse_expr(const char* expression, cron_expr* target, const char** err
}
memset(target, 0, sizeof(*target));
if (len > 5) {
set_number_hits(fields[pos++], target->seconds, 0, 60, error);
if (fields[pos][0] == 'L') {
field = fields[pos++];
set_number_hits(field+1, target->seconds, 0, CRON_MAX_SECONDS+CRON_MAX_LEAP_SECONDS, error);
} else {
set_number_hits(fields[pos++], target->seconds, 0, CRON_MAX_SECONDS, error);
}
if (*error) goto return_res;
} else {
set_number_hits("0", target->seconds, 0, 60, error);
set_number_hits("0", target->seconds, 0, CRON_MAX_SECONDS, error);
}
set_number_hits(fields[pos++], target->minutes, 0, 60, error);
set_number_hits(fields[pos++], target->minutes, 0, CRON_MAX_MINUTES, error);
if (*error) goto return_res;
set_number_hits(fields[pos++], target->hours, 0, 24, error);
set_number_hits(fields[pos++], target->hours, 0, CRON_MAX_HOURS, error);
if (*error) goto return_res;
ret = set_days_of_month(fields[pos++], target->days_of_month, target->days_of_week, target->day_in_month, target->flags, error);
if (*error) goto return_res;
Expand Down
7 changes: 7 additions & 0 deletions ccronexpr_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,15 @@ void check_expr_invalid(const char* expr) {
}

void test_expr() {
char* tz = getenv("TZ");
/*Test leap seconds - nejsou nastavené hodnoty, co se kontrolují */
/*Test leap seconds
check_fn(cron_next, "60 0 0 * * *", "2015-01-01_15:12:42", "2015-06-30_00:00:00", __LINE__);*/
if (tz && !strcmp("right/UTC", tz)) {
check_fn(cron_next, "L59 * * * * *", "2016-12-31_23:50:00", "2016-12-31_23:50:59", __LINE__);
check_fn(cron_next, "L60 * * * * *", "2016-12-31_23:50:00", "2016-12-31_23:59:60", __LINE__);
check_fn(cron_next, "L60 * * * * *", "2016-12-31_23:59:59", "2016-12-31_23:59:60", __LINE__);
}

check_fn(cron_next, "* * * 1 1 * *", "1970-01-01_15:12:42", "1970-01-01_15:12:43", __LINE__);
check_fn(cron_next, "* * * 1 1 * 1970,2100,2193,2199", "1970-01-01_15:12:42", "1970-01-01_15:12:43", __LINE__);
Expand Down

0 comments on commit 7918c19

Please sign in to comment.