Search code examples
c#.netf#string-formattingc#-to-f#

Iterating through a calendar in F#


for (int ctr = 1; ctr <= gregorianCalendar.GetMonthsInYear(gregorianCalendar.GetYear(startOfYear)); ctr++) {
    Console.Write(" {0,2}", ctr);
    Console.WriteLine("{0,12}{1,15:MMMM}",
                      gregorianCalendar.GetDaysInMonth(gregorianCalendar.GetYear(startOfMonth), gregorianCalendar.GetMonth(startOfMonth)),
                      startOfMonth);
    startOfMonth = gregorianCalendar.AddMonths(startOfMonth, 1);
}

I was trying to write the same code in F# but I don't know what {0, 2} and {0,12}{1,15:MMMM} is, what they do and what F# equivalent of these are. The main target here is F# equivalent of C# code above. But, I would be glad if you explain formats above shortly.

Notes:

  • gregorianCalendar is an instance of System.Globalization.GregorianCalendar.
  • startOfYear is an instance of DateTime which has value of DateTime(2023, 1, 1).
  • startOfMonth is an instance of DateTime which has value same as value of startOfYear at initialization. It's used to loop through months.

Solution

  • Here are a few different translations, from trying to change as little as possible to getting more advanced

    open System
    open System.Globalization
    let now, today = DateTime.Now, DateTime.Today
    let startOfYear = DateTime(now.Year, now.Month, 1)
    let g = GregorianCalendar()
    let range = [1.. g.GetMonthsInYear(g.GetYear(startOfYear))]
    let runViaFor() =
        let mutable startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
        for ctr in range do
            printf "%2i" ctr
            printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
            startOfMonth <- g.AddMonths(startOfMonth, 1)
        ()
    let runViaSeq() =
        let mutable startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
        range
        |> Seq.iter(fun ctr ->
            printf "%2i" ctr
            printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
            startOfMonth <- g.AddMonths(startOfMonth, 1)
        )
    let runViaFold() =
        let startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
        (startOfMonth, range)
        ||> Seq.fold(fun startOfMonth ctr ->
            printf "%2i" ctr
            printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
            g.AddMonths(startOfMonth, 1)
        )
        |> ignore<DateTime>
        
    let withRefactors today =
        let addDays (dt:DateTime) (i:int) = float i |> dt.AddDays
        let getStartOfMonth(dt:DateTime) = dt.Day - 1 |> (*) -1 |> addDays dt
        
        let getLastDayOfMonth(startOfMonth:DateTime) = 
            let year = g.GetYear(startOfMonth)
            let month = g.GetMonth(startOfMonth)
            g.GetDaysInMonth(year, month)
        let printRow (startOfMonth:DateTime) ctr =
            printf "%2i" ctr
            printfn "%12i%15s" (getLastDayOfMonth startOfMonth) (startOfMonth.ToString("MMMM"))
        let printAndGet startOfMonth ctr =
            printRow startOfMonth ctr
            g.AddMonths(startOfMonth, 1)
            
            
        (getStartOfMonth today, range)
        ||> Seq.fold printAndGet
        |> ignore<DateTime>
    printfn "For:"    
    runViaFor()
    printfn "----"
    printfn "Seq:"
    runViaSeq()
    printfn "----"
    printfn "Fold:"
    runViaFold()
    printfn "----"
    printfn "Ref:"
    withRefactors today
    printfn "----"
    

    sample output: codesnippetimg