logo

utils-std

Collection of commonly available Unix tools

date.c (2987B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #define _XOPEN_SOURCE 700 // strptime is in XSI
  6. #include "../lib/iso_parse.h" /* iso_parse */
  7. #include <errno.h> /* errno */
  8. #include <locale.h> /* setlocale */
  9. #include <locale.h> /* setlocale() */
  10. #include <stdio.h> /* BUFSIZ, perror(), puts() */
  11. #include <stdlib.h> /* exit(), strtol() */
  12. #include <time.h> /* time, localtime, tm, strftime, strptime */
  13. #include <unistd.h> /* getopt(), optarg, optind */
  14. static void
  15. usage()
  16. {
  17. fprintf(stderr, "date [-uR] [-d datetime] [+format]\n");
  18. fprintf(stderr, "date [-uR] -f now_format now [+format]\n");
  19. }
  20. int
  21. main(int argc, char *argv[])
  22. {
  23. char outstr[BUFSIZ];
  24. struct tm *tm;
  25. time_t now;
  26. char *format = "%c";
  27. char *input_format = NULL;
  28. int uflag = 0;
  29. int dflag = 0;
  30. int c;
  31. setlocale(LC_ALL, "");
  32. now = time(NULL);
  33. if(now == (time_t)-1)
  34. {
  35. perror("date: time");
  36. exit(EXIT_FAILURE);
  37. }
  38. while((c = getopt(argc, argv, ":d:f:uR")) != -1)
  39. {
  40. char *errstr = NULL;
  41. switch(c)
  42. {
  43. case 'd': /* Custom datetime */
  44. if(input_format != NULL)
  45. {
  46. fprintf(stderr, "date: Cannot both use '-d' and '-f'\n");
  47. exit(EXIT_FAILURE);
  48. }
  49. now = iso_parse(optarg, &errstr).tv_sec;
  50. dflag = 1;
  51. if(errstr != NULL)
  52. {
  53. fprintf(stderr, "date: iso_parse(\"%s\", …): %s\n", optarg, errstr);
  54. exit(EXIT_FAILURE);
  55. }
  56. break;
  57. case 'f': /* input datetime format */
  58. if(dflag == 1)
  59. {
  60. fprintf(stderr, "date: Cannot both use '-d' and '-f'\n");
  61. exit(EXIT_FAILURE);
  62. }
  63. input_format = optarg;
  64. break;
  65. case 'u': /* UTC timezone */
  66. uflag++;
  67. break;
  68. case 'R': /* Email (RFC 5322) format */
  69. format = "%a, %d %b %Y %H:%M:%S %z";
  70. break;
  71. case ':':
  72. fprintf(stderr, "date: Error: Missing operand for option: '-%c'\n", optopt);
  73. usage();
  74. return 1;
  75. case '?':
  76. fprintf(stderr, "date: Error: Unrecognised option: '-%c'\n", optopt);
  77. usage();
  78. return 1;
  79. }
  80. }
  81. if(uflag)
  82. {
  83. tm = gmtime(&now);
  84. if(tm == NULL)
  85. {
  86. perror("date: gmtime");
  87. exit(EXIT_FAILURE);
  88. }
  89. }
  90. else
  91. {
  92. tm = localtime(&now);
  93. if(tm == NULL)
  94. {
  95. perror("date: localtime");
  96. exit(EXIT_FAILURE);
  97. }
  98. }
  99. argc -= optind;
  100. argv += optind;
  101. if(argc > 0 && input_format != NULL)
  102. {
  103. char *res = strptime(argv[0], input_format, tm);
  104. if(res == NULL)
  105. {
  106. fprintf(stderr,
  107. "date: strptime(\"%s\", \"%s\", …) as passed by '-f' option failed\n",
  108. argv[0],
  109. input_format);
  110. exit(EXIT_FAILURE);
  111. }
  112. argv++;
  113. argc--;
  114. }
  115. if(argc > 0 && *argv && **argv == '+')
  116. {
  117. format = *argv + 1;
  118. argv++;
  119. argc--;
  120. }
  121. errno = 0;
  122. if(strftime(outstr, sizeof(outstr), format, tm) == 0 && errno != 0)
  123. {
  124. perror("date: strftime");
  125. exit(EXIT_FAILURE);
  126. }
  127. if(puts(outstr) < 0)
  128. {
  129. perror("date: puts");
  130. exit(EXIT_FAILURE);
  131. }
  132. return 0;
  133. }