easter.c 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6. #include <errno.h>
  7. #include <limits.h>
  8. #define METONIC_PERIOD 19
  9. void usage() {
  10. fprintf(stderr, "Usage: easter <YYYY>\n");
  11. }
  12. bool is_year(char *arg) {
  13. int c = *arg == '-' ? 1 : 0; // Skip leading negative sign
  14. while(*(arg + c) != '\0') {
  15. if(!isdigit(*(arg + c))) {
  16. return false;
  17. }
  18. ++c;
  19. }
  20. return true;
  21. }
  22. bool strtoy(char *y_str, long *y_num) {
  23. errno = 0;
  24. *y_num = strtol(y_str, NULL, 10);
  25. if((errno == ERANGE && (*y_num == LONG_MAX || *y_num == LONG_MIN))
  26. || (errno != 0 && *y_num == 0)) {
  27. return false;
  28. }
  29. return true;
  30. }
  31. // Ref: https://en.wikipedia.org/wiki/Computus#Algorithms
  32. void easter(const long year) {
  33. long a = year % METONIC_PERIOD;
  34. long b = year/100;
  35. long c = year%100;
  36. long d = b/4;
  37. long e = b%4;
  38. long f = (b + 8)/25;
  39. long g = (b - f + 1)/3;
  40. long h = (19*a + b - d - g + 15) % 30;
  41. long i = c/4;
  42. long k = c%4;
  43. long l = (32 + 2*e + 2*i - h - k) % 7;
  44. long m = (a + 11*h + 22*l)/451;
  45. long date = h + l - 7*m + 114;
  46. long month = date/31;
  47. long day = date % 31 + 1;
  48. printf("%04ld-%02ld-%02ld\n", year, month, day);
  49. }
  50. int main(int argc, char **argv) {
  51. if(argc != 2) {
  52. usage();
  53. exit(1);
  54. }
  55. if(!is_year(argv[1])) {
  56. usage();
  57. exit(1);
  58. }
  59. long Y;
  60. if(!strtoy(argv[1], &Y)) {
  61. usage();
  62. exit(1);
  63. }
  64. easter(Y);
  65. return 0;
  66. }