Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 527 forks source link

Possible bug using POSIX::strftime Digital UNIX Perl 5.005_03 #514

Closed p5pRT closed 20 years ago

p5pRT commented 24 years ago

Migrated from rt.perl.org#1361 (status was 'resolved')

Searchable as RT1361$

p5pRT commented 24 years ago

From phil@finchcomputer.com

I believe I have found a bug in Perl > 5.004_04 (possibly only Perl 5.005+) using POSIX​::strftime. I've been using POSIX​::strftime to print out formatted times obtained through Perl's gmtime call. Everything is fine when not going through strftime (i.e. scalar(gmtime)) or using Perl 5.004_01-5.004_04\, but when format the times through strftime 5.005_03 it seems to get confused about daylight savings times even though I'm passing it a full array from gmtime.

The problem seems to be that strftime C module calls mktime() which sets (or actually improperly re-sets) "isdst" in the data structure I passed to it causing time to be 1 hour off with data structures that would land within my DST period. I think stftime shouldn't be calling mktime but I'm not 100% sure. This didn't used to happen (perl 5.004_01-03 anyway) and with 5.005 it breaks my database application.

Should I not use strftime? Is strftime supposed to call mktime? It seems a bit dangerous to assume the programmer actually wants this behavior but maybe I'm missing something here.

The *real* world where I've run into problems\, gmtime sets tm_isdst to 0 appropriately\, but using POSIX​::strftime make things look like daylight savings time apparently!

% /opt/dtv/bin/perl -e '@​tmp=gmtime;use POSIX; print scalar(gmtime)\,   " or (@​tmp)\n"\,POSIX​::strftime("%Y %m %d %H​:%M​:%S"\, @​tmp)\, "\n"' ;   Fri Sep 3 00​:46​:11 1999 or (11 46 0 3 8 99 5 245 0)   1999 09 03 01​:46​:11

% /opt/dtv/bin/perl -e '@​tmp=gmtime;use POSIX; print scalar(gmtime)\,   " or (@​tmp) "\,POSIX​::strftime("%Y %m %d %H​:%M​:%S"\, @​tmp)\, "\n"' ;   Fri Sep 3 00​:57​:37 1999 or (37 57 0 3 8 99 5 245 0)   1999 09 03 01​:57​:37

The equivalent C code that works without this problem.

Details\, including output from perlbug below\, and I believe I've found a fix for it (not sure if it's the proper fix or not since I may be missing somethinge here) the diff is included below...

Phil -- Phillip E. Lobbes http​://www.finchcomputer.com/ (818)550-9060 phil@​finchcomputer.com

Details...

* The system (Digital UNIX 4\, Perl 5.005_03)​:   bambam% uname -a   OSF1 bambam V4.0 1091 alpha

* The problematic type of Perl program (NOTE​: note 1hr difference!)​:   #!/opt/dtv/bin/perl   use POSIX;   @​tmp=gmtime;   print(scalar(gmtime)\, " or (@​tmp)\n"\,   POSIX​::strftime("%Y %m %d %H​:%M​:%S"\, @​tmp)\,   "\n");   Fri Sep 3 00​:46​:11 1999 or (11 46 0 3 8 99 5 245 0)   1999 09 03 01​:46​:11

* Sample C code that works...   #include \<time.h>   #include \<stdio.h>   #define SLENGTH 80  
  main() {   char nowstr[SLENGTH];   time_t nowbin;   const struct tm *nowstruct;  
  if (time(&nowbin) == (time_t) - 1)   printf("Could not get time of day from time()\n");  
  nowstruct = gmtime(&nowbin);   printf("isdst bef %d\n"\, nowstruct->tm_isdst);   if (strftime(nowstr\, SLENGTH\, "%Y %m %d %H​:%M​:%S"\, nowstruct) ==   (size_t) 0)   printf("Could not get string from strftime()\n");   printf("Today's date gm bef is %s\n"\, nowstr);  
  mktime(nowstruct);   printf("isdst aft %d\n"\, nowstruct->tm_isdst);   if (strftime(nowstr\, SLENGTH\, "%Y %m %d %H​:%M​:%S"\, nowstruct) ==   (size_t) 0)   printf("Could not get string from strftime()\n");  
  printf("Today's date gm aft is %s\n"\, nowstr);   }

* Output from the system date call and from the C code. The first time   is the expected time\, the second time emulates the Perl POSIX module   behavior...

  % date -u   Mon Sep 13 21​:34​:52 UTC 1999   % a.out   isdst bef 0   Today's date gm bef is 1999 09 13 21​:34​:53   isdst aft 1   Today's date gm aft is 1999 09 13 22​:34​:53

* POSSIBLE FIX​: Output from diff directory is perl5.005_03/ext/POSIX...   % diff POSIX.xs POSIX.xs.ORIG   3632c3632   \< /* BAD resets ISDST settings​: (void) mktime(&mytm); */   ---   > (void) mktime(&mytm);

* bambam% /opt/dtv/perl/5.005_03/bin/perlbug -d -v Site configuration information for perl 5.00503​:

Configured by lobbesp at Mon Jul 19 10​:56​:06 PDT 1999.

Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration​:   Platform​:   osname=dec_osf\, osvers=4.0\, archname=alpha-dec_osf   uname='osf1 bambam v4.0 1091 alpha '   hint=recommended\, useposix=true\, d_sigaction=define   usethreads=undef useperlio=undef d_sfio=undef   Compiler​:   cc='cc'\, optimize='-O4'\, gccversion=   cppflags='-std -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C'   ccflags ='-std -fprm d -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C'   stdchar='unsigned char'\, d_stdstdio=define\, usevfork=false   intsize=4\, longsize=8\, ptrsize=8\, doublesize=8   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=8   alignbytes=8\, usemymalloc=y\, prototype=define   Linker and Libraries​:   ld='ld'\, ldflags =' -L/usr/local/lib -L/opt/local/lib'   libpth=/usr/local/lib /opt/local/lib /usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib   libs=-ldbm -ldb -lm   libc=/usr/shlib/libc.so\, so=so\, useshrplib=true\, libperl=libperl.so   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags=' -Wl\,-rpath\,/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf/CORE'   cccdlflags=' '\, lddlflags='-shared -expect_unresolved "*" -O4 -msym -s -L/usr/local/lib -L/opt/local/lib'

