mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #1912 from mustrumr/calendarspec-sub-second-v3
Calendarspec sub second v3
This commit is contained in:
commit
aa2fb804a1
@ -229,6 +229,10 @@
|
||||
the value and all values plus multiples of the repetition value
|
||||
are matched.</para>
|
||||
|
||||
<para>The seconds component may contain decimal fractions both in
|
||||
the value and the repetition. All fractions are rounded to 6
|
||||
decimal places.</para>
|
||||
|
||||
<para>Either time or date specification may be omitted, in which
|
||||
case the current day and 00:00:00 is implied, respectively. If the
|
||||
second component is not specified, <literal>:00</literal> is
|
||||
@ -276,6 +280,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
|
||||
Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40
|
||||
Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
|
||||
2003-03-05 05:40 → 2003-03-05 05:40:00
|
||||
05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001
|
||||
2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC
|
||||
2003-03-05 → 2003-03-05 00:00:00
|
||||
03-05 → *-03-05 00:00:00
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "calendarspec.h"
|
||||
#include "fileio.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#define BITS_WEEKDAYS 127
|
||||
@ -49,7 +50,7 @@ void calendar_spec_free(CalendarSpec *c) {
|
||||
free_chain(c->day);
|
||||
free_chain(c->hour);
|
||||
free_chain(c->minute);
|
||||
free_chain(c->second);
|
||||
free_chain(c->microsecond);
|
||||
|
||||
free(c);
|
||||
}
|
||||
@ -135,7 +136,7 @@ int calendar_spec_normalize(CalendarSpec *c) {
|
||||
sort_chain(&c->day);
|
||||
sort_chain(&c->hour);
|
||||
sort_chain(&c->minute);
|
||||
sort_chain(&c->second);
|
||||
sort_chain(&c->microsecond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -177,7 +178,7 @@ _pure_ bool calendar_spec_valid(CalendarSpec *c) {
|
||||
if (!chain_valid(c->minute, 0, 59))
|
||||
return false;
|
||||
|
||||
if (!chain_valid(c->second, 0, 59))
|
||||
if (!chain_valid(c->microsecond, 0, 60*USEC_PER_SEC-1))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -232,7 +233,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
|
||||
}
|
||||
}
|
||||
|
||||
static void format_chain(FILE *f, int space, const CalendarComponent *c) {
|
||||
static void format_chain(FILE *f, int space, const CalendarComponent *c, bool usec) {
|
||||
assert(f);
|
||||
|
||||
if (!c) {
|
||||
@ -241,14 +242,25 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c) {
|
||||
}
|
||||
|
||||
assert(c->value >= 0);
|
||||
fprintf(f, "%0*i", space, c->value);
|
||||
if (!usec)
|
||||
fprintf(f, "%0*i", space, c->value);
|
||||
else if (c->value % USEC_PER_SEC == 0)
|
||||
fprintf(f, "%0*i", space, (int) (c->value / USEC_PER_SEC));
|
||||
else
|
||||
fprintf(f, "%0*i.%06i", space, (int) (c->value / USEC_PER_SEC), (int) (c->value % USEC_PER_SEC));
|
||||
|
||||
if (c->repeat > 0)
|
||||
fprintf(f, "/%i", c->repeat);
|
||||
if (c->repeat > 0) {
|
||||
if (!usec)
|
||||
fprintf(f, "/%i", c->repeat);
|
||||
else if (c->repeat % USEC_PER_SEC == 0)
|
||||
fprintf(f, "/%i", (int) (c->repeat / USEC_PER_SEC));
|
||||
else
|
||||
fprintf(f, "/%i.%06i", (int) (c->repeat / USEC_PER_SEC), (int) (c->repeat % USEC_PER_SEC));
|
||||
}
|
||||
|
||||
if (c->next) {
|
||||
fputc(',', f);
|
||||
format_chain(f, space, c->next);
|
||||
format_chain(f, space, c->next, usec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,17 +282,17 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
|
||||
fputc(' ', f);
|
||||
}
|
||||
|
||||
format_chain(f, 4, c->year);
|
||||
format_chain(f, 4, c->year, false);
|
||||
fputc('-', f);
|
||||
format_chain(f, 2, c->month);
|
||||
format_chain(f, 2, c->month, false);
|
||||
fputc('-', f);
|
||||
format_chain(f, 2, c->day);
|
||||
format_chain(f, 2, c->day, false);
|
||||
fputc(' ', f);
|
||||
format_chain(f, 2, c->hour);
|
||||
format_chain(f, 2, c->hour, false);
|
||||
fputc(':', f);
|
||||
format_chain(f, 2, c->minute);
|
||||
format_chain(f, 2, c->minute, false);
|
||||
fputc(':', f);
|
||||
format_chain(f, 2, c->second);
|
||||
format_chain(f, 2, c->microsecond, true);
|
||||
|
||||
if (c->utc)
|
||||
fputs(" UTC", f);
|
||||
@ -391,35 +403,70 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
|
||||
}
|
||||
}
|
||||
|
||||
static int prepend_component(const char **p, CalendarComponent **c) {
|
||||
static int parse_component_decimal(const char **p, bool usec, unsigned long *res) {
|
||||
unsigned long value;
|
||||
const char *e = NULL;
|
||||
char *ee = NULL;
|
||||
int r;
|
||||
|
||||
errno = 0;
|
||||
value = strtoul(*p, &ee, 10);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (ee == *p)
|
||||
return -EINVAL;
|
||||
if ((unsigned long) (int) value != value)
|
||||
return -ERANGE;
|
||||
e = ee;
|
||||
|
||||
if (usec) {
|
||||
if (value * USEC_PER_SEC / USEC_PER_SEC != value)
|
||||
return -ERANGE;
|
||||
|
||||
value *= USEC_PER_SEC;
|
||||
if (*e == '.') {
|
||||
unsigned add;
|
||||
|
||||
e++;
|
||||
r = parse_fractional_part_u(&e, 6, &add);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (add + value < value)
|
||||
return -ERANGE;
|
||||
value += add;
|
||||
}
|
||||
}
|
||||
|
||||
*p = e;
|
||||
*res = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
|
||||
unsigned long value, repeat = 0;
|
||||
char *e = NULL, *ee = NULL;
|
||||
CalendarComponent *cc;
|
||||
int r;
|
||||
const char *e;
|
||||
|
||||
assert(p);
|
||||
assert(c);
|
||||
|
||||
errno = 0;
|
||||
value = strtoul(*p, &e, 10);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (e == *p)
|
||||
return -EINVAL;
|
||||
if ((unsigned long) (int) value != value)
|
||||
return -ERANGE;
|
||||
e = *p;
|
||||
|
||||
r = parse_component_decimal(&e, usec, &value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*e == '/') {
|
||||
repeat = strtoul(e+1, &ee, 10);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (ee == e+1)
|
||||
return -EINVAL;
|
||||
if ((unsigned long) (int) repeat != repeat)
|
||||
return -ERANGE;
|
||||
if (repeat <= 0)
|
||||
return -ERANGE;
|
||||
e++;
|
||||
r = parse_component_decimal(&e, usec, &repeat);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e = ee;
|
||||
if (repeat == 0)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':')
|
||||
@ -438,39 +485,12 @@ static int prepend_component(const char **p, CalendarComponent **c) {
|
||||
|
||||
if (*e ==',') {
|
||||
*p += 1;
|
||||
return prepend_component(p, c);
|
||||
return prepend_component(p, usec, c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_chain(const char **p, CalendarComponent **c) {
|
||||
const char *t;
|
||||
CalendarComponent *cc = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(c);
|
||||
|
||||
t = *p;
|
||||
|
||||
if (t[0] == '*') {
|
||||
*p = t + 1;
|
||||
*c = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = prepend_component(&t, &cc);
|
||||
if (r < 0) {
|
||||
free_chain(cc);
|
||||
return r;
|
||||
}
|
||||
|
||||
*p = t;
|
||||
*c = cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int const_chain(int value, CalendarComponent **c) {
|
||||
CalendarComponent *cc = NULL;
|
||||
|
||||
@ -489,6 +509,40 @@ static int const_chain(int value, CalendarComponent **c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
|
||||
const char *t;
|
||||
CalendarComponent *cc = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(c);
|
||||
|
||||
t = *p;
|
||||
|
||||
if (t[0] == '*') {
|
||||
if (usec) {
|
||||
r = const_chain(0, c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
(*c)->repeat = USEC_PER_SEC;
|
||||
} else
|
||||
*c = NULL;
|
||||
|
||||
*p = t + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = prepend_component(&t, usec, &cc);
|
||||
if (r < 0) {
|
||||
free_chain(cc);
|
||||
return r;
|
||||
}
|
||||
|
||||
*p = t;
|
||||
*c = cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_date(const char **p, CalendarSpec *c) {
|
||||
const char *t;
|
||||
int r;
|
||||
@ -503,7 +557,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
|
||||
if (*t == 0)
|
||||
return 0;
|
||||
|
||||
r = parse_chain(&t, &first);
|
||||
r = parse_chain(&t, false, &first);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -519,7 +573,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, &second);
|
||||
r = parse_chain(&t, false, &second);
|
||||
if (r < 0) {
|
||||
free_chain(first);
|
||||
return r;
|
||||
@ -540,7 +594,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, &third);
|
||||
r = parse_chain(&t, false, &third);
|
||||
if (r < 0) {
|
||||
free_chain(first);
|
||||
free_chain(second);
|
||||
@ -582,7 +636,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = parse_chain(&t, &h);
|
||||
r = parse_chain(&t, false, &h);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -592,7 +646,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, &m);
|
||||
r = parse_chain(&t, false, &m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -610,7 +664,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
|
||||
}
|
||||
|
||||
t++;
|
||||
r = parse_chain(&t, &s);
|
||||
r = parse_chain(&t, true, &s);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -639,7 +693,8 @@ finish:
|
||||
*p = t;
|
||||
c->hour = h;
|
||||
c->minute = m;
|
||||
c->second = s;
|
||||
c->microsecond = s;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -671,7 +726,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
}
|
||||
|
||||
if (strcaseeq(p, "minutely")) {
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -679,7 +734,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -690,7 +745,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -704,7 +759,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -724,7 +779,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -738,7 +793,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -765,7 +820,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -789,7 +844,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
|
||||
r = const_chain(0, &c->minute);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
r = const_chain(0, &c->second);
|
||||
r = const_chain(0, &c->microsecond);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -906,14 +961,16 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
|
||||
return (weekdays_bits & (1 << k));
|
||||
}
|
||||
|
||||
static int find_next(const CalendarSpec *spec, struct tm *tm) {
|
||||
static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
|
||||
struct tm c;
|
||||
int tm_usec;
|
||||
int r;
|
||||
|
||||
assert(spec);
|
||||
assert(tm);
|
||||
|
||||
c = *tm;
|
||||
tm_usec = *usec;
|
||||
|
||||
for (;;) {
|
||||
/* Normalize the current date */
|
||||
@ -927,7 +984,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
|
||||
if (r > 0) {
|
||||
c.tm_mon = 0;
|
||||
c.tm_mday = 1;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
}
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc))
|
||||
return r;
|
||||
@ -938,29 +995,29 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
|
||||
|
||||
if (r > 0) {
|
||||
c.tm_mday = 1;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
}
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
|
||||
c.tm_year ++;
|
||||
c.tm_mon = 0;
|
||||
c.tm_mday = 1;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = find_matching_component(spec->day, &c.tm_mday);
|
||||
if (r > 0)
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
|
||||
c.tm_mon ++;
|
||||
c.tm_mday = 1;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
|
||||
c.tm_mday++;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -969,7 +1026,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
|
||||
c.tm_min = c.tm_sec = 0;
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
|
||||
c.tm_mday ++;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = 0;
|
||||
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -978,19 +1035,23 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
|
||||
c.tm_sec = 0;
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
|
||||
c.tm_hour ++;
|
||||
c.tm_min = c.tm_sec = 0;
|
||||
c.tm_min = c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = find_matching_component(spec->second, &c.tm_sec);
|
||||
c.tm_sec = c.tm_sec * USEC_PER_SEC + tm_usec;
|
||||
r = find_matching_component(spec->microsecond, &c.tm_sec);
|
||||
tm_usec = c.tm_sec % USEC_PER_SEC;
|
||||
c.tm_sec /= USEC_PER_SEC;
|
||||
|
||||
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
|
||||
c.tm_min ++;
|
||||
c.tm_sec = 0;
|
||||
c.tm_sec = tm_usec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
*tm = c;
|
||||
*usec = tm_usec;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -999,14 +1060,17 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
|
||||
struct tm tm;
|
||||
time_t t;
|
||||
int r;
|
||||
usec_t tm_usec;
|
||||
|
||||
assert(spec);
|
||||
assert(next);
|
||||
|
||||
t = (time_t) (usec / USEC_PER_SEC) + 1;
|
||||
usec++;
|
||||
t = (time_t) (usec / USEC_PER_SEC);
|
||||
assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
|
||||
tm_usec = usec % USEC_PER_SEC;
|
||||
|
||||
r = find_next(spec, &tm);
|
||||
r = find_next(spec, &tm, &tm_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1014,6 +1078,6 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
|
||||
if (t == (time_t) -1)
|
||||
return -EINVAL;
|
||||
|
||||
*next = (usec_t) t * USEC_PER_SEC;
|
||||
*next = (usec_t) t * USEC_PER_SEC + tm_usec;
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ typedef struct CalendarSpec {
|
||||
|
||||
CalendarComponent *hour;
|
||||
CalendarComponent *minute;
|
||||
CalendarComponent *second;
|
||||
CalendarComponent *microsecond;
|
||||
} CalendarSpec;
|
||||
|
||||
void calendar_spec_free(CalendarSpec *c);
|
||||
|
@ -490,3 +490,39 @@ int safe_atod(const char *s, double *ret_d) {
|
||||
*ret_d = (double) d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
|
||||
size_t i;
|
||||
unsigned val = 0;
|
||||
const char *s;
|
||||
|
||||
s = *p;
|
||||
|
||||
/* accept any number of digits, strtoull is limted to 19 */
|
||||
for(i=0; i < digits; i++,s++) {
|
||||
if (*s < '0' || *s > '9') {
|
||||
if (i == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* too few digits, pad with 0 */
|
||||
for (; i < digits; i++)
|
||||
val *= 10;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
val *= 10;
|
||||
val += *s - '0';
|
||||
}
|
||||
|
||||
/* maybe round up */
|
||||
if (*s >= '5' && *s <= '9')
|
||||
val++;
|
||||
|
||||
s += strspn(s, DIGITS);
|
||||
|
||||
*p = s;
|
||||
*res = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -90,3 +90,5 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
|
||||
#endif
|
||||
|
||||
int safe_atod(const char *s, double *ret_d);
|
||||
|
||||
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -658,29 +659,18 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
|
||||
parse_usec:
|
||||
{
|
||||
char *end;
|
||||
unsigned long long val;
|
||||
size_t l;
|
||||
unsigned add;
|
||||
|
||||
k++;
|
||||
if (*k < '0' || *k > '9')
|
||||
r = parse_fractional_part_u(&k, 6, &add);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* base 10 instead of base 0, .09 is not base 8 */
|
||||
errno = 0;
|
||||
val = strtoull(k, &end, 10);
|
||||
if (*end || errno)
|
||||
if (*k)
|
||||
return -EINVAL;
|
||||
|
||||
l = end-k;
|
||||
x_usec = add;
|
||||
|
||||
/* val has l digits, make them 6 */
|
||||
for (; l < 6; l++)
|
||||
val *= 10;
|
||||
for (; l > 6; l--)
|
||||
val /= 10;
|
||||
|
||||
x_usec = val;
|
||||
}
|
||||
|
||||
from_tm:
|
||||
|
@ -75,7 +75,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_
|
||||
|
||||
u = after;
|
||||
r = calendar_spec_next_usec(c, after, &u);
|
||||
printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
|
||||
printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof(buf), u));
|
||||
if (expect != (usec_t)-1)
|
||||
assert_se(r >= 0 && u == expect);
|
||||
else
|
||||
@ -123,6 +123,9 @@ int main(int argc, char* argv[]) {
|
||||
test_one("annually", "*-01-01 00:00:00");
|
||||
test_one("*:2/3", "*-*-* *:02/3:00");
|
||||
test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
|
||||
test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
|
||||
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
|
||||
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
|
||||
|
||||
test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
|
||||
test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
|
||||
@ -131,11 +134,19 @@ int main(int argc, char* argv[]) {
|
||||
test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
|
||||
test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
|
||||
test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
|
||||
test_next("2016-03-27 03:17:00.420000001 UTC", "EET", 12345, 1459048620420000);
|
||||
test_next("2016-03-27 03:17:00.4200005 UTC", "EET", 12345, 1459048620420001);
|
||||
test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000);
|
||||
test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000);
|
||||
test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000);
|
||||
|
||||
assert_se(calendar_spec_from_string("test", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("7", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("121212:1:2", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0);
|
||||
assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user