' Calendar Date — date validation, day-of-week, and date arithmetic
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL year AS LONG
    LOCAL month AS LONG
    LOCAL day AS LONG
    LOCAL i AS LONG
    LOCAL j AS LONG
    LOCAL daysInMonth AS LONG
    LOCAL isLeapVal AS LONG
    LOCAL dayOfWeek AS LONG
    LOCAL totalDays AS LONG
    LOCAL dowName AS STRING
    LOCAL monthName AS STRING
    LOCAL dateStr AS STRING
    LOCAL testCount AS LONG
    LOCAL passCount AS LONG
    LOCAL failCount AS LONG
    LOCAL t AS LONG
    LOCAL y AS LONG
    LOCAL m AS LONG
    LOCAL d AS LONG
    LOCAL startYear AS LONG
    LOCAL endYear AS LONG
    LOCAL lineStr AS STRING
    testCount = 0
    passCount = 0
    failCount = 0
    PRINT "============================================"
    PRINT "          CALENDAR DATE UTILITY"
    PRINT "============================================"
    PRINT ""
    PRINT "Leap year determination:"
    PRINT ""
    FOR year = 1900 TO 2100
        IF year MOD 400 = 0 THEN
            isLeapVal = 1
        ELSE
            IF year MOD 100 = 0 THEN
                isLeapVal = 0
            ELSE
                IF year MOD 4 = 0 THEN
                    isLeapVal = 1
                ELSE
                    isLeapVal = 0
                END IF
            END IF
        END IF
        testCount = testCount + 1
        IF year = 1900 THEN
            IF isLeapVal = 0 THEN
                passCount = passCount + 1
            ELSE
                failCount = failCount + 1
            END IF
        END IF
        IF year = 2000 THEN
            IF isLeapVal = 1 THEN
                passCount = passCount + 1
            ELSE
                failCount = failCount + 1
            END IF
        END IF
        IF year = 2024 THEN
            IF isLeapVal = 1 THEN
                passCount = passCount + 1
            ELSE
                failCount = failCount + 1
            END IF
        END IF
        IF year MOD 10 = 0 THEN
            PRINT STR$(year) + " is "
            IF isLeapVal = 0 THEN
                PRINT "not "
            END IF
            PRINT "a leap year"
        END IF
    NEXT year
    PRINT ""
    PRINT "============================================"
    PRINT "      DAYS IN EACH MONTH"
    PRINT "============================================"
    PRINT ""
    FOR year = 2023 TO 2025
        PRINT "Year " + STR$(year) + ":"
        FOR month = 1 TO 12
            IF month = 2 THEN
                isLeapVal = 0
                IF year MOD 400 = 0 THEN
                    isLeapVal = 1
                ELSE
                    IF year MOD 100 = 0 THEN
                        isLeapVal = 0
                    ELSE
                        IF year MOD 4 = 0 THEN
                            isLeapVal = 1
                        END IF
                    END IF
                END IF
                IF isLeapVal = 1 THEN
                    daysInMonth = 29
                ELSE
                    daysInMonth = 28
                END IF
            ELSE
                IF month = 4 OR month = 6 OR month = 9 OR month = 11 THEN
                    daysInMonth = 30
                ELSE
                    daysInMonth = 31
                END IF
            END IF
            IF month = 1 THEN monthName = "Jan"
            IF month = 2 THEN monthName = "Feb"
            IF month = 3 THEN monthName = "Mar"
            IF month = 4 THEN monthName = "Apr"
            IF month = 5 THEN monthName = "May"
            IF month = 6 THEN monthName = "Jun"
            IF month = 7 THEN monthName = "Jul"
            IF month = 8 THEN monthName = "Aug"
            IF month = 9 THEN monthName = "Sep"
            IF month = 10 THEN monthName = "Oct"
            IF month = 11 THEN monthName = "Nov"
            IF month = 12 THEN monthName = "Dec"
            PRINT "  " + monthName + ": " + STR$(daysInMonth) + " days"
        NEXT month
    NEXT year
    PRINT ""
    PRINT "============================================"
    PRINT "      DAY OF WEEK (Zeller's congruence)"
    PRINT "============================================"
    PRINT ""
    FOR year = 2024 TO 2026
        FOR month = 1 TO 12
            day = 1
            m = month
            y = year
            IF m < 3 THEN
                m = m + 12
                y = y - 1
            END IF
            t = day + (13 * (m + 1)) / 5 + y + (y / 4) - (y / 100) + (y / 400)
            dayOfWeek = t MOD 7
            IF dayOfWeek < 0 THEN
                dayOfWeek = dayOfWeek + 7
            END IF
            dayOfWeek = dayOfWeek + 1
            IF dayOfWeek > 7 THEN
                dayOfWeek = dayOfWeek - 7
            END IF
            IF dayOfWeek = 1 THEN dowName = "Mon"
            IF dayOfWeek = 2 THEN dowName = "Tue"
            IF dayOfWeek = 3 THEN dowName = "Wed"
            IF dayOfWeek = 4 THEN dowName = "Thu"
            IF dayOfWeek = 5 THEN dowName = "Fri"
            IF dayOfWeek = 6 THEN dowName = "Sat"
            IF dayOfWeek = 7 THEN dowName = "Sun"
            IF month = 1 THEN monthName = "Jan"
            IF month = 2 THEN monthName = "Feb"
            IF month = 3 THEN monthName = "Mar"
            IF month = 4 THEN monthName = "Apr"
            IF month = 5 THEN monthName = "May"
            IF month = 6 THEN monthName = "Jun"
            IF month = 7 THEN monthName = "Jul"
            IF month = 8 THEN monthName = "Aug"
            IF month = 9 THEN monthName = "Sep"
            IF month = 10 THEN monthName = "Oct"
            IF month = 11 THEN monthName = "Nov"
            IF month = 12 THEN monthName = "Dec"
            dateStr = STR$(year) + "-" + monthName + "-01"
            PRINT dateStr + " is " + dowName
        NEXT month
    NEXT year
    PRINT ""
    PRINT "============================================"
    PRINT "      DATE VALIDATION"
    PRINT "============================================"
    PRINT ""
    LOCAL validDate AS LONG
    LOCAL testYear AS LONG
    LOCAL testMonth AS LONG
    LOCAL testDay AS LONG
    testYear = 2024
    testMonth = 2
    testDay = 29
    validDate = 1
    IF testMonth < 1 OR testMonth > 12 THEN
        validDate = 0
    END IF
    IF testDay < 1 THEN
        validDate = 0
    END IF
    IF testMonth = 2 THEN
        isLeapVal = 0
        IF testYear MOD 400 = 0 THEN
            isLeapVal = 1
        ELSE
            IF testYear MOD 100 = 0 THEN
                isLeapVal = 0
            ELSE
                IF testYear MOD 4 = 0 THEN
                    isLeapVal = 1
                END IF
            END IF
        END IF
        IF isLeapVal = 1 THEN
            IF testDay > 29 THEN
                validDate = 0
            END IF
        ELSE
            IF testDay > 28 THEN
                validDate = 0
            END IF
        END IF
    ELSE
        IF testMonth = 4 OR testMonth = 6 OR testMonth = 9 OR testMonth = 11 THEN
            IF testDay > 30 THEN
                validDate = 0
            END IF
        ELSE
            IF testDay > 31 THEN
                validDate = 0
            END IF
        END IF
    END IF
    PRINT "Date " + STR$(testYear) + "-" + STR$(testMonth) + "-" + STR$(testDay)
    IF validDate = 1 THEN
        PRINT " is valid"
    ELSE
        PRINT " is invalid"
    END IF
    testYear = 2023
    testMonth = 2
    testDay = 29
    validDate = 1
    IF testMonth < 1 OR testMonth > 12 THEN
        validDate = 0
    END IF
    IF testDay < 1 THEN
        validDate = 0
    END IF
    IF testMonth = 2 THEN
        isLeapVal = 0
        IF testYear MOD 400 = 0 THEN
            isLeapVal = 1
        ELSE
            IF testYear MOD 100 = 0 THEN
                isLeapVal = 0
            ELSE
                IF testYear MOD 4 = 0 THEN
                    isLeapVal = 1
                END IF
            END IF
        END IF
        IF isLeapVal = 1 THEN
            IF testDay > 29 THEN
                validDate = 0
            END IF
        ELSE
            IF testDay > 28 THEN
                validDate = 0
            END IF
        END IF
    ELSE
        IF testMonth = 4 OR testMonth = 6 OR testMonth = 9 OR testMonth = 11 THEN
            IF testDay > 30 THEN
                validDate = 0
            END IF
        ELSE
            IF testDay > 31 THEN
                validDate = 0
            END IF
        END IF
    END IF
    PRINT "Date " + STR$(testYear) + "-" + STR$(testMonth) + "-" + STR$(testDay)
    IF validDate = 1 THEN
        PRINT " is valid"
    ELSE
        PRINT " is invalid"
    END IF
    PRINT ""
    PRINT "Calendar date utilities complete"
    FUNCTION = 0
END FUNCTION
