#
# = Date Module
#
-# The `date` module xlat does convert time formats.
+# The `date` module parses dates, and prints them.
#
-
+# The server will normally print dates in its own pre-defined format.
+# It will also parse dates in a few limited formats. However, these
+# operations are for full dates (e.g. January 1, 2020 12:34pm). The
+# server does not print dates in other formats, and does not parse
+# dates in other formats.
#
-# ## Configuration Settings
+# The `date` module adds that functionality. It allows you to print
+# dates in almost any format you want. It allows you to parse dates
+# in almost any format, so long as you know what the fields are, and
+# how they are defined.
#
#
-# ### Simple date
+# ## Configuration Settings
#
date {
#
- # format::
- #
- # The `xlat` performs in three modes depending on the input it
- # is passed.
- #
- # The input string can be:
- #
- # - an expanded date or integer attribute;
- # - an expanded string attribute;
- # - the fixed strings `request` or `now`.
- #
- # ."Attribute" mode:
- #
- # If the given attribute is of `date` or `integer` type, the date
- # xlat will convert it to a `time` string in the format of the
- # format config item.
+ # format:: Formatting of the output string.
#
- # If the given attribute is a `string` type, the `xlat` will attempt
- # to parse it in the format specified by the format config item,
- # and will expand to a Unix timestamp (seconds since the epoch).
- #
- # ."Get time" mode:
- #
- # If the input is the string `request`, the `xlat` will format the
- # time the current request packet arrived according to the format
- # string, and return it as a string.
- #
- # If the input is the string `now`, the `xlat` will behave as
- # above, for the current time.
- #
- # See also the core provided expansions which are equivalent to
- # `request` and `now`, but return numerical values:
- #
- # [options="header,autowidth"]
- # |===
- # | Parameter | Description
- # | %l | request time in seconds since the epoch.
- # | %M | request time microsecond component.
- # | %c | current time in seconds since the epoch.
- # | %C | current time microsecond component.
- # |===
+ # The format arguments are the same as for the system
+ # `strftime` call. See `man strftime` for documentation.
#
format = "%b %e %Y %H:%M:%S %Z"
#
- # utc::
+ # utc:: Whether conversions are in UTC or local time.
#
# If `utc` is enabled then any conversions will be made
# as UTC, not localtime.
format = "%Y-%m-%dT%H:%M:%SZ"
utc = yes
}
+
+#
+# ### xlat expansions
+#
+# The `date` module defines an expansion `%{date:}` When the
+# expansion is not passed an argument, it returns the current date
+# printed according to the `format` string defined above.
+#
+# ."Attribute" mode:
+#
+# If the argument to `%{date:...}` is an attribute of `date` or
+# `integer` type, the date used will be the time given by the
+# relevant attribute.
+#
+# For example, `%{date:&Event-Timestamp}` will use the date from the
+# `Event-Timestamp` attribute as the source of the date for printing.
+#
+# ."Get time" mode:
+#
+# If the input is the string `request`, the `xlat` will format the
+# time the current request packet arrived according to the format
+# string, and return it as a string.
+#
+# If the input is the string `now`, the `xlat` will behave as
+# above, for the current time.
+#
+# If the input string begins with `+`, then the remainder of the
+# string is interpreted as if the string had been given in the
+# `format` configuration item.
+#
+# For example `%{date:'+%A'}` will return `Monday` if today is Monday.
+#
+# Note that the `%` character is special for xlat expansions, and therefore
+# either has to be "protected" by string quotation, or the `%` character has
+# to be escaped itself, as in `%{date:+%%A}`
+#
+# ."Integer output"
+#
+# In some cases, it is useful for the module to parse dates instead
+# of printing them. In this mode, the format string is ignored.
+# Instead, the input arguments are parsed, and the output is an
+# integer containg the requested value.
+#
+# The following expansions return integer numbers:
+#
+# [options="header,autowidth"]
+# |===
+# | Parameter | Description
+# | %l | request time in seconds since the epoch.
+# | %M | request time microsecond component.
+# | %c | current time in seconds since the epoch.
+# | %C | current time microsecond component.
+# | &Attribute-Name | for string attributes, parse the string according to `format`, and return the integer value as a Unix timestamp.
+# |===
+#
}
static xlat_action_t date_encode_strftime(TALLOC_CTX *ctx, fr_dcursor_t *out, rlm_date_t const *inst,
- request_t *request, time_t date)
+ request_t *request, char const *fmt, time_t date)
{
struct tm tminfo;
char buff[64];
}
}
- if (strftime(buff, sizeof(buff), inst->fmt, &tminfo) == 0) return XLAT_ACTION_FAIL;
+ if (strftime(buff, sizeof(buff), fmt, &tminfo) == 0) return XLAT_ACTION_FAIL;
MEM(vb = fr_value_box_alloc_null(ctx));
MEM(fr_value_box_strdup(ctx, vb, NULL, buff, false) == 0);
*/
if (arg->type == FR_TYPE_STRING) {
if (strcmp(arg->vb_strvalue, "request") == 0) {
- return date_encode_strftime(ctx, out, inst, request,
+ return date_encode_strftime(ctx, out, inst, request, inst->fmt,
fr_time_to_sec(request->packet->timestamp));
}
if (strcmp(arg->vb_strvalue, "now") == 0) {
now:
- return date_encode_strftime(ctx, out, inst, request, fr_time_to_sec(fr_time()));
+ return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_time_to_sec(fr_time()));
+ }
+
+ /*
+ * %{date:'+%A'} == "Monday", to mirror the behavior of the `date` command.
+ */
+ if (arg->vb_strvalue[0] == '+') {
+ return date_encode_strftime(ctx, out, inst, request, arg->vb_strvalue + 1, fr_time_to_sec(fr_time()));
}
}
* format as a string.
*/
case FR_TYPE_DATE:
- return date_encode_strftime(ctx, out, inst, request, fr_unix_time_to_sec(arg->vb_date));
+ return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_unix_time_to_sec(arg->vb_date));
case FR_TYPE_UINT32:
- return date_encode_strftime(ctx, out, inst, request, (time_t) arg->vb_uint32);
+ return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint32);
case FR_TYPE_UINT64:
- return date_encode_strftime(ctx, out, inst, request, (time_t) arg->vb_uint64);
+ return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint64);
/*
* These are 'from' types, i.e. we'll convert the input string