xref: /plan9/sys/src/ape/lib/ap/gen/strftime.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <time.h>
2*3e12c5d1SDavid du Colombier #include <string.h>
3*3e12c5d1SDavid du Colombier 
4*3e12c5d1SDavid du Colombier static char *awday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
5*3e12c5d1SDavid du Colombier static char *wday[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
6*3e12c5d1SDavid du Colombier 			"Friday", "Saturday"};
7*3e12c5d1SDavid du Colombier static char *amon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
8*3e12c5d1SDavid du Colombier 			    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
9*3e12c5d1SDavid du Colombier static char *mon[12] = {"January", "February", "March", "April", "May", "June",
10*3e12c5d1SDavid du Colombier 		"July", "August", "September", "October", "November", "December"};
11*3e12c5d1SDavid du Colombier static char *ampm[2] = {"AM", "PM"};
12*3e12c5d1SDavid du Colombier static char *tz[2] = {"EST", "EDT"};
13*3e12c5d1SDavid du Colombier 
14*3e12c5d1SDavid du Colombier static int jan1(int);
15*3e12c5d1SDavid du Colombier static char *strval(char *, char *, char **, int, int);
16*3e12c5d1SDavid du Colombier static char *dval(char *, char *, int, int);
17*3e12c5d1SDavid du Colombier 
18*3e12c5d1SDavid du Colombier size_t
strftime(char * s,size_t maxsize,const char * format,const struct tm * t)19*3e12c5d1SDavid du Colombier strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
20*3e12c5d1SDavid du Colombier {
21*3e12c5d1SDavid du Colombier 	char *sp, *se, *fp;
22*3e12c5d1SDavid du Colombier 	int i;
23*3e12c5d1SDavid du Colombier 
24*3e12c5d1SDavid du Colombier 	sp = s;
25*3e12c5d1SDavid du Colombier 	se = s+maxsize;
26*3e12c5d1SDavid du Colombier 	for(fp=(char *)format; *fp && sp<se; fp++){
27*3e12c5d1SDavid du Colombier 		if(*fp != '%')
28*3e12c5d1SDavid du Colombier 			*sp++ = *fp;
29*3e12c5d1SDavid du Colombier 		else switch(*++fp){
30*3e12c5d1SDavid du Colombier 			case 'a':
31*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, awday, t->tm_wday, 7);
32*3e12c5d1SDavid du Colombier 				break;
33*3e12c5d1SDavid du Colombier 			case 'A':
34*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, wday, t->tm_wday, 7);
35*3e12c5d1SDavid du Colombier 				break;
36*3e12c5d1SDavid du Colombier 			case 'b':
37*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, amon, t->tm_mon, 12);
38*3e12c5d1SDavid du Colombier 				break;
39*3e12c5d1SDavid du Colombier 			case 'B':
40*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, mon, t->tm_mon, 12);
41*3e12c5d1SDavid du Colombier 				break;
42*3e12c5d1SDavid du Colombier 			case 'c':
43*3e12c5d1SDavid du Colombier 				sp += strftime(sp, se-sp, "%a %b %d %H:%M:%S %Y", t);
44*3e12c5d1SDavid du Colombier 				break;
45*3e12c5d1SDavid du Colombier 			case 'd':
46*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_mday, 2);
47*3e12c5d1SDavid du Colombier 				break;
48*3e12c5d1SDavid du Colombier 			case 'H':
49*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_hour, 2);
50*3e12c5d1SDavid du Colombier 				break;
51*3e12c5d1SDavid du Colombier 			case 'I':
52*3e12c5d1SDavid du Colombier 				i = t->tm_hour;
53*3e12c5d1SDavid du Colombier 				if(i == 0)
54*3e12c5d1SDavid du Colombier 					i = 12;
55*3e12c5d1SDavid du Colombier 				else if(i > 12)
56*3e12c5d1SDavid du Colombier 					i -= 12;
57*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, i, 2);
58*3e12c5d1SDavid du Colombier 				break;
59*3e12c5d1SDavid du Colombier 			case 'j':
60*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_yday+1, 3);
61*3e12c5d1SDavid du Colombier 				break;
62*3e12c5d1SDavid du Colombier 			case 'm':
63*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_mon+1, 2);
64*3e12c5d1SDavid du Colombier 				break;
65*3e12c5d1SDavid du Colombier 			case 'M':
66*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_min, 2);
67*3e12c5d1SDavid du Colombier 				break;
68*3e12c5d1SDavid du Colombier 			case 'p':
69*3e12c5d1SDavid du Colombier 				i = (t->tm_hour < 12)? 0 : 1;
70*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, ampm, i, 2);
71*3e12c5d1SDavid du Colombier 				break;
72*3e12c5d1SDavid du Colombier 			case 'S':
73*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_sec, 2);
74*3e12c5d1SDavid du Colombier 				break;
75*3e12c5d1SDavid du Colombier 			case 'U':
76*3e12c5d1SDavid du Colombier 				i = 7-jan1(t->tm_year);
77*3e12c5d1SDavid du Colombier 				if(i == 7)
78*3e12c5d1SDavid du Colombier 					i = 0;
79*3e12c5d1SDavid du Colombier 				/* Now i is yday number of first sunday in year */
80*3e12c5d1SDavid du Colombier 				if(t->tm_yday < i)
81*3e12c5d1SDavid du Colombier 					i = 0;
82*3e12c5d1SDavid du Colombier 				else
83*3e12c5d1SDavid du Colombier 					i = (t->tm_yday-i)/7 + 1;
84*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, i, 2);
85*3e12c5d1SDavid du Colombier 				break;
86*3e12c5d1SDavid du Colombier 			case 'w':
87*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_wday, 1);
88*3e12c5d1SDavid du Colombier 				break;
89*3e12c5d1SDavid du Colombier 			case 'W':
90*3e12c5d1SDavid du Colombier 				i = 8-jan1(t->tm_year);
91*3e12c5d1SDavid du Colombier 				if(i >= 7)
92*3e12c5d1SDavid du Colombier 					i -= 7;
93*3e12c5d1SDavid du Colombier 				/* Now i is yday number of first monday in year */
94*3e12c5d1SDavid du Colombier 				if(t->tm_yday < i)
95*3e12c5d1SDavid du Colombier 					i = 0;
96*3e12c5d1SDavid du Colombier 				else
97*3e12c5d1SDavid du Colombier 					i = (t->tm_yday-i)/7 + 1;
98*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, i, 2);
99*3e12c5d1SDavid du Colombier 				break;
100*3e12c5d1SDavid du Colombier 			case 'x':
101*3e12c5d1SDavid du Colombier 				sp += strftime(sp, se-sp, "%a %b %d, %Y", t);
102*3e12c5d1SDavid du Colombier 				break;
103*3e12c5d1SDavid du Colombier 			case 'X':
104*3e12c5d1SDavid du Colombier 				sp += strftime(sp, se-sp, "%H:%M:%S", t);
105*3e12c5d1SDavid du Colombier 				break;
106*3e12c5d1SDavid du Colombier 			case 'y':
107*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_year%100, 2);
108*3e12c5d1SDavid du Colombier 				break;
109*3e12c5d1SDavid du Colombier 			case 'Y':
110*3e12c5d1SDavid du Colombier 				sp = dval(sp, se, t->tm_year+1900, 4);
111*3e12c5d1SDavid du Colombier 				break;
112*3e12c5d1SDavid du Colombier 			case 'Z':
113*3e12c5d1SDavid du Colombier 				/* hack for now: assume eastern time zone */
114*3e12c5d1SDavid du Colombier 				i = t->tm_isdst? 1 : 0;
115*3e12c5d1SDavid du Colombier 				sp = strval(sp, se, tz, i, 2);
116*3e12c5d1SDavid du Colombier 				break;
117*3e12c5d1SDavid du Colombier 			case 0:
118*3e12c5d1SDavid du Colombier 				fp--; /* stop loop after next fp incr */
119*3e12c5d1SDavid du Colombier 				break;
120*3e12c5d1SDavid du Colombier 			default:
121*3e12c5d1SDavid du Colombier 				*sp++ = *fp;
122*3e12c5d1SDavid du Colombier 			}
123*3e12c5d1SDavid du Colombier 	}
124*3e12c5d1SDavid du Colombier 	if(*fp)
125*3e12c5d1SDavid du Colombier 		sp = s; /* format string didn't end: no room for conversion */
126*3e12c5d1SDavid du Colombier 	if(sp<se)
127*3e12c5d1SDavid du Colombier 		*sp = 0;
128*3e12c5d1SDavid du Colombier 	return sp-s;
129*3e12c5d1SDavid du Colombier }
130*3e12c5d1SDavid du Colombier 
131*3e12c5d1SDavid du Colombier static char *
strval(char * start,char * end,char ** array,int index,int alen)132*3e12c5d1SDavid du Colombier strval(char *start, char *end, char **array, int index, int alen)
133*3e12c5d1SDavid du Colombier {
134*3e12c5d1SDavid du Colombier 	int n;
135*3e12c5d1SDavid du Colombier 
136*3e12c5d1SDavid du Colombier 	if(index<0 || index>=alen){
137*3e12c5d1SDavid du Colombier 		*start = '?';
138*3e12c5d1SDavid du Colombier 		return start+1;
139*3e12c5d1SDavid du Colombier 	}
140*3e12c5d1SDavid du Colombier 	n = strlen(array[index]);
141*3e12c5d1SDavid du Colombier 	if(n > end-start)
142*3e12c5d1SDavid du Colombier 		n = end-start;
143*3e12c5d1SDavid du Colombier 	memcpy(start, array[index], n);
144*3e12c5d1SDavid du Colombier 	return start+n;
145*3e12c5d1SDavid du Colombier }
146*3e12c5d1SDavid du Colombier 
147*3e12c5d1SDavid du Colombier static char *
dval(char * start,char * end,int val,int width)148*3e12c5d1SDavid du Colombier dval(char *start, char *end, int val, int width)
149*3e12c5d1SDavid du Colombier {
150*3e12c5d1SDavid du Colombier 	char *p;
151*3e12c5d1SDavid du Colombier 
152*3e12c5d1SDavid du Colombier 	if(val<0 || end-start<width){
153*3e12c5d1SDavid du Colombier 		*start = '?';
154*3e12c5d1SDavid du Colombier 		return start+1;
155*3e12c5d1SDavid du Colombier 	}
156*3e12c5d1SDavid du Colombier 	p = start+width-1;
157*3e12c5d1SDavid du Colombier 	while(p>=start){
158*3e12c5d1SDavid du Colombier 		*p-- = val%10 + '0';
159*3e12c5d1SDavid du Colombier 		val /= 10;
160*3e12c5d1SDavid du Colombier 	}
161*3e12c5d1SDavid du Colombier 	if(val>0)
162*3e12c5d1SDavid du Colombier 		*start = '*';
163*3e12c5d1SDavid du Colombier 	return start+width;
164*3e12c5d1SDavid du Colombier }
165*3e12c5d1SDavid du Colombier 
166*3e12c5d1SDavid du Colombier /*
167*3e12c5d1SDavid du Colombier  *	return day of the week
168*3e12c5d1SDavid du Colombier  *	of jan 1 of given year
169*3e12c5d1SDavid du Colombier  */
170*3e12c5d1SDavid du Colombier static int
jan1(int yr)171*3e12c5d1SDavid du Colombier jan1(int yr)
172*3e12c5d1SDavid du Colombier {
173*3e12c5d1SDavid du Colombier 	int y, d;
174*3e12c5d1SDavid du Colombier 
175*3e12c5d1SDavid du Colombier /*
176*3e12c5d1SDavid du Colombier  *	normal gregorian calendar
177*3e12c5d1SDavid du Colombier  *	one extra day per four years
178*3e12c5d1SDavid du Colombier  */
179*3e12c5d1SDavid du Colombier 
180*3e12c5d1SDavid du Colombier 	y = yr+1900;
181*3e12c5d1SDavid du Colombier 	d = 4+y+(y+3)/4;
182*3e12c5d1SDavid du Colombier 
183*3e12c5d1SDavid du Colombier /*
184*3e12c5d1SDavid du Colombier  *	julian calendar
185*3e12c5d1SDavid du Colombier  *	regular gregorian
186*3e12c5d1SDavid du Colombier  *	less three days per 400
187*3e12c5d1SDavid du Colombier  */
188*3e12c5d1SDavid du Colombier 
189*3e12c5d1SDavid du Colombier 	if(y > 1800) {
190*3e12c5d1SDavid du Colombier 		d -= (y-1701)/100;
191*3e12c5d1SDavid du Colombier 		d += (y-1601)/400;
192*3e12c5d1SDavid du Colombier 	}
193*3e12c5d1SDavid du Colombier 
194*3e12c5d1SDavid du Colombier /*
195*3e12c5d1SDavid du Colombier  *	great calendar changeover instant
196*3e12c5d1SDavid du Colombier  */
197*3e12c5d1SDavid du Colombier 
198*3e12c5d1SDavid du Colombier 	if(y > 1752)
199*3e12c5d1SDavid du Colombier 		d += 3;
200*3e12c5d1SDavid du Colombier 
201*3e12c5d1SDavid du Colombier 	return(d%7);
202*3e12c5d1SDavid du Colombier }
203