xref: /dflybsd-src/gnu/usr.bin/rcs/lib/rcstime.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /* Convert between RCS time format and Posix and/or C formats.  */
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /* Copyright 1992, 1993, 1994, 1995 Paul Eggert
4*86d7f5d3SJohn Marino    Distributed under license by the Free Software Foundation, Inc.
5*86d7f5d3SJohn Marino 
6*86d7f5d3SJohn Marino This file is part of RCS.
7*86d7f5d3SJohn Marino 
8*86d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
9*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
10*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
11*86d7f5d3SJohn Marino any later version.
12*86d7f5d3SJohn Marino 
13*86d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
14*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
15*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*86d7f5d3SJohn Marino GNU General Public License for more details.
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
19*86d7f5d3SJohn Marino along with RCS; see the file COPYING.
20*86d7f5d3SJohn Marino If not, write to the Free Software Foundation,
21*86d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*86d7f5d3SJohn Marino 
23*86d7f5d3SJohn Marino Report problems and direct all questions to:
24*86d7f5d3SJohn Marino 
25*86d7f5d3SJohn Marino     rcs-bugs@cs.purdue.edu
26*86d7f5d3SJohn Marino 
27*86d7f5d3SJohn Marino */
28*86d7f5d3SJohn Marino /*
29*86d7f5d3SJohn Marino  * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcstime.c,v 1.5 1999/08/27 23:36:48 peter Exp $
30*86d7f5d3SJohn Marino  * $DragonFly: src/gnu/usr.bin/rcs/lib/rcstime.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
31*86d7f5d3SJohn Marino  */
32*86d7f5d3SJohn Marino 
33*86d7f5d3SJohn Marino #include "rcsbase.h"
34*86d7f5d3SJohn Marino #include "partime.h"
35*86d7f5d3SJohn Marino #include "maketime.h"
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino libId(rcstimeId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcstime.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino static long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */
40*86d7f5d3SJohn Marino static int use_zone_offset; /* if zero, use UTC without zone indication */
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino /*
43*86d7f5d3SJohn Marino * Convert Unix time to RCS format.
44*86d7f5d3SJohn Marino * For compatibility with older versions of RCS,
45*86d7f5d3SJohn Marino * dates from 1900 through 1999 are stored without the leading "19".
46*86d7f5d3SJohn Marino */
47*86d7f5d3SJohn Marino 	void
time2date(unixtime,date)48*86d7f5d3SJohn Marino time2date(unixtime,date)
49*86d7f5d3SJohn Marino 	time_t unixtime;
50*86d7f5d3SJohn Marino 	char date[datesize];
51*86d7f5d3SJohn Marino {
52*86d7f5d3SJohn Marino 	register struct tm const *tm = time2tm(unixtime, RCSversion<VERSION(5));
53*86d7f5d3SJohn Marino 	VOID sprintf(date,
54*86d7f5d3SJohn Marino #		if has_printf_dot
55*86d7f5d3SJohn Marino 			"%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
56*86d7f5d3SJohn Marino #		else
57*86d7f5d3SJohn Marino 			"%02d.%02d.%02d.%02d.%02d.%02d",
58*86d7f5d3SJohn Marino #		endif
59*86d7f5d3SJohn Marino 		tm->tm_year  +  ((unsigned)tm->tm_year < 100 ? 0 : 1900),
60*86d7f5d3SJohn Marino 		tm->tm_mon+1, tm->tm_mday,
61*86d7f5d3SJohn Marino 		tm->tm_hour, tm->tm_min, tm->tm_sec
62*86d7f5d3SJohn Marino 	);
63*86d7f5d3SJohn Marino }
64*86d7f5d3SJohn Marino 
65*86d7f5d3SJohn Marino /* Like str2time, except die if an error was found.  */
66*86d7f5d3SJohn Marino static time_t str2time_checked P((char const*,time_t,long));
67*86d7f5d3SJohn Marino 	static time_t
str2time_checked(source,default_time,default_zone)68*86d7f5d3SJohn Marino str2time_checked(source, default_time, default_zone)
69*86d7f5d3SJohn Marino 	char const *source;
70*86d7f5d3SJohn Marino 	time_t default_time;
71*86d7f5d3SJohn Marino 	long default_zone;
72*86d7f5d3SJohn Marino {
73*86d7f5d3SJohn Marino 	time_t t = str2time(source, default_time, default_zone);
74*86d7f5d3SJohn Marino 	if (t == -1)
75*86d7f5d3SJohn Marino 		faterror("unknown date/time: %s", source);
76*86d7f5d3SJohn Marino 	return t;
77*86d7f5d3SJohn Marino }
78*86d7f5d3SJohn Marino 
79*86d7f5d3SJohn Marino /*
80*86d7f5d3SJohn Marino * Parse a free-format date in SOURCE, convert it
81*86d7f5d3SJohn Marino * into RCS internal format, and store the result into TARGET.
82*86d7f5d3SJohn Marino */
83*86d7f5d3SJohn Marino 	void
str2date(source,target)84*86d7f5d3SJohn Marino str2date(source, target)
85*86d7f5d3SJohn Marino 	char const *source;
86*86d7f5d3SJohn Marino 	char target[datesize];
87*86d7f5d3SJohn Marino {
88*86d7f5d3SJohn Marino 	time2date(
89*86d7f5d3SJohn Marino 		str2time_checked(source, now(),
90*86d7f5d3SJohn Marino 			use_zone_offset ? zone_offset
91*86d7f5d3SJohn Marino 			: RCSversion<VERSION(5) ? TM_LOCAL_ZONE
92*86d7f5d3SJohn Marino 			: 0
93*86d7f5d3SJohn Marino 		),
94*86d7f5d3SJohn Marino 		target
95*86d7f5d3SJohn Marino 	);
96*86d7f5d3SJohn Marino }
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino /* Convert an RCS internal format date to time_t.  */
99*86d7f5d3SJohn Marino 	time_t
date2time(source)100*86d7f5d3SJohn Marino date2time(source)
101*86d7f5d3SJohn Marino 	char const source[datesize];
102*86d7f5d3SJohn Marino {
103*86d7f5d3SJohn Marino 	char s[datesize + zonelenmax];
104*86d7f5d3SJohn Marino 	return str2time_checked(date2str(source, s), (time_t)0, 0);
105*86d7f5d3SJohn Marino }
106*86d7f5d3SJohn Marino 
107*86d7f5d3SJohn Marino 
108*86d7f5d3SJohn Marino /* Set the time zone for date2str output.  */
109*86d7f5d3SJohn Marino 	void
zone_set(s)110*86d7f5d3SJohn Marino zone_set(s)
111*86d7f5d3SJohn Marino 	char const *s;
112*86d7f5d3SJohn Marino {
113*86d7f5d3SJohn Marino 	if ((use_zone_offset = *s)) {
114*86d7f5d3SJohn Marino 		long zone;
115*86d7f5d3SJohn Marino 		char const *zonetail = parzone(s, &zone);
116*86d7f5d3SJohn Marino 		if (!zonetail || *zonetail)
117*86d7f5d3SJohn Marino 			error("%s: not a known time zone", s);
118*86d7f5d3SJohn Marino 		else
119*86d7f5d3SJohn Marino 			zone_offset = zone;
120*86d7f5d3SJohn Marino 	}
121*86d7f5d3SJohn Marino }
122*86d7f5d3SJohn Marino 
123*86d7f5d3SJohn Marino 
124*86d7f5d3SJohn Marino /*
125*86d7f5d3SJohn Marino * Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
126*86d7f5d3SJohn Marino * Yield DATEBUF.
127*86d7f5d3SJohn Marino */
128*86d7f5d3SJohn Marino 	char const *
date2str(date,datebuf)129*86d7f5d3SJohn Marino date2str(date, datebuf)
130*86d7f5d3SJohn Marino 	char const date[datesize];
131*86d7f5d3SJohn Marino 	char datebuf[datesize + zonelenmax];
132*86d7f5d3SJohn Marino {
133*86d7f5d3SJohn Marino 	register char const *p = date;
134*86d7f5d3SJohn Marino 
135*86d7f5d3SJohn Marino 	while (*p++ != '.')
136*86d7f5d3SJohn Marino 		continue;
137*86d7f5d3SJohn Marino 	if (!use_zone_offset)
138*86d7f5d3SJohn Marino 	    VOID sprintf(datebuf,
139*86d7f5d3SJohn Marino 		"19%.*s/%.2s/%.2s %.2s:%.2s:%s"
140*86d7f5d3SJohn Marino 			+ (date[2]=='.' && VERSION(5)<=RCSversion  ?  0  :  2),
141*86d7f5d3SJohn Marino 		(int)(p-date-1), date,
142*86d7f5d3SJohn Marino 		p, p+3, p+6, p+9, p+12
143*86d7f5d3SJohn Marino 	    );
144*86d7f5d3SJohn Marino 	else {
145*86d7f5d3SJohn Marino 	    struct tm t;
146*86d7f5d3SJohn Marino 	    struct tm const *z;
147*86d7f5d3SJohn Marino 	    int non_hour;
148*86d7f5d3SJohn Marino 	    long zone;
149*86d7f5d3SJohn Marino 	    char c;
150*86d7f5d3SJohn Marino 
151*86d7f5d3SJohn Marino 	    t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
152*86d7f5d3SJohn Marino 	    t.tm_mon = atoi(p) - 1;
153*86d7f5d3SJohn Marino 	    t.tm_mday = atoi(p+3);
154*86d7f5d3SJohn Marino 	    t.tm_hour = atoi(p+6);
155*86d7f5d3SJohn Marino 	    t.tm_min = atoi(p+9);
156*86d7f5d3SJohn Marino 	    t.tm_sec = atoi(p+12);
157*86d7f5d3SJohn Marino 	    t.tm_wday = -1;
158*86d7f5d3SJohn Marino 	    zone = zone_offset;
159*86d7f5d3SJohn Marino 	    if (zone == TM_LOCAL_ZONE) {
160*86d7f5d3SJohn Marino 		time_t u = tm2time(&t, 0), d;
161*86d7f5d3SJohn Marino 		z = localtime(&u);
162*86d7f5d3SJohn Marino 		d = difftm(z, &t);
163*86d7f5d3SJohn Marino 		zone  =  (time_t)-1 < 0 || d < -d  ?  d  :  -(long)-d;
164*86d7f5d3SJohn Marino 	    } else {
165*86d7f5d3SJohn Marino 		adjzone(&t, zone);
166*86d7f5d3SJohn Marino 		z = &t;
167*86d7f5d3SJohn Marino 	    }
168*86d7f5d3SJohn Marino 	    c = '+';
169*86d7f5d3SJohn Marino 	    if (zone < 0) {
170*86d7f5d3SJohn Marino 		zone = -zone;
171*86d7f5d3SJohn Marino 		c = '-';
172*86d7f5d3SJohn Marino 	    }
173*86d7f5d3SJohn Marino 	    VOID sprintf(datebuf,
174*86d7f5d3SJohn Marino #		if has_printf_dot
175*86d7f5d3SJohn Marino 		    "%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
176*86d7f5d3SJohn Marino #		else
177*86d7f5d3SJohn Marino 		    "%02d-%02d-%02d %02d:%02d:%02d%c%02d",
178*86d7f5d3SJohn Marino #		endif
179*86d7f5d3SJohn Marino 		z->tm_year + 1900,
180*86d7f5d3SJohn Marino 		z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec,
181*86d7f5d3SJohn Marino 		c, (int) (zone / (60*60))
182*86d7f5d3SJohn Marino 	    );
183*86d7f5d3SJohn Marino 	    if ((non_hour = zone % (60*60))) {
184*86d7f5d3SJohn Marino #		if has_printf_dot
185*86d7f5d3SJohn Marino 		    static char const fmt[] = ":%.2d";
186*86d7f5d3SJohn Marino #		else
187*86d7f5d3SJohn Marino 		    static char const fmt[] = ":%02d";
188*86d7f5d3SJohn Marino #		endif
189*86d7f5d3SJohn Marino 		VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60);
190*86d7f5d3SJohn Marino 		if ((non_hour %= 60))
191*86d7f5d3SJohn Marino 		    VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour);
192*86d7f5d3SJohn Marino 	    }
193*86d7f5d3SJohn Marino 	}
194*86d7f5d3SJohn Marino 	return datebuf;
195*86d7f5d3SJohn Marino }
196