111891Speter/* Convert between RCS time format and Posix and/or C formats.  */
211891Speter
311891Speter/* Copyright 1992, 1993, 1994, 1995 Paul Eggert
411891Speter   Distributed under license by the Free Software Foundation, Inc.
511891Speter
611891SpeterThis file is part of RCS.
711891Speter
811891SpeterRCS is free software; you can redistribute it and/or modify
911891Speterit under the terms of the GNU General Public License as published by
1011891Speterthe Free Software Foundation; either version 2, or (at your option)
1111891Speterany later version.
1211891Speter
1311891SpeterRCS is distributed in the hope that it will be useful,
1411891Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1511891SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1611891SpeterGNU General Public License for more details.
1711891Speter
1811891SpeterYou should have received a copy of the GNU General Public License
1911891Speteralong with RCS; see the file COPYING.
2011891SpeterIf not, write to the Free Software Foundation,
2111891Speter59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2211891Speter
2311891SpeterReport problems and direct all questions to:
2411891Speter
2511891Speter    rcs-bugs@cs.purdue.edu
2611891Speter
2711891Speter*/
2811891Speter
2911891Speter#include "rcsbase.h"
3011891Speter#include "partime.h"
3111891Speter#include "maketime.h"
3211891Speter
3350472SpeterlibId(rcstimeId, "$FreeBSD$")
3411891Speter
3511891Speterstatic long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */
3611891Speterstatic int use_zone_offset; /* if zero, use UTC without zone indication */
3711891Speter
3811891Speter/*
3911891Speter* Convert Unix time to RCS format.
4011891Speter* For compatibility with older versions of RCS,
4111891Speter* dates from 1900 through 1999 are stored without the leading "19".
4211891Speter*/
4311891Speter	void
4411891Spetertime2date(unixtime,date)
4511891Speter	time_t unixtime;
4611891Speter	char date[datesize];
4711891Speter{
4811891Speter	register struct tm const *tm = time2tm(unixtime, RCSversion<VERSION(5));
4911891Speter	VOID sprintf(date,
5011891Speter#		if has_printf_dot
5111891Speter			"%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
5211891Speter#		else
5311891Speter			"%02d.%02d.%02d.%02d.%02d.%02d",
5411891Speter#		endif
5511891Speter		tm->tm_year  +  ((unsigned)tm->tm_year < 100 ? 0 : 1900),
5611891Speter		tm->tm_mon+1, tm->tm_mday,
5711891Speter		tm->tm_hour, tm->tm_min, tm->tm_sec
5811891Speter	);
5911891Speter}
6011891Speter
6111891Speter/* Like str2time, except die if an error was found.  */
6211891Speterstatic time_t str2time_checked P((char const*,time_t,long));
6311891Speter	static time_t
6411891Speterstr2time_checked(source, default_time, default_zone)
6511891Speter	char const *source;
6611891Speter	time_t default_time;
6711891Speter	long default_zone;
6811891Speter{
6911891Speter	time_t t = str2time(source, default_time, default_zone);
7011891Speter	if (t == -1)
7111891Speter		faterror("unknown date/time: %s", source);
7211891Speter	return t;
7311891Speter}
7411891Speter
7511891Speter/*
7611891Speter* Parse a free-format date in SOURCE, convert it
7711891Speter* into RCS internal format, and store the result into TARGET.
7811891Speter*/
7911891Speter	void
8011891Speterstr2date(source, target)
8111891Speter	char const *source;
8211891Speter	char target[datesize];
8311891Speter{
8411891Speter	time2date(
8511891Speter		str2time_checked(source, now(),
8611891Speter			use_zone_offset ? zone_offset
8711891Speter			: RCSversion<VERSION(5) ? TM_LOCAL_ZONE
8811891Speter			: 0
8911891Speter		),
9011891Speter		target
9111891Speter	);
9211891Speter}
9311891Speter
9411891Speter/* Convert an RCS internal format date to time_t.  */
9511891Speter	time_t
9611891Speterdate2time(source)
9711891Speter	char const source[datesize];
9811891Speter{
9911891Speter	char s[datesize + zonelenmax];
10011891Speter	return str2time_checked(date2str(source, s), (time_t)0, 0);
10111891Speter}
10211891Speter
10311891Speter
10411891Speter/* Set the time zone for date2str output.  */
10511891Speter	void
10611891Speterzone_set(s)
10711891Speter	char const *s;
10811891Speter{
10911891Speter	if ((use_zone_offset = *s)) {
11011891Speter		long zone;
11111891Speter		char const *zonetail = parzone(s, &zone);
11211891Speter		if (!zonetail || *zonetail)
11311891Speter			error("%s: not a known time zone", s);
11411891Speter		else
11511891Speter			zone_offset = zone;
11611891Speter	}
11711891Speter}
11811891Speter
11911891Speter
12011891Speter/*
12111891Speter* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
12211891Speter* Yield DATEBUF.
12311891Speter*/
12411891Speter	char const *
12511891Speterdate2str(date, datebuf)
12611891Speter	char const date[datesize];
12711891Speter	char datebuf[datesize + zonelenmax];
12811891Speter{
12911891Speter	register char const *p = date;
13011891Speter
13111891Speter	while (*p++ != '.')
13211891Speter		continue;
13311891Speter	if (!use_zone_offset)
13411891Speter	    VOID sprintf(datebuf,
13511891Speter		"19%.*s/%.2s/%.2s %.2s:%.2s:%s"
13611891Speter			+ (date[2]=='.' && VERSION(5)<=RCSversion  ?  0  :  2),
13711891Speter		(int)(p-date-1), date,
13811891Speter		p, p+3, p+6, p+9, p+12
13911891Speter	    );
14011891Speter	else {
14111891Speter	    struct tm t;
14211891Speter	    struct tm const *z;
14311891Speter	    int non_hour;
14411891Speter	    long zone;
14511891Speter	    char c;
14611891Speter
14711891Speter	    t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
14811891Speter	    t.tm_mon = atoi(p) - 1;
14911891Speter	    t.tm_mday = atoi(p+3);
15011891Speter	    t.tm_hour = atoi(p+6);
15111891Speter	    t.tm_min = atoi(p+9);
15211891Speter	    t.tm_sec = atoi(p+12);
15311891Speter	    t.tm_wday = -1;
15411891Speter	    zone = zone_offset;
15511891Speter	    if (zone == TM_LOCAL_ZONE) {
15611891Speter		time_t u = tm2time(&t, 0), d;
15711891Speter		z = localtime(&u);
15811891Speter		d = difftm(z, &t);
15911891Speter		zone  =  (time_t)-1 < 0 || d < -d  ?  d  :  -(long)-d;
16011891Speter	    } else {
16111891Speter		adjzone(&t, zone);
16211891Speter		z = &t;
16311891Speter	    }
16411891Speter	    c = '+';
16511891Speter	    if (zone < 0) {
16611891Speter		zone = -zone;
16711891Speter		c = '-';
16811891Speter	    }
16911891Speter	    VOID sprintf(datebuf,
17011891Speter#		if has_printf_dot
17111891Speter		    "%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
17211891Speter#		else
17311891Speter		    "%02d-%02d-%02d %02d:%02d:%02d%c%02d",
17411891Speter#		endif
17511891Speter		z->tm_year + 1900,
17611891Speter		z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec,
17711891Speter		c, (int) (zone / (60*60))
17811891Speter	    );
17911891Speter	    if ((non_hour = zone % (60*60))) {
18011891Speter#		if has_printf_dot
18111891Speter		    static char const fmt[] = ":%.2d";
18211891Speter#		else
18311891Speter		    static char const fmt[] = ":%02d";
18411891Speter#		endif
18511891Speter		VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60);
18611891Speter		if ((non_hour %= 60))
18711891Speter		    VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour);
18811891Speter	    }
18911891Speter	}
19011891Speter	return datebuf;
19111891Speter}
192