update the octal situation in perlfaq4.pod
[p5sagit/p5-mst-13.2.git] / pod / perlfaq4.pod
index 8c570c2..714bc08 100644 (file)
@@ -39,6 +39,11 @@ arbitrary-precision decimal numbers with the Math::BigFloat module
 (part of the standard Perl distribution), but mathematical operations
 are consequently slower.
 
+If precision is important, such as when dealing with money, it's good
+to work with integers and then divide at the last possible moment.
+For example, work in pennies (1995) instead of dollars and cents
+(19.95) and divide by 100 at the end.
+
 To get rid of the superfluous digits, just use a format (eg,
 C<printf("%.2f", 19.95)>) to get the required precision.
 See L<perlop/"Floating-point Arithmetic">.  
@@ -46,19 +51,36 @@ See L<perlop/"Floating-point Arithmetic">.
 =head2 Why isn't my octal data interpreted correctly?
 
 Perl only understands octal and hex numbers as such when they occur
-as literals in your program.  If they are read in from somewhere and
-assigned, no automatic conversion takes place.  You must explicitly
-use oct() or hex() if you want the values converted.  oct() interprets
+as literals in your program.  Octal literals in perl must start with 
+a leading "0" and hexadecimal literals must start with a leading "0x".
+If they are read in from somewhere and assigned, no automatic 
+conversion takes place.  You must explicitly use oct() or hex() if you 
+want the values converted to decimal.  oct() interprets
 both hex ("0x350") numbers and octal ones ("0350" or even without the
 leading "0", like "377"), while hex() only converts hexadecimal ones,
 with or without a leading "0x", like "0x255", "3A", "ff", or "deadbeef".
+The inverse mapping from decimal to octal can be done with either the
+"%o" or "%O" sprintf() formats.  To get from decimal to hex try either 
+the "%x" or the "%X" formats to sprintf().
 
 This problem shows up most often when people try using chmod(), mkdir(),
-umask(), or sysopen(), which all want permissions in octal.
+umask(), or sysopen(), which by widespread tradition typically take 
+permissions in octal.
 
-    chmod(644,  $file);        # WRONG -- perl -w catches this
+    chmod(644,  $file);        # WRONG
     chmod(0644, $file);        # right
 
+Note the mistake in the first line was specifying the decimal literal 
+644, rather than the intended octal literal 0644.  The problem can
+be seen with:
+
+    printf(0"%o",644); # prints 01204
+
+Surely you had not intended C<chmod(01204, $file);> - did you?  If you
+want to use numeric literals as arguments to chmod() et al. then please
+try to express them as octal constants, that is with a leading zero and 
+with the following digits restricted to the set 0..7.
+
 =head2 Does Perl have a round() function?  What about ceil() and floor()?  Trig functions?
 
 Remember that int() merely truncates toward 0.  For rounding to a
@@ -227,22 +249,22 @@ L<perlfunc/"localtime">):
 
     $day_of_year = (localtime(time()))[7];
 
-or more legibly (in 5.004 or higher):
+or more legibly (in 5.7.1 or higher):
 
-    use Time::localtime;
-    $day_of_year = localtime(time())->yday;
+    use Time::Piece;
+    $day_of_year = localtime->day_of_year();
 
-You can find the week of the year by dividing this by 7:
+You can find the week of the year by using Time::Piece's strftime():
 
-    $week_of_year = int($day_of_year / 7);
+    $week_of_year = localtime->strftime("%U");
+    $iso_week = localtime->strftime("%V");
 
-Of course, this believes that weeks start at zero.  The Date::Calc
-module from CPAN has a lot of date calculation functions, including
-day of the year, week of the year, and so on.   Note that not
-all businesses consider ``week 1'' to be the same; for example,
-American businesses often consider the first week with a Monday
-in it to be Work Week #1, despite ISO 8601, which considers
-WW1 to be the first week with a Thursday in it.
+The difference between %U and %V is that %U assumes that the first day
+of week 1 is the first Sunday of the year, whereas ISO 8601:1988 uses
+the first week that has at least 4 days in the current year, and with
+Monday as the first day of the week. You can also use %W, which will
+return the week of the year with Monday as the first day of week 1. See
+your strftime(3) man page for more details.
 
 =head2 How do I find the current century or millennium?
 
@@ -273,6 +295,10 @@ your dates, then you should probably use either of the Date::Manip and
 Date::Calc modules from CPAN before you go hacking up your own parsing
 routine to handle arbitrary date formats.
 
