| 1 | /* date - print or set the system date and time
|
|---|
| 2 | Copyright (C) 1989-2006 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This program is free software; you can redistribute it and/or modify
|
|---|
| 5 | it under the terms of the GNU General Public License as published by
|
|---|
| 6 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 7 | any later version.
|
|---|
| 8 |
|
|---|
| 9 | This program is distributed in the hope that it will be useful,
|
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 12 | GNU General Public License for more details.
|
|---|
| 13 |
|
|---|
| 14 | You should have received a copy of the GNU General Public License
|
|---|
| 15 | along with this program; if not, write to the Free Software Foundation,
|
|---|
| 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|---|
| 17 |
|
|---|
| 18 | David MacKenzie <[email protected]> */
|
|---|
| 19 |
|
|---|
| 20 | #include <config.h>
|
|---|
| 21 | #include <stdio.h>
|
|---|
| 22 | #include <getopt.h>
|
|---|
| 23 | #include <sys/types.h>
|
|---|
| 24 | #if HAVE_LANGINFO_CODESET
|
|---|
| 25 | # include <langinfo.h>
|
|---|
| 26 | #endif
|
|---|
| 27 |
|
|---|
| 28 | #include "system.h"
|
|---|
| 29 | #include "argmatch.h"
|
|---|
| 30 | #include "error.h"
|
|---|
| 31 | #include "getdate.h"
|
|---|
| 32 | #include "getline.h"
|
|---|
| 33 | #include "inttostr.h"
|
|---|
| 34 | #include "posixtm.h"
|
|---|
| 35 | #include "quote.h"
|
|---|
| 36 | #include "stat-time.h"
|
|---|
| 37 | #include "fprintftime.h"
|
|---|
| 38 |
|
|---|
| 39 | /* The official name of this program (e.g., no `g' prefix). */
|
|---|
| 40 | #define PROGRAM_NAME "date"
|
|---|
| 41 |
|
|---|
| 42 | #define AUTHORS "David MacKenzie"
|
|---|
| 43 |
|
|---|
| 44 | int putenv ();
|
|---|
| 45 |
|
|---|
| 46 | static bool show_date (const char *format, struct timespec when);
|
|---|
| 47 |
|
|---|
| 48 | enum Time_spec
|
|---|
| 49 | {
|
|---|
| 50 | /* Display only the date. */
|
|---|
| 51 | TIME_SPEC_DATE,
|
|---|
| 52 | /* Display date, hours, minutes, and seconds. */
|
|---|
| 53 | TIME_SPEC_SECONDS,
|
|---|
| 54 | /* Similar, but display nanoseconds. */
|
|---|
| 55 | TIME_SPEC_NS,
|
|---|
| 56 |
|
|---|
| 57 | /* Put these last, since they aren't valid for --rfc-3339. */
|
|---|
| 58 |
|
|---|
| 59 | /* Display date and hour. */
|
|---|
| 60 | TIME_SPEC_HOURS,
|
|---|
| 61 | /* Display date, hours, and minutes. */
|
|---|
| 62 | TIME_SPEC_MINUTES
|
|---|
| 63 | };
|
|---|
| 64 |
|
|---|
| 65 | static char const *const time_spec_string[] =
|
|---|
| 66 | {
|
|---|
| 67 | /* Put "hours" and "minutes" first, since they aren't valid for
|
|---|
| 68 | --rfc-3339. */
|
|---|
| 69 | "hours", "minutes",
|
|---|
| 70 | "date", "seconds", "ns", NULL
|
|---|
| 71 | };
|
|---|
| 72 | static enum Time_spec const time_spec[] =
|
|---|
| 73 | {
|
|---|
| 74 | TIME_SPEC_HOURS, TIME_SPEC_MINUTES,
|
|---|
| 75 | TIME_SPEC_DATE, TIME_SPEC_SECONDS, TIME_SPEC_NS
|
|---|
| 76 | };
|
|---|
| 77 | ARGMATCH_VERIFY (time_spec_string, time_spec);
|
|---|
| 78 |
|
|---|
| 79 | /* A format suitable for Internet RFC 2822. */
|
|---|
| 80 | static char const rfc_2822_format[] = "%a, %d %b %Y %H:%M:%S %z";
|
|---|
| 81 |
|
|---|
| 82 | /* The name this program was run with, for error messages. */
|
|---|
| 83 | char *program_name;
|
|---|
| 84 |
|
|---|
| 85 | /* For long options that have no equivalent short option, use a
|
|---|
| 86 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
|---|
| 87 | enum
|
|---|
| 88 | {
|
|---|
| 89 | RFC_3339_OPTION = CHAR_MAX + 1
|
|---|
| 90 | };
|
|---|
| 91 |
|
|---|
| 92 | static char const short_options[] = "d:f:I::r:Rs:u";
|
|---|
| 93 |
|
|---|
| 94 | static struct option const long_options[] =
|
|---|
| 95 | {
|
|---|
| 96 | {"date", required_argument, NULL, 'd'},
|
|---|
| 97 | {"file", required_argument, NULL, 'f'},
|
|---|
| 98 | {"iso-8601", optional_argument, NULL, 'I'}, /* Deprecated. */
|
|---|
| 99 | {"reference", required_argument, NULL, 'r'},
|
|---|
| 100 | {"rfc-822", no_argument, NULL, 'R'},
|
|---|
| 101 | {"rfc-2822", no_argument, NULL, 'R'},
|
|---|
| 102 | {"rfc-3339", required_argument, NULL, RFC_3339_OPTION},
|
|---|
| 103 | {"set", required_argument, NULL, 's'},
|
|---|
| 104 | {"uct", no_argument, NULL, 'u'},
|
|---|
| 105 | {"utc", no_argument, NULL, 'u'},
|
|---|
| 106 | {"universal", no_argument, NULL, 'u'},
|
|---|
| 107 | {GETOPT_HELP_OPTION_DECL},
|
|---|
| 108 | {GETOPT_VERSION_OPTION_DECL},
|
|---|
| 109 | {NULL, 0, NULL, 0}
|
|---|
| 110 | };
|
|---|
| 111 |
|
|---|
| 112 | #if LOCALTIME_CACHE
|
|---|
| 113 | # define TZSET tzset ()
|
|---|
| 114 | #else
|
|---|
| 115 | # define TZSET /* empty */
|
|---|
| 116 | #endif
|
|---|
| 117 |
|
|---|
| 118 | #ifdef _DATE_FMT
|
|---|
| 119 | # define DATE_FMT_LANGINFO() nl_langinfo (_DATE_FMT)
|
|---|
| 120 | #else
|
|---|
| 121 | # define DATE_FMT_LANGINFO() ""
|
|---|
| 122 | #endif
|
|---|
| 123 |
|
|---|
| 124 | void
|
|---|
| 125 | usage (int status)
|
|---|
| 126 | {
|
|---|
| 127 | if (status != EXIT_SUCCESS)
|
|---|
| 128 | fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
|---|
| 129 | program_name);
|
|---|
| 130 | else
|
|---|
| 131 | {
|
|---|
| 132 | printf (_("\
|
|---|
| 133 | Usage: %s [OPTION]... [+FORMAT]\n\
|
|---|
| 134 | or: %s [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]\n\
|
|---|
| 135 | "),
|
|---|
| 136 | program_name, program_name);
|
|---|
| 137 | fputs (_("\
|
|---|
| 138 | Display the current time in the given FORMAT, or set the system date.\n\
|
|---|
| 139 | \n\
|
|---|
| 140 | -d, --date=STRING display time described by STRING, not `now'\n\
|
|---|
| 141 | -f, --file=DATEFILE like --date once for each line of DATEFILE\n\
|
|---|
| 142 | "), stdout);
|
|---|
| 143 | fputs (_("\
|
|---|
| 144 | -r, --reference=FILE display the last modification time of FILE\n\
|
|---|
| 145 | -R, --rfc-2822 output date and time in RFC 2822 format\n\
|
|---|
| 146 | --rfc-3339=TIMESPEC output date and time in RFC 3339 format.\n\
|
|---|
| 147 | TIMESPEC=`date', `seconds', or `ns' for\n\
|
|---|
| 148 | date and time to the indicated precision.\n\
|
|---|
| 149 | -s, --set=STRING set time described by STRING\n\
|
|---|
| 150 | -u, --utc, --universal print or set Coordinated Universal Time\n\
|
|---|
| 151 | "), stdout);
|
|---|
| 152 | fputs (HELP_OPTION_DESCRIPTION, stdout);
|
|---|
| 153 | fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
|---|
| 154 | fputs (_("\
|
|---|
| 155 | \n\
|
|---|
| 156 | FORMAT controls the output. The only valid option for the second form\n\
|
|---|
| 157 | specifies Coordinated Universal Time. Interpreted sequences are:\n\
|
|---|
| 158 | \n\
|
|---|
| 159 | %% a literal %\n\
|
|---|
| 160 | %a locale's abbreviated weekday name (e.g., Sun)\n\
|
|---|
| 161 | "), stdout);
|
|---|
| 162 | fputs (_("\
|
|---|
| 163 | %A locale's full weekday name (e.g., Sunday)\n\
|
|---|
| 164 | %b locale's abbreviated month name (e.g., Jan)\n\
|
|---|
| 165 | %B locale's full month name (e.g., January)\n\
|
|---|
| 166 | %c locale's date and time (e.g., Thu Mar 3 23:05:25 2005)\n\
|
|---|
| 167 | "), stdout);
|
|---|
| 168 | fputs (_("\
|
|---|
| 169 | %C century; like %Y, except omit last two digits (e.g., 21)\n\
|
|---|
| 170 | %d day of month (e.g, 01)\n\
|
|---|
| 171 | %D date; same as %m/%d/%y\n\
|
|---|
| 172 | %e day of month, space padded; same as %_d\n\
|
|---|
| 173 | "), stdout);
|
|---|
| 174 | fputs (_("\
|
|---|
| 175 | %F full date; same as %Y-%m-%d\n\
|
|---|
| 176 | %g last two digits of year of ISO week number (see %G)\n\
|
|---|
| 177 | %G year of ISO week number (see %V); normally useful only with %V\n\
|
|---|
| 178 | "), stdout);
|
|---|
| 179 | fputs (_("\
|
|---|
| 180 | %h same as %b\n\
|
|---|
| 181 | %H hour (00..23)\n\
|
|---|
| 182 | %I hour (01..12)\n\
|
|---|
| 183 | %j day of year (001..366)\n\
|
|---|
| 184 | "), stdout);
|
|---|
| 185 | fputs (_("\
|
|---|
| 186 | %k hour ( 0..23)\n\
|
|---|
| 187 | %l hour ( 1..12)\n\
|
|---|
| 188 | %m month (01..12)\n\
|
|---|
| 189 | %M minute (00..59)\n\
|
|---|
| 190 | "), stdout);
|
|---|
| 191 | fputs (_("\
|
|---|
| 192 | %n a newline\n\
|
|---|
| 193 | %N nanoseconds (000000000..999999999)\n\
|
|---|
| 194 | %p locale's equivalent of either AM or PM; blank if not known\n\
|
|---|
| 195 | %P like %p, but lower case\n\
|
|---|
| 196 | %r locale's 12-hour clock time (e.g., 11:11:04 PM)\n\
|
|---|
| 197 | %R 24-hour hour and minute; same as %H:%M\n\
|
|---|
| 198 | %s seconds since 1970-01-01 00:00:00 UTC\n\
|
|---|
| 199 | "), stdout);
|
|---|
| 200 | fputs (_("\
|
|---|
| 201 | %S second (00..60)\n\
|
|---|
| 202 | %t a tab\n\
|
|---|
| 203 | %T time; same as %H:%M:%S\n\
|
|---|
| 204 | %u day of week (1..7); 1 is Monday\n\
|
|---|
| 205 | "), stdout);
|
|---|
| 206 | fputs (_("\
|
|---|
| 207 | %U week number of year, with Sunday as first day of week (00..53)\n\
|
|---|
| 208 | %V ISO week number, with Monday as first day of week (01..53)\n\
|
|---|
| 209 | %w day of week (0..6); 0 is Sunday\n\
|
|---|
| 210 | %W week number of year, with Monday as first day of week (00..53)\n\
|
|---|
| 211 | "), stdout);
|
|---|
| 212 | fputs (_("\
|
|---|
| 213 | %x locale's date representation (e.g., 12/31/99)\n\
|
|---|
| 214 | %X locale's time representation (e.g., 23:13:48)\n\
|
|---|
| 215 | %y last two digits of year (00..99)\n\
|
|---|
| 216 | %Y year\n\
|
|---|
| 217 | "), stdout);
|
|---|
| 218 | fputs (_("\
|
|---|
| 219 | %z +hhmm numeric timezone (e.g., -0400)\n\
|
|---|
| 220 | %:z +hh:mm numeric timezone (e.g., -04:00)\n\
|
|---|
| 221 | %::z +hh:mm:ss numeric time zone (e.g., -04:00:00)\n\
|
|---|
| 222 | %:::z numeric time zone with : to necessary precision (e.g., -04, +05:30)\n\
|
|---|
| 223 | %Z alphabetic time zone abbreviation (e.g., EDT)\n\
|
|---|
| 224 | \n\
|
|---|
| 225 | By default, date pads numeric fields with zeroes.\n\
|
|---|
| 226 | The following optional flags may follow `%':\n\
|
|---|
| 227 | \n\
|
|---|
| 228 | - (hyphen) do not pad the field\n\
|
|---|
| 229 | _ (underscore) pad with spaces\n\
|
|---|
| 230 | 0 (zero) pad with zeros\n\
|
|---|
| 231 | ^ use upper case if possible\n\
|
|---|
| 232 | # use opposite case if possible\n\
|
|---|
| 233 | "), stdout);
|
|---|
| 234 | fputs (_("\
|
|---|
| 235 | \n\
|
|---|
| 236 | After any flags comes an optional field width, as a decimal number;\n\
|
|---|
| 237 | then an optional modifier, which is either\n\
|
|---|
| 238 | E to use the locale's alternate representations if available, or\n\
|
|---|
| 239 | O to use the locale's alternate numeric symbols if available.\n\
|
|---|
| 240 | "), stdout);
|
|---|
| 241 | printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
|---|
| 242 | }
|
|---|
| 243 | exit (status);
|
|---|
| 244 | }
|
|---|
| 245 |
|
|---|
| 246 | /* Parse each line in INPUT_FILENAME as with --date and display each
|
|---|
| 247 | resulting time and date. If the file cannot be opened, tell why
|
|---|
| 248 | then exit. Issue a diagnostic for any lines that cannot be parsed.
|
|---|
| 249 | Return true if successful. */
|
|---|
| 250 |
|
|---|
| 251 | static bool
|
|---|
| 252 | batch_convert (const char *input_filename, const char *format)
|
|---|
| 253 | {
|
|---|
| 254 | bool ok;
|
|---|
| 255 | FILE *in_stream;
|
|---|
| 256 | char *line;
|
|---|
| 257 | size_t buflen;
|
|---|
| 258 | struct timespec when;
|
|---|
| 259 |
|
|---|
| 260 | if (STREQ (input_filename, "-"))
|
|---|
| 261 | {
|
|---|
| 262 | input_filename = _("standard input");
|
|---|
| 263 | in_stream = stdin;
|
|---|
| 264 | }
|
|---|
| 265 | else
|
|---|
| 266 | {
|
|---|
|
|---|