Bug 14472

Summary: date for Y#K
Product: Base System Reporter: Jin Guojun <jin>
Component: binAssignee: Sheldon Hearn <sheldonh>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.3-RELEASE   
Hardware: Any   
OS: Any   

Description Jin Guojun 1999-10-23 14:47:22 UTC
	`date` command does not take thousand/hundred digits.
	Since we are fixing Y2K problem, why don't we just simply fix
	YnK problem at once, so no one has to fix such problem in
	the next century, and for the rest centuries :-)

How-To-Repeat: 
# date 199910221913.15
date: illegal time format
usage: date [-nu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... 
            [-f fmt date | [[[[yy]mm]dd]HH]MM[.ss]] [+format]
# date 9910221913.30
Fri Oct 22 19:13:30 PDT 1999
# uname -rsm
FreeBSD 3.3-RELEASE i386
# date 210001010100
date: illegal time format
usage: date [-nu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
            [-f fmt date | [[[[yy]mm]dd]HH]MM[.ss]] [+format]
# date 0110221913.30
Mon Oct 22 19:13:30 PDT 2001
#  date 9910221917.40
Fri Oct 22 19:17:40 PDT 1999
Comment 1 Sheldon Hearn 1999-10-25 12:28:07 UTC
On Fri, 22 Oct 1999 19:32:02 MST, Jin Guojun wrote:

> # date 199910221913.15
> date: illegal time format

The following patch should give you what you want.  Note that you can
only specify 4-digit years within the range 1902-2037.

Ciao,
Sheldon.

Index: date.c
===================================================================
RCS file: /home/ncvs/src/bin/date/date.c,v
retrieving revision 1.30
diff -u -d -r1.30 date.c
--- date.c	1999/08/27 23:13:59	1.30
+++ date.c	1999/10/25 11:27:20
@@ -174,7 +174,9 @@
 	exit(retval);
 }
 
-#define	ATOI2(ar)	((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+#define	ATOI2(ar)	(((ar++)[0] - '0') * 10 + ((ar++)[1] - '0'))
+#define	ATOI4(ar)	(((ar++)[0] - '0') * 1000 + ((ar++)[1] - '0') * 100 + \
+			 ((ar++)[2] - '0') * 10 + ((ar++)[3] - '0'))
 void
 setthetime(fmt, p, jflag, nflag)
 	const char *fmt;
@@ -221,11 +223,16 @@
 
 		/* if p has a ".ss" field then let's pretend it's not there */
 		switch (strlen(p) - ((dot != NULL) ? 3 : 0)) {
+		case 12:				/* cc */
+			lt->tm_year = ATOI4(p) - 1900;
+			if (lt->tm_year < 0)
+				badformat();
+			goto year_done;
 		case 10:				/* yy */
 			lt->tm_year = ATOI2(p);
 			if (lt->tm_year < 69)		/* hack for 2000 ;-} */
 				lt->tm_year += 100;
-			/* FALLTHROUGH */
+year_done:		/* FALLTHROUGH */
 		case 8:					/* mm */
 			lt->tm_mon = ATOI2(p);
 			if (lt->tm_mon > 12)
Comment 2 Sheldon Hearn 1999-10-25 12:50:12 UTC
On Mon, 25 Oct 1999 13:28:07 +0200, Sheldon Hearn wrote:

> The following patch should give you what you want.  Note that you can
> only specify 4-digit years within the range 1902-2037.

I sent you a diff for the source, but not for the manpage. The diff for
the latter follows.

Ciao,
Sheldon.

Index: date.1
===================================================================
RCS file: /home/ncvs/src/bin/date/date.1,v
retrieving revision 1.31
diff -u -d -r1.31 date.1
--- date.1	1999/08/27 23:13:58	1.31
+++ date.1	1999/10/25 11:49:14
@@ -49,7 +49,7 @@
 .Op Fl t Ar minutes_west
 .Op Fl v Ns Ar [+|-]val Ns Op ymwdHMS
 .Ar ...
-.Op Fl f Ar fmt Ar date | [[[[yy]mm]dd]HH]MM[\&.ss]
+.Op Fl f Ar fmt Ar date | [[[[[cc]yy]mm]dd]HH]MM[\&.ss]
 .Op Cm + Ns Ar format
 .Sh DESCRIPTION
 .Nm Date
@@ -74,7 +74,7 @@
 .Ar fmt
 as the format string to parse the date provided rather than using
 the default
-.Ar [[[[yy]mm]dd]HH]MM[.ss]
+.Ar [[[[[cc]yy]mm]dd]HH]MM[.ss]
 format.  Parsing is done using
 .Xr strptime 3 .
 .It Fl j
@@ -168,6 +168,8 @@
 The canonical representation for setting the date and time is:
 .Pp
 .Bl -tag -width Ds -compact -offset indent
+.It Ar cc
+Century (either 19 or 20) prepended to the abbreviated year.
 .It Ar yy
 Year in abbreviated form (e.g. 89 for 1989, 06 for 2006).
 .It Ar mm
Comment 3 Jin Guojun 1999-10-25 17:12:37 UTC
Thanks, the patch works.

> > # date 199910221913.15
> > date: illegal time format
> 
> The following patch should give you what you want.  Note that you can
> only specify 4-digit years within the range 1902-2037.

I tried to tracing downto the time2 in /usr/src/lib/libc/stdtime/localtime.c
but had no clue how it works. That is, I could not find how the 2037 is set.
Any idea how we can fix this limitation?

Thanks,

	-Jin

> Ciao,
> Sheldon.
> 
> Index: date.c
> ===================================================================
Comment 4 Sheldon Hearn 1999-10-26 08:51:34 UTC
On Mon, 25 Oct 1999 09:12:37 MST, jin@george.lbl.gov wrote:

> That is, I could not find how the 2037 is set.  Any idea how we
> can fix this limitation?

It's not a small job. :-)

You'd need to change the definition of _BSD_TIME_T, which is a long at
the moment.  I imagine there's an enormous amount of software (including
parts of the kernel) that'd choke on this.

