1/*
2 * prettydate - convert a time stamp to something readable
3 */
4#include <stdio.h>
5
6#include "ntp_fp.h"
7#include "ntp_unixtime.h"	/* includes <sys/time.h> */
8#include "lib_strbuf.h"
9#include "ntp_stdlib.h"
10
11static const char *months[] = {
12  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
13  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
14};
15
16static const char *days[] = {
17  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
18};
19
20/* Helper function to handle possible wraparound of the ntp epoch.
21
22   Works by assuming that the localtime/gmtime library functions
23   have been updated so that they work
24*/
25
26#define MAX_EPOCH_NR 1000
27
28struct tm *
29ntp2unix_tm(
30	u_long ntp, int local
31	)
32{
33	time_t t, curr;
34	struct tm *tm;
35	int curr_year, epoch_nr;
36
37	/* First get the current year: */
38	curr = time(NULL);
39	tm = local ? localtime(&curr) : gmtime(&curr);
40	if (!tm) return NULL;
41
42	curr_year = 1900 + tm->tm_year;
43
44	/* Convert the ntp timestamp to a unix utc seconds count: */
45	t = (time_t) ntp - JAN_1970;
46
47	/* Check that the ntp timestamp is not before a 136 year window centered
48	   around the current year:
49
50	   Failsafe in case of an infinite loop:
51       Allow up to 1000 epochs of 136 years each!
52	*/
53    for (epoch_nr = 0; epoch_nr < MAX_EPOCH_NR; epoch_nr++) {
54		tm = local ? localtime(&t) : gmtime(&t);
55
56#if SIZEOF_TIME_T < 4
57# include "Bletch: sizeof(time_t) < 4!"
58#endif
59
60#if SIZEOF_TIME_T == 4
61		/* If 32 bits, then year is 1970-2038, so no sense looking */
62		epoch_nr = MAX_EPOCH_NR;
63#else	/* SIZEOF_TIME_T > 4 */
64		/* Check that the resulting year is in the correct epoch: */
65		if (1900 + tm->tm_year > curr_year - 68) break;
66
67		/* Epoch wraparound: Add 2^32 seconds! */
68		t += (time_t) 65536 << 16;
69#endif /* SIZEOF_TIME_T > 4 */
70	}
71	return tm;
72}
73
74char *
75prettydate(
76	l_fp *ts
77	)
78{
79	char *bp;
80	struct tm *tm;
81	time_t sec;
82	u_long msec;
83
84	LIB_GETBUF(bp);
85
86	sec = ts->l_ui;
87	msec = ts->l_uf / 4294967;	/* fract / (2 ** 32 / 1000) */
88
89	tm = ntp2unix_tm(sec, 1);
90	if (!tm) {
91		(void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
92		       (u_long)ts->l_ui, (u_long)ts->l_uf);
93	}
94	else {
95		(void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
96		       (u_long)ts->l_ui, (u_long)ts->l_uf, days[tm->tm_wday],
97		       months[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year,
98		       tm->tm_hour,tm->tm_min, tm->tm_sec, msec);
99	}
100
101	return bp;
102}
103
104char *
105gmprettydate(
106	l_fp *ts
107	)
108{
109	char *bp;
110	struct tm *tm;
111	time_t sec;
112	u_long msec;
113
114	LIB_GETBUF(bp);
115
116	sec = ts->l_ui;
117	msec = ts->l_uf / 4294967;	/* fract / (2 ** 32 / 1000) */
118
119	tm = ntp2unix_tm(sec, 0);
120	if (!tm) {
121		(void) sprintf(bp, "%08lx.%08lx  --- --- -- ---- --:--:--",
122		       (u_long)ts->l_ui, (u_long)ts->l_uf);
123	}
124	else {
125		(void) sprintf(bp, "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
126		       (u_long)ts->l_ui, (u_long)ts->l_uf, days[tm->tm_wday],
127		       months[tm->tm_mon], tm->tm_mday, 1900 + tm->tm_year,
128		       tm->tm_hour,tm->tm_min, tm->tm_sec, msec);
129	}
130
131	return bp;
132}
133