+Also note that the core module Time::Piece overloads the addition and
+subtraction operators to provide date calculation options. See
+L<Time::Piece/Date Calculations>.
+
 =head2 How can I take a string and turn it into epoch seconds?
 
 If it's a regular enough string that it always has the same format,
@@ -282,24 +308,30 @@ and Date::Manip modules from CPAN.
 
 =head2 How can I find the Julian Day?
 
-Use the Time::JulianDay module (part of the Time-modules bundle
-available from CPAN.)
+Use Time::Piece as follows:
+
+    use Time::Piece;
+    my $julian_day = localtime->julian_day;
+    my $mjd = localtime->mjd; # modified julian day
 
-Before you immerse yourself too deeply in this, be sure to verify that it
-is the I<Julian> Day you really want.  Are you really just interested in
-a way of getting serial days so that they can do date arithmetic?  If you
+Before you immerse yourself too deeply in this, be sure to verify that
+it is the I<Julian> Day you really want.  Are you interested in a way
+of getting serial days so that you just can tell how many days they
+are apart or so that you can do also other date arithmetic?  If you
 are interested in performing date arithmetic, this can be done using
-either Date::Manip or Date::Calc, without converting to Julian Day first.
-
-There is too much confusion on this issue to cover in this FAQ, but the
-term is applied (correctly) to a calendar now supplanted by the Gregorian
-Calendar, with the Julian Calendar failing to adjust properly for leap
-years on centennial years (among other annoyances).  The term is also used
-(incorrectly) to mean: [1] days in the Gregorian Calendar; and [2] days
-since a particular starting time or `epoch', usually 1970 in the Unix
-world and 1980 in the MS-DOS/Windows world.  If you find that it is not
-the first meaning that you really want, then check out the Date::Manip
-and Date::Calc modules.  (Thanks to David Cassell for most of this text.)
+Time::Piece (standard module since Perl 5.8), or by modules
+Date::Manip or Date::Calc.
+
+There is too many details and much confusion on this issue to cover in
+this FAQ, but the term is applied (correctly) to a calendar now
+supplanted by the Gregorian Calendar, with the Julian Calendar failing
+to adjust properly for leap years on centennial years (among other
+annoyances).  The term is also used (incorrectly) to mean: [1] days in
+the Gregorian Calendar; and [2] days since a particular starting time
+or `epoch', usually 1970 in the Unix world and 1980 in the
+MS-DOS/Windows world.  If you find that it is not the first meaning
+that you really want, then check out the Date::Manip and Date::Calc
+modules.  (Thanks to David Cassell for most of this text.)
 
 =head2 How do I find yesterday's date?
 
@@ -311,6 +343,14 @@ epoch.  Take twenty-four hours off that:
 Then you can pass this to C<localtime()> and get the individual year,
 month, day, hour, minute, seconds values.
 
+Alternatively, you can use Time::Piece to subtract a day from the value
+returned from C<localtime()>:
+
+    use Time::Piece;
+    use Time::Seconds; # imports seconds constants, like ONE_DAY
+    my $today = localtime();
+    my $yesterday = $today - ONE_DAY;
+
 Note very carefully that the code above assumes that your days are
 twenty-four hours each.  For most people, there are two days a year
 when they aren't: the switch to and from summer time throws this off.
@@ -446,7 +486,8 @@ parser.
 If you are serious about writing a parser, there are a number of
 modules or oddities that will make your life a lot easier.  There are
 the CPAN modules Parse::RecDescent, Parse::Yapp, and Text::Balanced;
-and the byacc program.
+and the byacc program.   Starting from perl 5.8 the Text::Balanced
+is part of the standard distribution.
 
 One simple destructive, inside-out approach that you might try is to
 pull out the smallest nesting parts one at a time:
@@ -994,7 +1035,7 @@ Like (d), but @in contains only small positive integers:
 
 But perhaps you should have been using a hash all along, eh?
 
-=head2 How can I tell whether a list or array contains a certain element?
+=head2 How can I tell whether a certain element is contained in a list or array?
 
 Hearing the word "in" is an I<in>dication that you probably should have
 used a hash, not a list or array, to store your data.  Hashes are
@@ -1762,7 +1803,8 @@ respectively.
 
 For some specific applications, you can use one of the DBM modules.
 See L<AnyDBM_File>.  More generically, you should consult the FreezeThaw,
-Storable, or Class::Eroot modules from CPAN.  Here's one example using
+Storable, or Class::Eroot modules from CPAN.  Starting from Perl 5.8
+Storable is part of the standard distribution.  Here's one example using
 Storable's C<store> and C<retrieve> functions:
 
     use Storable;