Ciao,
Sheldon.

PS: The function you'd wanna look at is settimeofday.
Comment 5 Sheldon Hearn 1999-10-27 08:42:29 UTC
BDE pointed out unsafe use of the post-increment operator in my diff.
This one should be safe.

Ciao,
Sheldon.

Index: date.c
===================================================================
RCS file: /home/ncvs/src/bin/date/date.c,v
retrieving revision 1.30
diff -u -d -r1.30 date.c
--- date.c	1999/08/27 23:13:59	1.30
+++ date.c	1999/10/27 07:41:09
@@ -175,6 +175,8 @@
 }
 
 #define	ATOI2(ar)	((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+#define	ATOI4(ar)	((ar)[0] - '0') * 1000 + ((ar)[1] - '0') * 100 + \
+			    ((ar)[2] - '0') * 10 + ((ar)[3] - '0'); (ar) += 4;
 void
 setthetime(fmt, p, jflag, nflag)
 	const char *fmt;
@@ -221,11 +223,16 @@
 
 		/* if p has a ".ss" field then let's pretend it's not there */
 		switch (strlen(p) - ((dot != NULL) ? 3 : 0)) {
+		case 12:				/* cc */
+			lt->tm_year = -1900 + ATOI4(p);
+			if (lt->tm_year < 0)
+				badformat();
+			goto year_done;
 		case 10:				/* yy */
 			lt->tm_year = ATOI2(p);
 			if (lt->tm_year < 69)		/* hack for 2000 ;-} */
 				lt->tm_year += 100;
-			/* FALLTHROUGH */
+year_done:		/* FALLTHROUGH */
 		case 8:					/* mm */
 			lt->tm_mon = ATOI2(p);
 			if (lt->tm_mon > 12)
Comment 6 Sheldon Hearn freebsd_committer freebsd_triage 1999-11-10 13:36:35 UTC
State Changed
From-To: open->suspended

Committed in date.c rev 1.31 and date.1 rev 1.32, waiting for MFC before 
closing. 


Comment 7 Sheldon Hearn freebsd_committer freebsd_triage 1999-11-10 13:36:35 UTC
Responsible Changed
From-To: freebsd-bugs->sheldonh

TThis reminder is for me. :-) 
Comment 8 Sheldon Hearn freebsd_committer freebsd_triage 1999-12-15 14:04:50 UTC
State Changed
From-To: suspended->closed

Merged from CURRENT in time for 3.4-RELEASE.