[Short Prog] Week Number Getter
Tags: raku, shell, perl, haskell
Published: 2021-08-05 07:55:23

  The one way to store my weekly documents in a directory or a weekly task in a spreadsheet is to store them into a separate directory (or a sheet) by weekly basis. and I used the week number because it has shorter name than using period notation like (08.02-08.08).
  I scanned some invoices and name it in sort of "20210805.Chicken.pdf" then I move them into appropriate "week -number-ed" directory.
  then I realised that there might be some automatic way to put them into matched weekly directory.

## How to get week number in Raku
  I'm a [raku](www.raku.org) user. and I could make it a simple terminal interface programme like below.

```perl
#!/usr/bin/env raku
multi sub MAIN ( Int $year, Int $month, Int $day ) {
    say Date.new( :$year, :$month, :$day ).week-number();
}
```

```shell
> chmod u+x week-number.raku
> week-number.raku 2021 8 4
31
```

I think it's pretty straight forward if get used to some syntax.

If you want to use a single text like "20210804"
I could add one more multi sub for the MAIN()

```perl
sub cut-off-last-two-digits( @i ) returns Int {
    # warning: side effect
    ( @i.pop, @i.pop ).reverse.join.Int
}

multi sub MAIN ( Int \yyyymmdd ) {
    my @i = yyyymmdd.comb;

    my ( $year, $month, $day );

    $day   = cut-off-last-two-digits @i;
    $month = cut-off-last-two-digits @i;
    $year  = @i.join.Int;

    if (( $year, $month, $day )>>.defined).any == False {
        die "check your input: {yyyymmdd}";
    }
    samewith( $year, $month, $day );
}

multi sub MAIN ( Int $year, Int $month, Int $day ) {
    say Date.new( :$year, :$month, :$day ).week-number();
}
```

## **Perl5** Version
I searched the internet and I used DateTime module to implement.
but I guess DateTime is quite heavy module. because perl is normally very very fast but this programme isn't.

```perl
#!/usr/bin/env perl
use strict; use warnings;
use v5.26;
use DateTime;
use File::Basename;

our $PROG = $0;

my @parsed;
my ( $year, $month, $day );

use enum qw(F_YEAR F_MONTH F_DAY);

sub usage {
    print <<  'END_OF_USAGE';
$PROG <YYYYMMDD>
  OR
$PROG <YYYY> <MM> <DD>
END_OF_USAGE
}

if ( @ARGV == 1 ) {
    # parse as YYYYMMDD
    my $str = $ARGV[0];
    @parsed = $str =~ /^(\d+)(\d\d)(\d\d)$/;
} elsif ( @ARGV == 3 ) {
    @parsed = @ARGV;
} else {
    usage();
    exit 1;
}

( $year, $month, $day ) = @parsed[F_YEAR, F_MONTH, F_DAY];

my $dt = DateTime->new( year     => $year,
                       month    => $month,
                       day      => $day );

print $dt->week_number();
```

## **Haskell Version**
I still hate some part of code and there is no proper way to handle errors but it is working fast. so I'm going to stick with this programme for a while.

```shell
> stack new week-number
```

### app/Main.hs
```haskell
module Main where

import System.Environment
import Lib

main :: IO ()
main = do
  args <- getArgs -- note: args :: [String]
  putStrLn (case args of
              yyyymmdd:[] ->
                weekNumberStringFromString yyyymmdd
              y:m:d:[] ->
                let y' = (read y :: Integer)
                    m' = (read m :: Int)
                    d' = (read d :: Int)
                in
                  weekNumberStringFromGregorian y' m' d'
              _ ->
                unlines
                [ "usage:"
                , "week-number: <yyyymmdd>"
                , "  or"
                , "week-number: <yyyy> <m> <d>" ] )
```

### src/Lib.hs
```haskell
module Lib
  ( weekNumberStringFromString
  , weekNumberStringFromGregorian
    ) where

import qualified Data.Time as DT

weekNumberStringFromString :: String -> String
weekNumberStringFromString yyyymmdd =
  let ut = DT.parseTimeOrError
           True DT.defaultTimeLocale "%Y%m%d" yyyymmdd  :: DT.UTCTime
  in
    DT.formatTime DT.defaultTimeLocale "%V" ut

weekNumberStringFromGregorian :: Integer -> Int -> Int -> String
weekNumberStringFromGregorian y m d =
  ( DT.formatTime DT.defaultTimeLocale "%V" ) $ DT.fromGregorian y m d
```

```shell
> stack build
> stack install
> week-number-exe 2021 8 4
31
```

so now I need to make some script go through the file
and get the date information from the file name and move them into
right place.

Okay. That's all today.