← Back to davo.co
aboutsummaryrefslogtreecommitdiffstats
path: root/terran.c
blob: e604cd9a782099674ff8784c849342f7e2888437 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>

/*
   terran multiplicative factors between units that are fixed for
   Lunar, Day, Hour, Minute, Second
*/
enum { dl = 28, hd = 24, mh = 60, sm = 60, sh = mh*sm, sd = hd * mh * sm, };

/*
  There is a long term period of 128 years, that has exactly 31 leap
  years. This amounts to 46751 days.
*/
enum { dy = 365, yp = 128, dp = yp*dy + 31, };

/*
   Then, periods of four years are grouped together, that have either
   0 or 1 leap year.
*/
enum { yq = 4, dq0 = yq*dy, dq1 = dq0 + 1, };

time_t isotime(char const t[static 1]) {
  struct tm date[1] = {
    [0] = { .tm_year = 1900,.tm_mon = 1, },
  };
  int retscan = sscanf(t, "%i-%i-%i %i:%i:%i",
                       &date->tm_year, &date->tm_mon, &date->tm_mday,
                       &date->tm_hour, &date->tm_min, &date->tm_sec);
  if (retscan <= 0) {
    if (errno) perror("can't scan");
    return 0;
  }
  date->tm_year -= 1900;
  date->tm_mon -= 1;
  return mktime(date);
  /* gmtime_r(&ret, date); */
  /* return mktime(date); */
}

void time2terran(time_t t) {
  /* Provide us with the terran epoch. This is not as easy as it may
     appear as a first site, since it is difficult to express a UTC
     timestamp in a struct tm: we have convert back and forth with
     mktime and gmtime to obtain the correct timestamp at 1969-12-22 0:0:0.
   */
  struct tm terranEpoch[1] = {
    {
      .tm_year = 69, // year starts at 1900
      .tm_mon = 11,  // mon starts at 0
      .tm_mday = 23, // mday starts at 1
    },
  };
  time_t epoch = mktime(terranEpoch);
  struct tm terranEpoch2[1];
  gmtime_r(&epoch, terranEpoch2);
  time_t epoch2 = mktime(terranEpoch2);
  terranEpoch[0].tm_sec += difftime(epoch2, epoch);
  epoch = mktime(terranEpoch);

  /* Now that we have the appropriate epoch, look how many seconds
     have passed since then.
  */
  long secs = difftime(t, epoch);
  long days = secs/sd;
  secs -= days*sd;

  /*
    adjust with respect to the 128 year periods
   */
  long per = days / dp;
  if (days < 0) {
    per -= 1;
  }
  long year = per * yp;
  days -= per*dp;

  // the first four years aren't leap years
  if (days < dq0) {
    year += (days / dy);
    days -= (days / dy) * dy;
  } else {
    // correct for the first 4 years
    year += yq;
    days -= dq0;
    /*
       In the remaining period every fourth year starting with year 0
       is a leap year. Compute the amount of such 4 year periods and
       adjust
    */
    long const qer = days / dq1;
    year += qer*yq;
    days %= dq1;
    // the first year is a leap year
    if (days > dy+1) {
      // adjust for that leap year
      year += 1;
      days -= (dy+1);
      // compute the remaining days
      year += (days / dy);
      days %= dy;
    }
  }
  size_t const lunar = days / dl;
  days %= dl;
  while (secs < 0) secs += sd;
  size_t hour = secs / sh;
  secs -= hour*sh;
  size_t min = secs / sm;
  secs %= sm;
  printf("%ld.%ld.%ld,%ld:%ld:%ld TC\n", year, lunar, days, hour, min, secs);
}

int main (int argc, char* argv[argc+1]) {
  time_t now = time(0);
  time2terran(now);
  for (int i = 1; i < argc; ++i)
    time2terran(isotime(argv[i]));
  return EXIT_SUCCESS;
}