Generating Day of Week in Pure Perl

Discussion in 'Perl Misc' started by rev, Dec 1, 2003.

  1. rev

    rev Guest

    I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    to get the day of the week from this (Monday). But, this is occurring
    on my hosting vendor so whatever does it needs to be pure Perl.

    I cannot use the POSIX package.
    I cannot install any package that requires compilation.
    Anything I use needs to work through the year 2100.

    Any suggestions on this?

    -rev
    rev, Dec 1, 2003
    #1
    1. Advertising

  2. It was a dark and stormy night, and rev managed to scribble:

    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > to get the day of the week from this (Monday). But, this is occurring
    > on my hosting vendor so whatever does it needs to be pure Perl.
    >
    > I cannot use the POSIX package.
    > I cannot install any package that requires compilation.
    > Anything I use needs to work through the year 2100.
    >
    > Any suggestions on this?
    >
    > -rev



    Here's a quick solution (works for years 1900-2100) :

    The two routines below work out days between dates and days of the week
    Q.How may days between 15-jan-1999 and 5-jul-2003
    A. date_ymd("20030715") - date_ymd("19990105");
    Q . What day is 21-mar-2003.
    A. weekday(date_ymd("20030321"));

    sub date_ymd { my($year)=substr($_[0],0,4); my($month)=substr($_[0],4,2);
    my($day)=substr($_[0],6,2); my(@months) = (0,31,59,90,120,151,181,212,243,273,304,334);
    return $year*365+int(($year-1)/4)+$months[$month-1]+$day($year%4==0&&$month>=3?1:0) +5; }

    sub weekday { my ($offset)=@_; my(@wday) = ( "Sun", "Mon", "Tue", "Wed", "Thu",
    "Fri", "Sat" );

    return $wday[$offset%7]; }


    gtoomey
    Gregory Toomey, Dec 1, 2003
    #2
    1. Advertising

  3. rev wrote:
    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I
    > need to get the day of the week from this (Monday). But, this is
    > occurring on my hosting vendor so whatever does it needs to be pure
    > Perl.
    >
    > I cannot use the POSIX package.
    > I cannot install any package that requires compilation.
    > Anything I use needs to work through the year 2100.


    This solution makes use of the pure Perl (and standard) module
    Time::Local and the localtime() function:

    sub day {
    use Time::Local;
    my @t = split /\//, shift;
    my $time = timelocal(0,0,0,$t[1],$t[0]-1,$t[2]-1900);
    my @days = qw/Sunday Monday Tuesday
    Wednesday Thursday Friday Saturday/;
    return $days[ (localtime $time)[6] ];
    }

    my $date = '12/01/2003';
    print day($date);

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Dec 1, 2003
    #3
  4. rev

    J. Gleixner Guest

    rev wrote:
    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > to get the day of the week from this (Monday). But, this is occurring
    > on my hosting vendor so whatever does it needs to be pure Perl.
    >
    > I cannot use the POSIX package.
    > I cannot install any package that requires compilation.
    > Anything I use needs to work through the year 2100.
    >
    > Any suggestions on this?


    Find Epoch seconds, using Time::Local

    perldoc Time::Local

    Then use localtime() to find the day of the week

    perldoc -f localtime

    Then you should easily be able to come up with Monday-Sunday by using
    that as an index on a simple array.
    J. Gleixner, Dec 1, 2003
    #4
  5. * rev <>:

    > I cannot use the POSIX package.


    Why?


    cheers,
    --
    Iain.
    Iain Truskett, Dec 2, 2003
    #5
  6. rev

    Tom Guest

    "rev" <> wrote in message
    news:7qOyb.28801$...
    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > to get the day of the week from this (Monday). But, this is occurring
    > on my hosting vendor so whatever does it needs to be pure Perl.


    OS?

    Windows XP:

    $date = `date /t`;
    chomp($date);
    ($weekday,$tmp1) = split (/\s+/, $date);

    UNIX(Linux):

    $date = `date`;
    # $date = "Sun Aug 31 5:12:57 PDT 2003"; # < Sample
    chomp($date);
    ($weekday,$month,$day,$ctime,$timezone,$year) = split (/\s+/, $date);
    Tom, Dec 2, 2003
    #6
  7. rev

    Tore Aursand Guest

    On Mon, 01 Dec 2003 22:40:51 -0800, Tom wrote:
    >> I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    >> to get the day of the week from this (Monday). But, this is occurring
    >> on my hosting vendor so whatever does it needs to be pure Perl.


    > OS?


    The OP was talking about "pure Perl". Why drag the OS into this case?

    > Windows XP:
    >
    > $date = `date /t`;
    > chomp($date);
    > ($weekday,$tmp1) = split (/\s+/, $date);
    >
    > UNIX(Linux):
    >
    > $date = `date`;
    > # $date = "Sun Aug 31 5:12:57 PDT 2003"; # < Sample
    > chomp($date);
    > ($weekday,$month,$day,$ctime,$timezone,$year) = split (/\s+/, $date);


    This is hardly "pure Perl".


    --
    Tore Aursand <>
    "A car is not the only thing that can be recalled by its maker." --
    Unknown
    Tore Aursand, Dec 2, 2003
    #7
  8. rev

    Tintin Guest

    "rev" <> wrote in message
    news:7qOyb.28801$...
    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > to get the day of the week from this (Monday). But, this is occurring
    > on my hosting vendor so whatever does it needs to be pure Perl.
    >
    > I cannot use the POSIX package.


    Why not? It provides a very simple and portable solution.
    Tintin, Dec 3, 2003
    #8
  9. rev

    Bart Lateur Guest

    Iain Truskett wrote:

    >* rev <>:
    >
    >> I cannot use the POSIX package.

    >
    >Why?


    For the same reason he can't use any other module. The ISP probably
    deleted it and isn't willing to install it again.

    --
    Bart.
    Bart Lateur, Dec 4, 2003
    #9
  10. rev

    Tore Aursand Guest

    On Thu, 04 Dec 2003 08:24:52 +0000, Bart Lateur wrote:
    >>> I cannot use the POSIX package.


    >> Why?


    > For the same reason he can't use any other module. The ISP probably
    > deleted it and isn't willing to install it again.


    Why would an ISP delete a module that comes with Perl?


    --
    Tore Aursand <>
    "I know not with what weapons World War 3 will be fought, but World War
    4 will be fought with sticks and stones." -- Albert Einstein
    Tore Aursand, Dec 4, 2003
    #10
  11. Tore Aursand <> wrote:
    > On Thu, 04 Dec 2003 08:24:52 +0000, Bart Lateur wrote:
    >>>> I cannot use the POSIX package.

    >
    >>> Why?

    >
    >> For the same reason he can't use any other module. The ISP probably
    >> deleted it and isn't willing to install it again.

    >
    > Why would an ISP delete a module that comes with Perl?

    ^^^


    The "S" often stands for "silly" rather than for "service". :-(


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Dec 4, 2003
    #11
  12. rev

    Ben Morrow Guest

    Tore Aursand <> wrote:
    > On Thu, 04 Dec 2003 08:24:52 +0000, Bart Lateur wrote:
    > >>> I cannot use the POSIX package.

    >
    > >> Why?

    >
    > > For the same reason he can't use any other module. The ISP probably
    > > deleted it and isn't willing to install it again.

    >
    > Why would an ISP delete a module that comes with Perl?


    A perhaps better question is 'Why would anyone *use* an ISP that
    deleted a module that comes with Perl?' :).

    Ben

    --
    The cosmos, at best, is like a rubbish heap scattered at random.
    - Heraclitus
    Ben Morrow, Dec 4, 2003
    #12
  13. rev wrote:

    > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > to get the day of the week from this (Monday). But, this is occurring
    > on my hosting vendor so whatever does it needs to be pure Perl.


    This works for any Gregorian Calendar day. Apologies for the formatting; my
    news client likes to wrap text and I can't be bothered turning off the
    feature for one lousy post. I'll leave it as an exercise for you to
    extract the day, month and year from the string to pass to this function.
    If you know that the date is a valid one, you can omit the function body
    from the first comment until "don't try this at home".

    # weekday
    # input: three scalar parameters: year, month (1-origin), day (1-origin).
    # output: scalar from 0 to 6 representing Sunday to Saturday respectively.
    # returns undef if month or day is out of bounds or any input is
    # not integral.
    sub weekday ($$$)
    {
    my ($y,$m,$d) = @_;

    # Year must be made positive for modulus to work correctly.
    $y += 400 * (1 + abs int $y/400) if $y <= 0;

    # Return undef if anything is out of bounds.
    return undef if
    $y != int $y or
    $m != int $m or
    $d != int $d or
    $m < 1 || $m > 12 or
    $d < 1 ||
    $d > [[31,28,31,30,31,30,31,31,30,31,30,31]
    [31,29,31,30,31,30,31,31,30,31,30,31]] ->
    [ ((! ($y % 400) || ($y % 100)) && (! ($y % 4))) || 0 ][ $m-1 ];

    # The calculation. Don't try this at home, kids.
    (
    [[6,2,2,5,0,3,5,1,4,6,2,4],[6,2,3,6,1,4,6,2,5,0,3,5]] ->
    [ ((! ($y % 400) || ($y % 100)) && (! ($y % 4))) || 0 ][ $m-1 ]
    + $d
    + $y
    + int(($y-1)/4)
    - int(($y-1)/100)
    + int(($y-1)/400)
    ) % 7;
    }

    --
    Debbie Pickett
    http://www.csse.monash.edu.au/~debbiep
    Deborah Pickett, Dec 5, 2003
    #13
  14. Deborah Pickett wrote:
    >
    > [snip]
    >
    > --
    > Debbie Pickett
    > http://www.csse.monash.edu.au/~debbiep
    >


    A student of the demented Dr. Conway perhaps? ;-)

    BTW - in reference to your web page at: http://www.csse.monash.edu.au/courseware/cse2395/exercise/topic09.html

    > 3. Perl provides two Unix commands for creating processes: fork
    > clones the current process, so that two identical copies of the
    > process are running (the only difference is in the value the fork
    > function returns); exec completely replaces the current process
    > with the specified program. Suggest how to implement the system
    > function using fork and exec.


    AFAIK fork is the only way to _create_ a process. exec doesn't _create_ a process, it
    replaces the currently running program with a different one but it is still the same process.

    From _Advanced Programming in the UNIX(R) Environment_ by W. Richard Stevens, page 188

    8.3 fork Function

    The <i>only</i> way a new process is created by the Unix kernel is when an existing process
    calls the fork function.



    John
    --
    use Perl;
    program
    fulfillment
    John W. Krahn, Dec 5, 2003
    #14
  15. rev

    Anno Siegel Guest

    Deborah Pickett <> wrote in comp.lang.perl.misc:
    > rev wrote:
    >
    > > I have a date formatted like so MM/DD/YYYY (e.g. 12/01/2003) and I need
    > > to get the day of the week from this (Monday). But, this is occurring
    > > on my hosting vendor so whatever does it needs to be pure Perl.

    >
    > This works for any Gregorian Calendar day. Apologies for the formatting; my
    > news client likes to wrap text and I can't be bothered turning off the
    > feature for one lousy post. I'll leave it as an exercise for you to
    > extract the day, month and year from the string to pass to this function.
    > If you know that the date is a valid one, you can omit the function body
    > from the first comment until "don't try this at home".


    Well, that's some compact bit of code. A few remarks:

    > # weekday
    > # input: three scalar parameters: year, month (1-origin), day (1-origin).


    Add

    # which are evaluated in scalar context.

    > # output: scalar from 0 to 6 representing Sunday to Saturday respectively.
    > # returns undef if month or day is out of bounds or any input is
    > # not integral.
    > sub weekday ($$$)


    If you use the prototype ($$$) the user must be told. Actually, I'd leave
    it out. It gives the function non-standard behavior for no good reason.

    > {
    > my ($y,$m,$d) = @_;
    >
    > # Year must be made positive for modulus to work correctly.


    The problem seems to be the missing year 0. The modulo operator
    works fine for negative numerators.

    > $y += 400 * (1 + abs int $y/400) if $y <= 0;
    >
    > # Return undef if anything is out of bounds.
    > return undef if


    Don't return undef to signal an error, simply return with no argument.
    Undef may do the wrong thing when the function is called in list context.
    In scalar context, the effect is the same.

    > $y != int $y or
    > $m != int $m or
    > $d != int $d or
    > $m < 1 || $m > 12 or
    > $d < 1 ||
    > $d > [[31,28,31,30,31,30,31,31,30,31,30,31]


    There's a comma missing at the end of this line. Did you *retype* the
    code?

    > [31,29,31,30,31,30,31,31,30,31,30,31]] ->
    > [ ((! ($y % 400) || ($y % 100)) && (! ($y % 4))) || 0 ][ $m-1 ];


    The leap year calculation is duplicated below. I'd make it a subroutine.

    > # The calculation. Don't try this at home, kids.
    > (
    > [[6,2,2,5,0,3,5,1,4,6,2,4],[6,2,3,6,1,4,6,2,5,0,3,5]] ->
    > [ ((! ($y % 400) || ($y % 100)) && (! ($y % 4))) || 0 ][ $m-1 ]
    > + $d
    > + $y
    > + int(($y-1)/4)
    > - int(($y-1)/100)
    > + int(($y-1)/400)


    Come to think of it, in the last three lines you're calculating the
    number of leap years before a given year. Make *that* a subroutine,
    and find if a given year is a leap year in terms of that.

    > ) % 7;
    > }


    Appending a revised version below. Indentation could use improvement
    too, but I left that alone.

    I have also used constants for the four auxiliary arrays. That actually
    adds some code, but it makes the relation between the arrays explicit.

    Anno


    # weekday
    # input: three scalar parameters: year, month (1-origin), day (1-origin).
    # output: scalar from 0 to 6 representing Sunday to Saturday respectively.
    # returns undef if month or day is out of bounds or any input is
    # not integral.

    use constant DAYS_IN_MONTH => do {
    my @dim_l = my @dim_n = (31,28,31,30,31,30,31,31,30,31,30,31);
    $dim_l[ 1]++; # Feb one day longer in leap years
    [\ @dim_n, \ @dim_l];
    };

    use constant WDAY_OF_FIRST => do {
    my @wof_n = ( 6); # Jan 1st is Saturday in reference year
    push @wof_n, ( $wof_n[-1] + $_) % 7 for @{ DAYS_IN_MONTH->[0]};
    pop @wof_n; # we generated a thirteenth
    my @wof_l = ( 6);
    push @wof_l, ( $wof_l[-1] + $_) % 7 for @{ DAYS_IN_MONTH->[1]};
    pop @wof_l; # we have a thirteenth
    [\ @wof_n, \ @wof_l]
    };

    sub weekday
    {
    my ($y,$m,$d) = @_;

    # Year must be made positive (missing year 0)
    $y += 400 * (1 + abs int $y/400) if $y <= 0;

    # Return undef if anything is out of bounds.
    return if
    $y != int $y or
    $m != int $m or
    $d != int $d or
    $m < 1 || $m > 12 or
    $d < 1 || $d > DAYS_IN_MONTH -> [ is_leap_year( $y)][ $m-1 ];

    # The calculation. Don't try this at home, kids.
    (
    WDAY_OF_FIRST -> [ is_leap_year( $y) ][ $m-1 ]
    + $d
    + $y
    + n_leap_years( $y - 1)
    ) % 7;
    }

    sub n_leap_years {
    my $y = shift;
    int($y/4) - int($y/100) + int($y/400);
    }

    sub is_leap_year {
    my $y = shift;
    n_leap_years( $y) - n_leap_years( $y - 1);
    }
    Anno Siegel, Dec 5, 2003
    #15
  16. In article <>,
    Bart Lateur <> wrote:

    > Iain Truskett wrote:
    >
    > >* rev <>:
    > >
    > >> I cannot use the POSIX package.

    > >
    > >Why?

    >
    > For the same reason he can't use any other module. The ISP probably
    > deleted it and isn't willing to install it again.


    Or because the homework assignment specifically said he can't...

    ;-)

    big

    --
    'When I first met Katho, she had a meat cleaver in one hand and
    half a sheep in the other. "Come in", she says, "Hammo's not here.
    I hope you like meat.' Sharkey in aus.moto
    Iain Chalmers, Dec 8, 2003
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest
    Replies:
    3
    Views:
    1,840
    Alexandre
    Dec 22, 2003
  2. Andy
    Replies:
    1
    Views:
    703
  3. Guest
    Replies:
    3
    Views:
    522
    Alexandre
    Dec 22, 2003
  4. Guest
    Replies:
    3
    Views:
    1,087
    Alexandre
    Dec 22, 2003
  5. Ilya Zakharevich
    Replies:
    0
    Views:
    110
    Ilya Zakharevich
    Oct 17, 2003
Loading...

Share This Page