Bug 14817

Summary: strptime(3) '%C' conversion incorrect
Product: Base System Reporter: Crist J. Clark <cjc>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me CC: kevin.ruddy
Priority: Normal    
Version: 3.3-STABLE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description Crist J. Clark 1999-11-11 05:40:01 UTC
	The strptime(3) function fills a time 'tm structure' from a
user's string using a format also provided by the user. However, the
'%C' conversion does not work as described in strftime(3) (which
strptime(3) references as containing the key for the conversions), nor
does a simple 'date +%C' return what the actual strptime(3) function
wants.

Fix: I actually looked at strptime(3) to fix something else (it
can't read formats that run together, e.g "%y%j%H%M%S"), when I
noticed the way it handles '%C' is contradictory to the manpages and
date(1)'s operation. It was a quick fix. Patch:


How-To-Repeat: 
	A C fragment,

		struct tm tm;

		strptime("19","%C",&tm);

		printf("%d\n",tm.tm_year);

Which fails using the existing code. It should return,

		0

Or of we were to substitute "20" for "19",

		100
Comment 1 Sheldon Hearn 1999-11-11 09:19:27 UTC
On Thu, 11 Nov 1999 00:43:29 EST, "Crist J. Clark" wrote:

> However, the '%C' conversion does not work as described in strftime(3)
> (which strptime(3) references as containing the key for the
> conversions), nor does a simple 'date +%C' return what the actual
> strptime(3) function wants.

I think that strptime(3) does behave as expected.  I think you're
assuming too much.

> 		struct tm tm;
> 
> 		strptime("19","%C",&tm);
> 
> 		printf("%d\n",tm.tm_year);

You can't expect tm_year to contain anything sensible after your call to
strptime, because you haven't given it enough information.  Try using it
in conjunction with %g and you'll get sensible results.

Ciao,
Sheldon.
Comment 2 Crist J. Clark 1999-11-11 15:43:26 UTC
Sheldon Hearn wrote,
> On Thu, 11 Nov 1999 00:43:29 EST, "Crist J. Clark" wrote:
> 
> > However, the '%C' conversion does not work as described in strftime(3)
> > (which strptime(3) references as containing the key for the
> > conversions), nor does a simple 'date +%C' return what the actual
> > strptime(3) function wants.
> 
> I think that strptime(3) does behave as expected.  I think you're
> assuming too much.

No, it does not. In /usr/src/lib/libc/stdtime/strptime.c we have,

                 case 'C':
                        buf = _strptime(buf, Locale->date_fmt, tm);
                        if (buf == 0)
                                return 0;
                        break;

And in stdftime.c we have,

                        case 'C':
                                /*
                                ** %C used to do a...
                                **      _fmt("%a %b %e %X %Y", t);
                                ** ...whereas now POSIX 1003.2 calls for
                                ** something completely different.
                                ** (ado, 5/24/93)
                                */
                                pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
                                        "%02d", pt, ptlim);
                                continue;

Which quite clearly points out theat strptime(3) is using something
like the _old_ (pre-93!) definition of '%C' contrary to POSIX,
strftime(3) documentation and functionality, and date(1) functionality.

stdptime.c is clearly wrong.

> > 		struct tm tm;
> > 
> > 		strptime("19","%C",&tm);
> > 
> > 		printf("%d\n",tm.tm_year);
> 
> You can't expect tm_year to contain anything sensible after your call to
> strptime, because you haven't given it enough information.  Try using it
> in conjunction with %g and you'll get sensible results.

Well, I would go to show that using the existing '%C' combined with
'%g' would not work either, but ran into a little problem. '%g' (or
'%G') is not defined at all in strptime.c.

However, I one might think "%C %y" would accomplish what you would
like. Unfortunately, '%y' _sets_ tm.tm_year, so even if '%C' did
what it was supposed to, the result would be wiped out.

So, now that I look at it more closely, since '%y' cannot be used in
combination with '%C' anyway, '%C' is pretty useless even if it works.
I also now realize if you have a date like, "10/20/50," there is no
way to tell strptime() that you mean 1950 and _not_ 2050. You'd have
to fix tm.tm_year yourself.

It actually might be best to simply elimiate '%C' from strptime.c
altogether (since the current implementation is incorrect and a fix is
almost useless even if it works) and make note of some of these issues
on the manpages. 
-- 
Crist J. Clark                           cjclark@home.com
Comment 3 Sheldon Hearn 1999-12-08 16:00:59 UTC
Hi there!

Can you let me know whether rev 1.12 of strptime.c fixed the problem.  I
haven't looked any deeper than the commit message. :-)

Thanks,
Sheldon.
Comment 4 Andrey A. Chernov freebsd_committer freebsd_triage 1999-12-08 16:34:18 UTC
State Changed
From-To: open->analyzed

Fixed in -current by different way 
Comment 5 dd freebsd_committer freebsd_triage 2001-07-13 15:22:35 UTC
State Changed
From-To: analyzed->closed

fixed long ago