#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
+#include <locale.h>
#include <string.h>
#include <sys/timex.h>
#include "hwclock.h"
#include "strv.h"
#include "pager.h"
+#include "time-dst.h"
-static bool arg_fix_system = false;
+static bool arg_adjust_system_clock = false;
static bool arg_no_pager = false;
static enum transport {
TRANSPORT_NORMAL,
return true;
}
+static const char *jump_str(int delta_minutes, char *s, size_t size) {
+ if (delta_minutes == 60)
+ return "one hour forward";
+ if (delta_minutes == -60)
+ return "one hour backwards";
+ if (delta_minutes < 0) {
+ snprintf(s, size, "%i minutes backwards", -delta_minutes);
+ return s;
+ }
+ if (delta_minutes > 0) {
+ snprintf(s, size, "%i minutes forward", delta_minutes);
+ return s;
+ }
+ return "";
+}
+
static void print_status_info(StatusInfo *i) {
usec_t n;
+ char a[FORMAT_TIMESTAMP_MAX];
char b[FORMAT_TIMESTAMP_MAX];
+ char s[32];
struct tm tm;
time_t sec;
+ char *zc, *zn;
+ time_t t, tc, tn;
+ int dn;
+ bool is_dstc, is_dstn;
int r;
assert(i);
+ /* enforce the values of /etc/localtime */
+ if (getenv("TZ")) {
+ fprintf(stderr, "Warning: ignoring the TZ variable, reading the system's timezone setting only.\n\n");
+ unsetenv("TZ");
+ }
+
n = now(CLOCK_REALTIME);
sec = (time_t) (n / USEC_PER_SEC);
zero(tm);
- assert_se(strftime(b, sizeof(b), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
- char_array_0(b);
- printf(" Local time: %s\n", b);
+ assert_se(strftime(a, sizeof(a), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
+ char_array_0(a);
+ printf(" Local time: %s\n", a);
zero(tm);
- assert_se(strftime(b, sizeof(b), "%a, %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
- char_array_0(b);
- printf(" Universal time: %s\n", b);
+ assert_se(strftime(a, sizeof(a), "%a, %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
+ char_array_0(a);
+ printf(" Universal time: %s\n", a);
zero(tm);
r = hwclock_get_time(&tm);
/* Calculcate the week-day */
mktime(&tm);
- assert_se(strftime(b, sizeof(b), "%a, %Y-%m-%d %H:%M:%S", &tm) > 0);
- char_array_0(b);
- printf(" RTC time: %s\n", b);
+ assert_se(strftime(a, sizeof(a), "%a, %Y-%m-%d %H:%M:%S", &tm) > 0);
+ char_array_0(a);
+ printf(" RTC time: %s\n", a);
}
+ zero(tm);
+ assert_se(strftime(a, sizeof(a), "%z", localtime_r(&sec, &tm)) > 0);
+ char_array_0(a);
printf(" Timezone: %s\n"
+ " UTC offset: %s\n"
" NTP enabled: %s\n"
"NTP synchronized: %s\n"
" RTC in local TZ: %s\n",
strna(i->timezone),
+ a,
yes_no(i->ntp),
yes_no(ntp_synced()),
yes_no(i->local_rtc));
+ r = time_get_dst(sec, "/etc/localtime",
+ &tc, &zc, &is_dstc,
+ &tn, &dn, &zn, &is_dstn);
+ if (r < 0)
+ printf(" DST active: n/a\n");
+ else {
+ printf(" DST active: %s\n", yes_no(is_dstc));
+
+ t = tc - 1;
+ zero(tm);
+ assert_se(strftime(a, sizeof(a), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
+ char_array_0(a);
+
+ zero(tm);
+ assert_se(strftime(b, sizeof(b), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0);
+ char_array_0(b);
+ printf(" Last DST change: %s → %s, DST became %s\n"
+ " %s\n"
+ " %s\n",
+ strna(zn), strna(zc), is_dstc ? "active" : "inactive", a, b);
+
+ t = tn - 1;
+ zero(tm);
+ assert_se(strftime(a, sizeof(a), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
+ char_array_0(a);
+
+ zero(tm);
+ assert_se(strftime(b, sizeof(b), "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0);
+ char_array_0(b);
+ printf(" Next DST change: %s → %s, DST will become %s, the clock will jump %s\n"
+ " %s\n"
+ " %s\n",
+ strna(zc), strna(zn), is_dstn ? "active" : "inactive", jump_str(dn, s, sizeof(s)), a, b);
+
+ free(zc);
+ free(zn);
+ }
+
if (i->local_rtc)
fputs("\n" ANSI_HIGHLIGHT_ON
"Warning: The RTC is configured to maintain time in the local time zone. This\n"
}
b = r;
- q = arg_fix_system;
+ q = arg_adjust_system_clock;
return bus_method_call_with_reply(
bus,
DBUS_TYPE_INVALID);
}
-static int zone_compare(const void *_a, const void *_b) {
- const char **a = (const char**) _a, **b = (const char**) _b;
-
- return strcmp(*a, *b);
-}
-
static int list_timezones(DBusConnection *bus, char **args, unsigned n) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **zones = NULL;
- size_t n_zones;
+ size_t n_zones = 0;
char **i;
assert(args);
}
if (zones)
- zones[n_zones] = 0;
-
- qsort(zones, n_zones, sizeof(char*), zone_compare);
+ zones[n_zones] = NULL;
pager_open_if_enabled();
+ strv_sort(zones);
STRV_FOREACH(i, zones)
puts(*i);
static int help(void) {
- printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Query or control system time and date settings.\n\n"
+ printf("%s [OPTIONS...] COMMAND ...\n\n"
+ "Query or change system time and date settings.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --fix-system Adjust system clock when changing local RTC mode\n"
+ " --adjust-system-clock\n"
+ " Adjust system clock when changing local RTC mode\n"
" --no-pager Do not pipe output into a pager\n"
" --no-ask-password Do not prompt for password\n"
" -H --host=[USER@]HOST Operate on remote host\n\n"
"Commands:\n"
- " status Show current time settings\n"
- " set-time [TIME] Set system time\n"
- " set-timezone [ZONE] Set system timezone\n"
- " list-timezones Show known timezones\n"
- " set-local-rtc [BOOL] Control whether RTC is in local time\n"
- " set-ntp [BOOL] Control whether NTP is enabled\n",
+ " status Show current time settings\n"
+ " set-time TIME Set system time\n"
+ " set-timezone ZONE Set system timezone\n"
+ " list-timezones Show known timezones\n"
+ " set-local-rtc BOOL Control whether RTC is in local time\n"
+ " set-ntp BOOL Control whether NTP is enabled\n",
program_invocation_short_name);
return 0;
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
- ARG_FIX_SYSTEM,
+ ARG_ADJUST_SYSTEM_CLOCK,
ARG_NO_ASK_PASSWORD
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "host", required_argument, NULL, 'H' },
- { "privileged", no_argument, NULL, 'P' },
- { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
- { "fix-system", no_argument, NULL, ARG_FIX_SYSTEM },
- { NULL, 0, NULL, 0 }
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "host", required_argument, NULL, 'H' },
+ { "privileged", no_argument, NULL, 'P' },
+ { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+ { "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK },
+ { NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hp:as:H:P", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "+hH:P", options, NULL)) >= 0) {
switch (c) {
arg_host = optarg;
break;
- case ARG_FIX_SYSTEM:
- arg_fix_system = true;
+ case ARG_ADJUST_SYSTEM_CLOCK:
+ arg_adjust_system_clock = true;
break;
case ARG_NO_PAGER:
dbus_error_init(&error);
+ setlocale(LC_ALL, "");
log_parse_environment();
log_open();