Locally applied patches​:  


@​INC for perl 5.00503​:   /opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf   /opt/dtv/perl/5.005_03/lib/5.00503   /opt/dtv/perl/5.005_03/lib/site_perl/5.005/alpha-dec_osf   /opt/dtv/perl/5.005_03/lib/site_perl/5.005   .


Environment for perl 5.00503​:   HOME=/home/lobbesp   LANG (unset)   LANGUAGE (unset)   LD_LIBRARY_PATH=/oracle/app/oracle/product/8.0.5/lib   LOGDIR (unset)   PATH=/home/lobbesp/bin​:/home/lobbesp/X/bin​:/home/lobbesp/scripts​:/usr/bin​:.​:/oracle/app/oracle/product/8.0.5/bin​:/oracle/app/oracle/product/8.0.5/obackup/bin​:/sbin​:/usr/sbin​:/usr/bin/X11​:/usr/ccs/bin​:/home/lobbesp/site/bin​:/home/lobbesp/scripts​:/usr/local/bin​:/opt/dtv/bin​:/usr/dt​:.   PERL_BADLANG (unset)   SHELL=/usr/local/bin/tcsh

Complete configuration data for perl 5.00503​:

Author='' CONFIG='true' Date='$Date' Header='' Id='$Id' Locker='' Log='$Log' Mcc='Mcc' PATCHLEVEL='5' RCSfile='$RCSfile' Revision='$Revision' SUBVERSION='3' Source='' State='' _a='.a' _exe='' _o='.o' afs='false' alignbytes='8' ansi2knr='' aphostname='' apiversion='5.005' ar='ar' archlib='/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf' archlibexp='/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf' archname='alpha-dec_osf' archobjs='' awk='awk' baserev='5.0' bash='' bin='/opt/dtv/perl/5.005_03/bin' binexp='/opt/dtv/perl/5.005_03/bin' bison='' byacc='byacc' byteorder='12345678' c='\c' castflags='0' cat='cat' cc='cc' cccdlflags=' ' ccdlflags=' -Wl\,-rpath\,/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf/CORE' ccflags='-std -fprm d -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C' ccsymbols='LANGUAGE_C=1 SYSTYPE_BSD=1 _LONGLONG=1 __ALPHA=1 __Alpha_AXP=1 __DATE__="Jul __DECC=1 __DECC_MODE_COMMON=1 __DECC_VER=50890011 __IEEE_FLOAT=1 __INITIAL_POINTER_SIZE=0 __LANGUAGE_C__=1 __PRAGMA_ENVIRONMENT=1 __TIME__="10​:57​:09" __X_FLOAT=0' cf_by='lobbesp' cf_email='lobbesp@​bambam.directv.com' cf_time='Mon Jul 19 10​:56​:06 PDT 1999' chgrp='' chmod='' chown='' clocktype='clock_t' comm='comm' compress='' config_arg0='Configure' config_arg1='-ds' config_arg2='-e' config_arg3='-Dprefix=/opt/dtv/perl/5.005_03' config_argc='3' config_args='-ds -e -Dprefix=/opt/dtv/perl/5.005_03' contains='grep' cp='cp' cpio='' cpp='cpp' cpp_stuff='42' cppccsymbols='_SYSTYPE_BSD=1 __alpha=1 __osf__=1 __unix__=1 unix=1' cppflags='-std -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C' cpplast='' cppminus='' cpprun='/usr/bin/cpp' cppstdin='cppstdin' cppsymbols='' cryptlib='' csh='csh' d_Gconvert='gcvt((x)\,(n)\,(b))' d_access='define' d_alarm='define' d_archlib='define' d_attribut='' d_bcmp='define' d_bcopy='define' d_bsd='' d_bsdgetpgrp='' d_bsdsetpgrp='define' d_bzero='define' d_casti32='' d_castneg='define' d_charvspr='' d_chown='define' d_chroot='define' d_chsize='' d_closedir='define' d_const='define' d_crypt='define' d_csh='define' d_cuserid='define' d_dbl_dig='define' d_difftime='define' d_dirnamlen='define' d_dlerror='define' d_dlopen='define' d_dlsymun='' d_dosuid='' d_dup2='define' d_endgrent='define' d_endhent='define' d_endnent='define' d_endpent='define' d_endpwent='define' d_endsent='define' d_eofnblk='define' d_eunice='' d_fchmod='define' d_fchown='define' d_fcntl='define' d_fd_macros='define' d_fd_set='define' d_fds_bits='define' d_fgetpos='define' d_flexfnam='define' d_flock='define' d_fork='define' d_fpathconf='define' d_fsetpos='define' d_fstatfs='define' d_fstatvfs='define' d_ftime='' d_getgrent='define' d_getgrps='define' d_gethbyaddr='define' d_gethbyname='define' d_gethent='define' d_gethname='' d_gethostprotos='define' d_getlogin='define' d_getmntent='' d_getnbyaddr='define' d_getnbyname='define' d_getnent='define' d_getnetprotos='define' d_getpbyname='define' d_getpbynumber='define' d_getpent='define' d_getpgid='define' d_getpgrp='define' d_getpgrp2='' d_getppid='define' d_getprior='define' d_getprotoprotos='define' d_getpwent='define' d_getsbyname='define' d_getsbyport='define' d_getsent='define' d_getservprotos='define' d_gettimeod='define' d_gnulibc='' d_grpasswd='define' d_hasmntopt='' d_htonl='define' d_index='' d_inetaton='define' d_isascii='define' d_killpg='define' d_lchown='define' d_link='define' d_locconv='define' d_lockf='define' d_longdbl='define' d_longlong='define' d_lstat='define' d_mblen='define' d_mbstowcs='define' d_mbtowc='define' d_memcmp='define' d_memcpy='define' d_memmove='define' d_memset='define' d_mkdir='define' d_mkfifo='define' d_mktime='define' d_msg='define' d_msgctl='define' d_msgget='define' d_msgrcv='define' d_msgsnd='define' d_mymalloc='define' d_nice='define' d_oldpthreads='' d_oldsock='' d_open3='define' d_pathconf='define' d_pause='define' d_phostname='' d_pipe='define' d_poll='define' d_portable='define' d_pthread_yield='' d_pthreads_created_joinable='' d_pwage='' d_pwchange='' d_pwclass='' d_pwcomment='define' d_pwexpire='' d_pwgecos='define' d_pwpasswd='define' d_pwquota='define' d_readdir='define' d_readlink='define' d_rename='define' d_rewinddir='define' d_rmdir='define' d_safebcpy='define' d_safemcpy='define' d_sanemcmp='define' d_sched_yield='define' d_seekdir='define' d_select='define' d_sem='define' d_semctl='define' d_semctl_semid_ds='define' d_semctl_semun='define' d_semget='define' d_semop='define' d_setegid='define' d_seteuid='define' d_setgrent='define' d_setgrps='define' d_sethent='define' d_setlinebuf='define' d_setlocale='define' d_setnent='define' d_setpent='define' d_setpgid='define' d_setpgrp='define' d_setpgrp2='' d_setprior='define' d_setpwent='define' d_setregid='define' d_setresgid='' d_setresuid='' d_setreuid='define' d_setrgid='define' d_setruid='define' d_setsent='define' d_setsid='define' d_setvbuf='define' d_sfio='' d_shm='define' d_shmat='define' d_shmatprototype='define' d_shmctl='define' d_shmdt='define' d_shmget='define' d_sigaction='define' d_sigsetjmp='define' d_socket='define' d_sockpair='define' d_statblks='define' d_statfsflags='define' d_stdio_cnt_lval='define' d_stdio_ptr_lval='define' d_stdiobase='define' d_stdstdio='define' d_strchr='define' d_strcoll='define' d_strctcpy='define' d_strerrm='strerror(e)' d_strerror='define' d_strtod='define' d_strtol='define' d_strtoul='define' d_strxfrm='define' d_suidsafe='' d_symlink='define' d_syscall='define' d_sysconf='define' d_sysernlst='' d_syserrlst='define' d_system='define' d_tcgetpgrp='define' d_tcsetpgrp='define' d_telldir='define' d_time='define' d_times='define' d_truncate='define' d_tzname='define' d_umask='define' d_uname='define' d_union_semun='' d_vfork='' d_void_closedir='' d_voidsig='define' d_voidtty='' d_volatile='define' d_vprintf='define' d_wait4='define' d_waitpid='define' d_wcstombs='define' d_wctomb='define' d_xenix='' date='date' db_hashtype='u_int32_t' db_prefixtype='size_t' defvoidused='15' direntrytype='struct dirent' dlext='so' dlsrc='dl_dlopen.xs' doublesize='8' dynamic_ext='B DB_File Data/Dumper Fcntl IO IPC/SysV NDBM_File ODBM_File Opcode POSIX SDBM_File Socket attrs re' eagain='EAGAIN' ebcdic='' echo='echo' egrep='egrep' emacs='' eunicefix='​:' exe_ext='' expr='expr' extensions='B DB_File Data/Dumper Fcntl IO IPC/SysV NDBM_File ODBM_File Opcode POSIX SDBM_File Socket attrs re Errno' find='find' firstmakefile='makefile' flex='' fpostype='fpos_t' freetype='void' full_ar='/usr/bin/ar' full_csh='/usr/bin/csh' full_sed='/usr/bin/sed' gccversion='' gidtype='gid_t' glibpth='/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib' grep='grep' groupcat='cat /etc/group' groupstype='gid_t' gzip='gzip' h_fcntl='false' h_sysfile='true' hint='recommended' hostcat='ypcat hosts' huge='' i_arpainet='define' i_bsdioctl='' i_db='define' i_dbm='define' i_dirent='define' i_dld='' i_dlfcn='define' i_fcntl='' i_float='define' i_gdbm='' i_grp='define' i_limits='define' i_locale='define' i_machcthreads='' i_malloc='define' i_math='define' i_memory='' i_mntent='' i_ndbm='define' i_netdb='define' i_neterrno='' i_niin='define' i_pthread='define' i_pwd='define' i_rpcsvcdbm='' i_sfio='' i_sgtty='' i_stdarg='define' i_stddef='define' i_stdlib='define' i_string='define' i_sysdir='define' i_sysfile='define' i_sysfilio='' i_sysin='' i_sysioctl='define' i_sysmount='define' i_sysndir='' i_sysparam='define' i_sysresrc='define' i_sysselct='define' i_syssockio='' i_sysstat='define' i_sysstatvfs='define' i_systime='define' i_systimek='' i_systimes='define' i_systypes='define' i_sysun='define' i_syswait='define' i_termio='' i_termios='define' i_time='' i_unistd='define' i_utime='define' i_values='define' i_varargs='' i_varhdr='stdarg.h' i_vfork='' ignore_versioned_solibs='' incpath='' inews='' installarchlib='/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf' installbin='/opt/dtv/perl/5.005_03/bin' installman1dir='/opt/dtv/perl/5.005_03/man/man1' installman3dir='/opt/dtv/perl/5.005_03/man/man3' installprivlib='/opt/dtv/perl/5.005_03/lib/5.00503' installscript='/opt/dtv/perl/5.005_03/bin' installsitearch='/opt/dtv/perl/5.005_03/lib/site_perl/5.005/alpha-dec_osf' installsitelib='/opt/dtv/perl/5.005_03/lib/site_perl/5.005' installusrbinperl='define' intsize='4' known_extensions='B DB_File Data/Dumper Fcntl GDBM_File IO IPC/SysV NDBM_File ODBM_File Opcode POSIX SDBM_File Socket Thread attrs re' ksh='' large='' ld='ld' lddlflags='-shared -expect_unresolved "*" -O4 -msym -s -L/usr/local/lib -L/opt/local/lib' ldflags=' -L/usr/local/lib -L/opt/local/lib' less='less' lib_ext='.a' libc='/usr/shlib/libc.so' libperl='libperl.so' libpth='/usr/local/lib /opt/local/lib /usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib' libs='-ldbm -ldb -lm' libswanted='sfio socket inet nsl nm gdbm dbm db malloc dld ld sun m cposix posix ndir dir crypt ucb BSD x' line='line' lint='' lkflags='' ln='ln' lns='/usr/bin/ln -s' locincpth='/usr/local/include /opt/local/include /usr/gnu/include /opt/gnu/include /usr/GNU/include /opt/GNU/include' loclibpth='/usr/local/lib /opt/local/lib /usr/gnu/lib /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib' longdblsize='8' longlongsize='8' longsize='8' lp='' lpr='' ls='ls' lseektype='off_t' mail='' mailx='' make='make' make_set_make='#' mallocobj='malloc.o' mallocsrc='malloc.c' malloctype='void *' man1dir='/opt/dtv/perl/5.005_03/man/man1' man1direxp='/opt/dtv/perl/5.005_03/man/man1' man1ext='1' man3dir='/opt/dtv/perl/5.005_03/man/man3' man3direxp='/opt/dtv/perl/5.005_03/man/man3' man3ext='3' medium='' mips='' mips_type='' mkdir='mkdir' models='none' modetype='mode_t' more='more' mv='' myarchname='alpha-dec_osf' mydomain='.directv.com' myhostname='bambam' myuname='osf1 bambam v4.0 1091 alpha ' n='' netdb_hlen_type='int' netdb_host_type='const char *' netdb_name_type='const char *' netdb_net_type='int' nm='nm' nm_opt='-p' nm_so_opt='' nonxs_ext='Errno' nroff='nroff' o_nonblock='O_NONBLOCK' obj_ext='.o' optimize='-O4' orderlib='false' osname='dec_osf' osvers='4.0' package='perl5' pager='/usr/bin/more' passcat='cat /etc/passwd' patchlevel='5' path_sep='​:' perl='perl' perladmin='lobbesp@​bambam.directv.com' perlpath='/opt/dtv/perl/5.005_03/bin/perl' pg='pg' phostname='hostname' pidtype='pid_t' plibpth='' pmake='' pr='' prefix='/opt/dtv/perl/5.005_03' prefixexp='/opt/dtv/perl/5.005_03' privlib='/opt/dtv/perl/5.005_03/lib/5.00503' privlibexp='/opt/dtv/perl/5.005_03/lib/5.00503' prototype='define' ptrsize='8' randbits='15' ranlib='​:' rd_nodata='-1' rm='rm' rmail='' runnm='true' scriptdir='/opt/dtv/perl/5.005_03/bin' scriptdirexp='/opt/dtv/perl/5.005_03/bin' sed='sed' selectminbits='32' selecttype='fd_set *' sendmail='sendmail' sh='/bin/sh' shar='' sharpbang='#!' shmattype='void *' shortsize='2' shrpenv='' shsharp='true' sig_name='ZERO HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM IOINT STOP TSTP CONT CHLD TTIN TTOU AIO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2 RESV RTMIN NUM34 NUM35 NUM36 NUM37 NUM38 NUM39 NUM40 NUM41 NUM42 NUM43 NUM44 NUM45 NUM46 NUM47 MAX IOT LOST URG CLD IO POLL PTY PWR RTMAX ' sig_name_init='"ZERO"\, "HUP"\, "INT"\, "QUIT"\, "ILL"\, "TRAP"\, "ABRT"\, "EMT"\, "FPE"\, "KILL"\, "BUS"\, "SEGV"\, "SYS"\, "PIPE"\, "ALRM"\, "TERM"\, "IOINT"\, "STOP"\, "TSTP"\, "CONT"\, "CHLD"\, "TTIN"\, "TTOU"\, "AIO"\, "XCPU"\, "XFSZ"\, "VTALRM"\, "PROF"\, "WINCH"\, "INFO"\, "USR1"\, "USR2"\, "RESV"\, "RTMIN"\, "NUM34"\, "NUM35"\, "NUM36"\, "NUM37"\, "NUM38"\, "NUM39"\, "NUM40"\, "NUM41"\, "NUM42"\, "NUM43"\, "NUM44"\, "NUM45"\, "NUM46"\, "NUM47"\, "MAX"\, "IOT"\, "LOST"\, "URG"\, "CLD"\, "IO"\, "POLL"\, "PTY"\, "PWR"\, "RTMAX"\, 0' sig_num='0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 6 6 16 20 23 23 23 29 48 ' sig_num_init='0\, 1\, 2\, 3\, 4\, 5\, 6\, 7\, 8\, 9\, 10\, 11\, 12\, 13\, 14\, 15\, 16\, 17\, 18\, 19\, 20\, 21\, 22\, 23\, 24\, 25\, 26\, 27\, 28\, 29\, 30\, 31\, 32\, 33\, 34\, 35\, 36\, 37\, 38\, 39\, 40\, 41\, 42\, 43\, 44\, 45\, 46\, 47\, 48\, 6\, 6\, 16\, 20\, 23\, 23\, 23\, 29\, 48\, 0' signal_t='void' sitearch='/opt/dtv/perl/5.005_03/lib/site_perl/5.005/alpha-dec_osf' sitearchexp='/opt/dtv/perl/5.005_03/lib/site_perl/5.005/alpha-dec_osf' sitelib='/opt/dtv/perl/5.005_03/lib/site_perl/5.005' sitelibexp='/opt/dtv/perl/5.005_03/lib/site_perl/5.005' sizetype='size_t' sleep='' smail='' small='' so='so' sockethdr='' socketlib='' sort='sort' spackage='Perl5' spitshell='cat' split='' src='.' ssizetype='ssize_t' startperl='#!/opt/dtv/perl/5.005_03/bin/perl' startsh='#!/bin/sh' static_ext=' ' stdchar='unsigned char' stdio_base='((fp)->_base)' stdio_bufsiz='((fp)->_cnt + (fp)->_ptr - (fp)->_base)' stdio_cnt='((fp)->_cnt)' stdio_filbuf='' stdio_ptr='((fp)->_ptr)' strings='/usr/include/string.h' submit='' subversion='3' sysman='/usr/man/man1' tail='' tar='' tbl='' tee='tee' test='test' timeincl='/usr/include/sys/time.h ' timetype='time_t' touch='touch' tr='tr' trnl='\n' troff='' uidtype='uid_t' uname='uname' uniq='uniq' usedl='define' usemymalloc='y' usenm='true' useopcode='true' useperlio='' useposix='true' usesfio='false' useshrplib='true' usethreads='' usevfork='false' usrinc='/usr/include' uuname='' version='5.00503' vi='' voidflags='15' xlibpth='/usr/lib/386 /lib/386' zcat='' zip='zip'

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Sun\, 19 Sep 1999 15​:30​:31 -0700\, Gurusamy Sarathy wrote (in part)​:

Sarathy> The mktime() call was added (change#1914) to fix the Sarathy> behavior of strftime() on linux\, and apparently\, Sarathy> alpha-dec_osf (!).

Sarathy> I'd say this needs to be controlled via the hints only Sarathy> for the platforms that need it.

I know of no vendor strftime() which doesn't need help to avoid SEGVs. I consider reverting to SEGVs to avoid a cosmetic bug to be very wrong. On the other hand\, mktime()'s docs (on the vendor releases I checked) are misleading\, and using it turns out to be very wrong as well. (The UNIX98 spec makes it rather explicit that mktime() was wrong\, but I didn't have that available when I submitted the patch which added the mktime() call.)

Sometime today I'll submit a patch which substitutes a 'minimktime' which only rationalizes the input values\, but which doesn't assume that you want something equivalent to a localtime() result. Since we already call init_tm()\, that should be OK for whatever timezone values you might really have wanted\, as well.

/spider

p5pRT commented 24 years ago

From @timbunce

On Thu\, Sep 23\, 1999 at 09​:55​:26AM -0400\, spider-perl@​Orb.Nashua.NH.US wrote​:

On Sun\, 19 Sep 1999 15​:30​:31 -0700\, Gurusamy Sarathy wrote (in part)​:

Sarathy> The mktime() call was added (change#1914) to fix the Sarathy> behavior of strftime() on linux\, and apparently\, Sarathy> alpha-dec_osf (!).

Sarathy> I'd say this needs to be controlled via the hints only Sarathy> for the platforms that need it.

I know of no vendor strftime() which doesn't need help to avoid SEGVs. I consider reverting to SEGVs to avoid a cosmetic bug to be very wrong. On the other hand\, mktime()'s docs (on the vendor releases I checked) are misleading\, and using it turns out to be very wrong as well. (The UNIX98 spec makes it rather explicit that mktime() was wrong\, but I didn't have that available when I submitted the patch which added the mktime() call.)

Sometime today I'll submit a patch which substitutes a 'minimktime' which only rationalizes the input values\, but which doesn't assume that you want something equivalent to a localtime() result. Since we already call init_tm()\, that should be OK for whatever timezone values you might really have wanted\, as well.

/spider

Random observation​: I've found that mktime() can be _very slow\, so ways of avoiding it would be handy.

Tim.

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Thu\, 23 Sep 1999 16​:14​:30 +0100\, Tim Bunce wrote (in part)​:

Tim> Random observation​: I've found that mktime() can be _very Tim> slow\, so ways of avoiding it would be handy.

The mini-mktime won't be doing anything with tzset() or its equivalent\, so there should be no problem there. In fact\, it'll make neither library calls nor syscalls. All it does is straight in-line integer arithmetic. The algorithm it uses is rather obscure\, but it works\, and needs (depending on how you look at it) 0 or 1 table lookups. I'd already have sent the patch\, but I have my day job's work to get done today\, too. ;=}

/spider

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Hi\,

Just to clarify things a bit\, I believe taking out mktime in this case is the apropriate move replacing that with this "minimktime" is probably the best move *as long* as it doesn't change data or return bogus data (as it does with mktime on OSF1 and most likely Solaris if my test c program emulates perl bahavior properly).

I'd personally have my program SEGV if I pass improper data to strftime than give me bogus data. Even better would be to have Perl do boundary checking as I believe you're proposing with "minimktime" to trap improper data and return a null string instead of a time that is incorrect. I just want to be sure that this fix doesn't cause Perl to generate dates that are skewed by an hour. I can't afford to have bogus dates in my database and trying to fix a 250GB database that has *some* of it's times shifted by 1 hour is *painful*.

Maybe we should add a test to POSIX (not sure how portable this is but according to Sun man pages should be X/Open Portability Guide\, Issue 4 compatible)​:

  use POSIX;   @​t=qw(37 57 0 3 8 99 5 245 0); # a time which mktime could skew   $tstr="1999 09 03 00​:57​:37"; # what strftime should give us   $pstr=&POSIX​::strftime("%Y %m %d %H​:%M​:%S"\, @​t);   print (($tstr eq $pstr) ? "ok" : "not ok"\, " 99\n");

Phil

On Thu\, 23 Sep 1999 09​:55​:26 -0400\, spider-perl@​Orb.Nashua.NH.US said​:

spider> On Sun\, 19 Sep 1999 15​:30​:31 -0700\, Gurusamy Sarathy wrote (in spider> part)​: Sarathy> The mktime() call was added (change#1914) to fix the behavior Sarathy> of strftime() on linux\, and apparently\, alpha-dec_osf (!).

Sarathy> I'd say this needs to be controlled via the hints only for Sarathy> the platforms that need it.

spider> I know of no vendor strftime() which doesn't need help to spider> avoid SEGVs. I consider reverting to SEGVs to avoid a spider> cosmetic bug to be very wrong. On the other hand\, mktime()'s spider> docs (on the vendor releases I checked) are misleading\, and spider> using it turns out to be very wrong as well. (The UNIX98 spec spider> makes it rather explicit that mktime() was wrong\, but I didn't spider> have that available when I submitted the patch which added the spider> mktime() call.)

spider> Sometime today I'll submit a patch which substitutes a spider> 'minimktime' which only rationalizes the input values\, but spider> which doesn't assume that you want something equivalent to a spider> localtime() result. Since we already call init_tm()\, that spider> should be OK for whatever timezone values you might really spider> have wanted\, as well.

spider> /spider

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Thu\, 23 Sep 1999 09​:55​:26 -0400\, I wrote (in part)​:

sb> Sometime today I'll submit a patch which substitutes a sb> 'minimktime' which only rationalizes the input values\, but sb> which doesn't assume that you want something equivalent to a sb> localtime() result.

Here it is.

/spider

Inline Patch ```diff --- ext/POSIX/POSIX.pod.DIST Tue Jul 20 13:17:56 1999 +++ ext/POSIX/POSIX.pod Thu Sep 23 17:47:51 1999 @@ -1024,7 +1024,8 @@ If you want your code to be portable, yo should use only the conversion specifiers defined by the ANSI C standard. These are C. The given arguments are made consistent -by calling C before calling your system's C function. +as though by calling C before calling your system's +C function, except that the C value is not affected. The string for Tuesday, December 12, 1995. --- ext/POSIX/POSIX.xs.DIST Fri Aug 20 11:51:30 1999 +++ ext/POSIX/POSIX.xs Thu Sep 23 15:39:30 1999 @@ -332,6 +332,196 @@ init_tm(struct tm *ptm) /* see mktime, # define init_tm(ptm) #endif +/* + * mini_mktime - normalise struct tm values without the localtime() + * semantics (and overhead) of mktime(). + */ +static void +mini_mktime(struct tm *ptm) +{ + int yearday; + int secs; + int month, mday, year, jday; + int odd_cent, odd_year; + +#define DAYS_PER_YEAR 365 +#define DAYS_PER_QYEAR (4*DAYS_PER_YEAR+1) +#define DAYS_PER_CENT (25*DAYS_PER_QYEAR-1) +#define DAYS_PER_QCENT (4*DAYS_PER_CENT+1) +#define SECS_PER_HOUR (60*60) +#define SECS_PER_DAY (24*SECS_PER_HOUR) +/* parentheses deliberately absent on these two, otherwise they don't work */ +#define MONTH_TO_DAYS 153/5 +#define DAYS_TO_MONTH 5/153 +/* offset to bias by March (month 4) 1st between month/mday & year finding */ +#define YEAR_ADJUST (4*MONTH_TO_DAYS+1) +/* as used here, the algorithm leaves Sunday as day 1 unless we adjust it */ +#define WEEKDAY_BIAS 6 /* (1+6)%7 makes Sunday 0 again */ + +/* + * Year/day algorithm notes: + * + * With a suitable offset for numeric value of the month, one can find + * an offset into the year by considering months to have 30.6 (153/5) days, + * using integer arithmetic (i.e., with truncation). To avoid too much + * messing about with leap days, we consider January and February to be + * the 13th and 14th month of the previous year. After that transformation, + * we need the month index we use to be high by 1 from 'normal human' usage, + * so the month index values we use run from 4 through 15. + * + * Given that, and the rules for the Gregorian calendar (leap years are those + * divisible by 4 unless also divisible by 100, when they must be divisible + * by 400 instead), we can simply calculate the number of days since some + * arbitrary 'beginning of time' by futzing with the (adjusted) year number, + * the days we derive from our month index, and adding in the day of the + * month. The value used here is not adjusted for the actual origin which + * it normally would use (1 January A.D. 1), since we're not exposing it. + * We're only building the value so we can turn around and get the + * normalised values for the year, month, day-of-month, and day-of-year. + * + * For going backward, we need to bias the value we're using so that we find + * the right year value. (Basically, we don't want the contribution of + * March 1st to the number to apply while deriving the year). Having done + * that, we 'count up' the contribution to the year number by accounting for + * full quadracenturies (400-year periods) with their extra leap days, plus + * the contribution from full centuries (to avoid counting in the lost leap + * days), plus the contribution from full quad-years (to count in the normal + * leap days), plus the leftover contribution from any non-leap years. + * At this point, if we were working with an actual leap day, we'll have 0 + * days left over. This is also true for March 1st, however. So, we have + * to special-case that result, and (earlier) keep track of the 'odd' + * century and year contributions. If we got 4 extra centuries in a qcent, + * or 4 extra years in a qyear, then it's a leap day and we call it 29 Feb. + * Otherwise, we add back in the earlier bias we removed (the 123 from + * figuring in March 1st), find the month index (integer division by 30.6), + * and the remainder is the day-of-month. We then have to convert back to + * 'real' months (including fixing January and February from being 14/15 in + * the previous year to being in the proper year). After that, to get + * tm_yday, we work with the normalised year and get a new yearday value for + * January 1st, which we subtract from the yearday value we had earlier, + * representing the date we've re-built. This is done from January 1 + * because tm_yday is 0-origin. + * + * Since POSIX time routines are only guaranteed to work for times since the + * UNIX epoch (00:00:00 1 Jan 1970 UTC), the fact that this algorithm + * applies Gregorian calendar rules even to dates before the 16th century + * doesn't bother me. Besides, you'd need cultural context for a given + * date to know whether it was Julian or Gregorian calendar, and that's + * outside the scope for this routine. Since we convert back based on the + * same rules we used to build the yearday, you'll only get strange results + * for input which needed normalising, or for the 'odd' century years which + * were leap years in the Julian calander but not in the Gregorian one. + * I can live with that. + * + * This algorithm also fails to handle years before A.D. 1 gracefully, but + * that's still outside the scope for POSIX time manipulation, so I don't + * care. + */ + + year = 1900 + ptm->tm_year; + month = ptm->tm_mon; + mday = ptm->tm_mday; + /* allow given yday with no month & mday to dominate the result */ + if (ptm->tm_yday >= 0 && mday <= 0 && month <= 0) { + month = 0; + mday = 0; + jday = 1 + ptm->tm_yday; + } + else { + jday = 0; + } + if (month >= 2) + month+=2; + else + month+=14, year--; + yearday = DAYS_PER_YEAR * year + year/4 - year/100 + year/400; + yearday += month*MONTH_TO_DAYS + mday + jday; + /* + * Note that we don't know when leap-seconds were or will be, + * so we have to trust the user if we get something which looks + * like a sensible leap-second. Wild values for seconds will + * be rationalised, however. + */ + if ((unsigned) ptm->tm_sec <= 60) { + secs = 0; + } + else { + secs = ptm->tm_sec; + ptm->tm_sec = 0; + } + secs += 60 * ptm->tm_min; + secs += SECS_PER_HOUR * ptm->tm_hour; + if (secs < 0) { + if (secs-(secs/SECS_PER_DAY*SECS_PER_DAY) < 0) { + /* got negative remainder, but need positive time */ + /* back off an extra day to compensate */ + yearday += (secs/SECS_PER_DAY)-1; + secs -= SECS_PER_DAY * (secs/SECS_PER_DAY - 1); + } + else { + yearday += (secs/SECS_PER_DAY); + secs -= SECS_PER_DAY * (secs/SECS_PER_DAY); + } + } + else if (secs >= SECS_PER_DAY) { + yearday += (secs/SECS_PER_DAY); + secs %= SECS_PER_DAY; + } + ptm->tm_hour = secs/SECS_PER_HOUR; + secs %= SECS_PER_HOUR; + ptm->tm_min = secs/60; + secs %= 60; + ptm->tm_sec += secs; + /* done with time of day effects */ + /* + * The algorithm for yearday has (so far) left it high by 428. + * To avoid mistaking a legitimate Feb 29 as Mar 1, we need to + * bias it by 123 while trying to figure out what year it + * really represents. Even with this tweak, the reverse + * translation fails for years before A.D. 0001. + * It would still fail for Feb 29, but we catch that one below. + */ + jday = yearday; /* save for later fixup vis-a-vis Jan 1 */ + yearday -= YEAR_ADJUST; + year = (yearday / DAYS_PER_QCENT) * 400; + yearday %= DAYS_PER_QCENT; + odd_cent = yearday / DAYS_PER_CENT; + year += odd_cent * 100; + yearday %= DAYS_PER_CENT; + year += (yearday / DAYS_PER_QYEAR) * 4; + yearday %= DAYS_PER_QYEAR; + odd_year = yearday / DAYS_PER_YEAR; + year += odd_year; + yearday %= DAYS_PER_YEAR; + if (!yearday && (odd_cent==4 || odd_year==4)) { /* catch Feb 29 */ + month = 1; + yearday = 29; + } + else { + yearday += YEAR_ADJUST; /* recover March 1st crock */ + month = yearday*DAYS_TO_MONTH; + yearday -= month*MONTH_TO_DAYS; + /* recover other leap-year adjustment */ + if (month > 13) { + month-=14; + year++; + } + else { + month-=2; + } + } + ptm->tm_year = year - 1900; + ptm->tm_mon = month; + ptm->tm_mday = yearday; + /* re-build yearday based on Jan 1 to get tm_yday */ + year--; + yearday = year*DAYS_PER_YEAR + year/4 - year/100 + year/400; + yearday += 14*MONTH_TO_DAYS + 1; + ptm->tm_yday = jday - yearday; + /* fix tm_wday if not overridden by caller */ + if ((unsigned)ptm->tm_wday > 6) + ptm->tm_wday = (jday + WEEKDAY_BIAS) % 7; +} #ifdef HAS_LONG_DOUBLE # if LONG_DOUBLESIZE > DOUBLESIZE @@ -3650,7 +3840,7 @@ strftime(fmt, sec, min, hour, mday, mon, mytm.tm_wday = wday; mytm.tm_yday = yday; mytm.tm_isdst = isdst; - (void) mktime(&mytm); + mini_mktime(&mytm); len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm); /* ** The following is needed to handle to the situation where --- t/lib/posix.t.DIST Tue Jul 20 13:18:13 1999 +++ t/lib/posix.t Thu Sep 23 17:00:43 1999 @@ -14,7 +14,7 @@ use strict subs; $| = 1; -print "1..18\n"; +print "1..26\n"; $Is_W32 = $^O eq 'MSWin32'; @@ -94,6 +94,31 @@ # -DSTRUCT_TM_HASZONE to your cflags when compiling ext/POSIX/POSIX.c. # See ext/POSIX/hints/sunos_4.pl and ext/POSIX/hints/linux.pl print POSIX::strftime("ok 18 # %H:%M, on %D\n", localtime()); + +# If that worked, validate the mini_mktime() routine's normalisation of +# input fields to strftime(). +sub try_strftime { + my $num = shift; + my $expect = shift; + my $got = POSIX::strftime("%a %b %d %H:%M:%S %Y %j", @_); + if ($got eq $expect) { + print "ok $num\n"; + } + else { + print "# expected: $expect\n# got: $got\nnot ok $num\n"; + } +} + +$lc = &POSIX::setlocale(&POSIX::LC_TIME, 'C') if $Config{d_setlocale}; +try_strftime(19, "Wed Feb 28 00:00:00 1996 059", 0,0,0, 28,1,96); +try_strftime(20, "Thu Feb 29 00:00:60 1996 060", 60,0,-24, 30,1,96); +try_strftime(21, "Fri Mar 01 00:00:00 1996 061", 0,0,-24, 31,1,96); +try_strftime(22, "Sun Feb 28 00:00:00 1999 059", 0,0,0, 28,1,99); +try_strftime(23, "Mon Mar 01 00:00:00 1999 060", 0,0,24, 28,1,99); +try_strftime(24, "Mon Feb 28 00:00:00 2000 059", 0,0,0, 28,1,100); +try_strftime(25, "Tue Feb 29 00:00:00 2000 060", 0,0,0, 0,2,100); +try_strftime(26, "Wed Mar 01 00:00:00 2000 061", 0,0,0, 1,2,100); +&POSIX::setlocale(&POSIX::LC_TIME, $lc) if $Config{d_setlocale}; $| = 0; # The following line assumes buffered output, which may be not true with EMX: ```
p5pRT commented 23 years ago

From @gsar

On Mon\, 13 Sep 1999 14​:51​:17 PDT\, Phil Lobbes wrote​:

I believe I have found a bug in Perl > 5.004_04 (possibly only Perl 5.005+) using POSIX​::strftime. I've been using POSIX​::strftime to print out formatted times obtained through Perl's gmtime call. Everything is fine when not going through strftime (i.e. scalar(gmtime)) or using Perl 5.004_01-5.004_04\, but when format the times through strftime 5.005_03 it seems to get confused about daylight savings times even though I'm passing it a full array from gmtime.

The problem seems to be that strftime C module calls mktime() which sets (or actually improperly re-sets) "isdst" in the data structure I passed to it causing time to be 1 hour off with data structures that would land within my DST period. I think stftime shouldn't be calling mktime but I'm not 100% sure. This didn't used to happen (perl 5.004_01-03 anyway) and with 5.005 it breaks my database application.

Should I not use strftime? Is strftime supposed to call mktime? It seems a bit dangerous to assume the programmer actually wants this behavior but maybe I'm missing something here.

The *real* world where I've run into problems\, gmtime sets tm_isdst to 0 appropriately\, but using POSIX​::strftime make things look like daylight savings time apparently!

% /opt/dtv/bin/perl -e '@​tmp=gmtime;use POSIX; print scalar(gmtime)\, " or (@​tmp)\n"\,POSIX​::strftime("%Y %m %d %H​:%M​:%S"\, @​tmp)\, "\n"' ; Fri Sep 3 00​:46​:11 1999 or (11 46 0 3 8 99 5 245 0) 1999 09 03 01​:46​:11

The mktime() call was added (change#1914) to fix the behavior of strftime() on linux\, and apparently\, alpha-dec_osf (!). See​:

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-09/msg01660.html http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-11/msg00291.html http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-11/msg00864.html

I'd say this needs to be controlled via the hints only for the platforms that need it.

I've checked in the attached change. Someone will need to add a hints file for dec_osf after ascertaining whether calling mktime() there causes more problems than it solves.

Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration​: Platform​: osname=dec_osf\, osvers=4.0\, archname=alpha-dec_osf uname='osf1 bambam v4.0 1091 alpha ' hint=recommended\, useposix=true\, d_sigaction=define usethreads=undef useperlio=undef d_sfio=undef Compiler​: cc='cc'\, optimize='-O4'\, gccversion= cppflags='-std -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C' ccflags ='-std -fprm d -ieee -D_INTRINSICS -I/usr/local/include -I/opt/local/include -DLANGUAGE_C' stdchar='unsigned char'\, d_stdstdio=define\, usevfork=false intsize=4\, longsize=8\, ptrsize=8\, doublesize=8 d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=8 alignbytes=8\, usemymalloc=y\, prototype=define Linker and Libraries​: ld='ld'\, ldflags =' -L/usr/local/lib -L/opt/local/lib' libpth=/usr/local/lib /opt/local/lib /usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib libs=-ldbm -ldb -lm libc=/usr/shlib/libc.so\, so=so\, useshrplib=true\, libperl=libperl.so Dynamic Linking​: dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags=' -Wl\,-rpath\,/opt/dtv/perl/5.005_03/lib/5.00503/alpha-dec_osf/CORE' cccdlflags=' '\, lddlflags='-shared -expect_unresolved "*" -O4 -msym -s -L/usr/local/lib -L/opt/local/lib'

Sarathy gsar@​activestate.com

Inline Patch ```diff -----------------------------------8<----------------------------------- Change 4196 by gsar@auger on 1999/09/19 22:14:29 control change#1914 via hints (causes problems on some platforms) Affected files ... ... //depot/perl/ext/POSIX/POSIX.pod#12 edit ... //depot/perl/ext/POSIX/POSIX.xs#49 edit ... //depot/perl/ext/POSIX/hints/linux.pl#3 edit Differences ... ==== //depot/perl/ext/POSIX/POSIX.pod#12 (text) ==== Index: perl/ext/POSIX/POSIX.pod --- perl/ext/POSIX/POSIX.pod.~1~ Sun Sep 19 15:14:34 1999 +++ perl/ext/POSIX/POSIX.pod Sun Sep 19 15:14:34 1999 @@ -1023,7 +1023,7 @@ If you want your code to be portable, your format (C) argument should use only the conversion specifiers defined by the ANSI C standard. These are C. -The given arguments are made consistent +On platforms that need it, the given arguments are made consistent by calling C before calling your system's C function. The string for Tuesday, December 12, 1995. ==== //depot/perl/ext/POSIX/POSIX.xs#49 (text) ==== Index: perl/ext/POSIX/POSIX.xs --- perl/ext/POSIX/POSIX.xs.~1~ Sun Sep 19 15:14:34 1999 +++ perl/ext/POSIX/POSIX.xs Sun Sep 19 15:14:34 1999 @@ -3652,7 +3652,9 @@ mytm.tm_wday = wday; mytm.tm_yday = yday; mytm.tm_isdst = isdst; +#if defined(HINT_STRFTIME_NEEDS_MKTIME) (void) mktime(&mytm); +#endif len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm); /* ** The following is needed to handle to the situation where ==== //depot/perl/ext/POSIX/hints/linux.pl#3 (text) ==== Index: perl/ext/POSIX/hints/linux.pl --- perl/ext/POSIX/hints/linux.pl.~1~ Sun Sep 19 15:14:34 1999 +++ perl/ext/POSIX/hints/linux.pl Sun Sep 19 15:14:34 1999 @@ -2,4 +2,6 @@ # Thanks to Bart Schuller # See Message-ID: <19971009002636.50729@tanglefoot> # XXX A Configure test is needed. -$self->{CCFLAGS} = $Config{ccflags} . ' -DSTRUCT_TM_HASZONE -DHINT_SC_EXIST' ; +$self->{CCFLAGS} = $Config{ccflags} + . ' -DHINT_STRFTIME_NEEDS_MKTIME' + . ' -DSTRUCT_TM_HASZONE -DHINT_SC_EXIST' ; End of Patch. ```