QB64 Phoenix Edition
UniDate - Printable Version

+- QB64 Phoenix Edition (https://staging.qb64phoenix.com)
+-- Forum: QB64 Rising (https://staging.qb64phoenix.com/forumdisplay.php?fid=1)
+--- Forum: Prolific Programmers (https://staging.qb64phoenix.com/forumdisplay.php?fid=26)
+---- Forum: SMcNeill (https://staging.qb64phoenix.com/forumdisplay.php?fid=29)
+---- Thread: UniDate (/showthread.php?tid=1459)



UniDate - SMcNeill - 02-09-2023

As we were talking on Discord, it'd be nice if there was some function to easily format a date to the proper localization.  (month-day-year vs day-month-year, for example)

Well, now there is!

Code: (Select All)
PRINT UniDate$("mm/dd/yyyy", DATE$)
PRINT UniDate$("w, MM dd, YYYY", DATE$)
PRINT UniDate$("W, MM DD, YYYY", DATE$)
PRINT UniDate$("dd/mm/yyyy", DATE$)
PRINT UniDate$("W, E D, YYYY", DATE$)
PRINT UniDate$("mm-dd-yy", DATE$)

FUNCTION UniDate$ (format$, userdate$)
    'some basic documentation for formatting:
    'dates sent via userdate$ should be in the standardized QB64 DATE$ format -- MM/DD/YYYY
    'To customize your return date format, use the following syntax
    'w = short weekday names.  (Mon, Tue, Wed, Thu, Fri, Sat, Sun)
    'W = long weekday names.  (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
    'E = Extended month names.  (January, February, March....)
    'M = long month names.  (Jan, Feb, Mar...)
    'm = short month names.  (01, 02, 03...)
    'D = long day names.  (01st, 02nd, 03rd...)
    'd = short day names.  (01, 02, 03...)
    'Y or y (case insensitive) = year.  Number of Yy present determines the number of digits we return.
    '       YY = 2-digit year
    '       YYYY = 4 digit year
    '       Y with any additional number of y's = 4 digit year by default, so a typo of YYYYY is the same as YYYY.
    'Any other character is simply considered part of the desired output and faithfully carried over into the proper spot.
    '      For example, "mm/dd/yyyy" gives us "02/10/2023" for Feb 10th, 2023.
    '      Second example, "dd.mm.yyyy" gives us "10.02.2023" for the same date.
    '      Third example, "dd EE YYYY" gives us "02 February 2023" for that same date.
    'Note:  Extra digits of most of these codes are simply ignored for error proofing purposes, with only the initial code being accepted.
    '      For example "mM YYYY" is actually processed as a simple "m YYYY".  The process won't mix short, long, or extended results.
    '      Also for example, "m YY" is the *exact* same as "mm YY".
    '      Feel free to use extra digits as you desire to help you keep track of positional spacing in your format string.
    '      Even though "M D, yyyy" may process the same as "MMM DDDD, YYYY", the second may work better for you if you're trying to track
    '             position of formatted objects.  (The output would be "Feb 10th, 2023", and those extra characters help hold that
    '             positioning for us easily.)

    'And, I think that's it.  Enjoy, guys!


    temp$ = userdate$
    IF temp$ = "" THEN temp$ = DATE$
    m$ = LEFT$(temp$, 2)
    d$ = MID$(temp$, 4, 2)
    y$ = RIGHT$(temp$, 4)
    temp$ = format$
    DO
        firstchar$ = LEFT$(temp$, 1)
        SELECT CASE firstchar$
            CASE "E" 'extended month
                temp$ = MID$(temp$, 2)
                IF NOT MonthSet THEN
                    MonthSet = -1
                    SELECT CASE VAL(m$)
                        CASE 1: out$ = out$ + "January"
                        CASE 2: out$ = out$ + "February"
                        CASE 3: out$ = out$ + "March"
                        CASE 4: out$ = out$ + "April"
                        CASE 5: out$ = out$ + "May"
                        CASE 6: out$ = out$ + "June"
                        CASE 7: out$ = out$ + "July"
                        CASE 8: out$ = out$ + "August"
                        CASE 9: out$ = out$ + "September"
                        CASE 10: out$ = out$ + "October"
                        CASE 11: out$ = out$ + "November"
                        CASE 12: out$ = out$ + "December"
                    END SELECT
                END IF
            CASE "M" 'long month
                temp$ = MID$(temp$, 2)
                IF NOT MonthSet THEN
                    MonthSet = -1
                    SELECT CASE VAL(m$)
                        CASE 1: out$ = out$ + "Jan"
                        CASE 2: out$ = out$ + "Feb"
                        CASE 3: out$ = out$ + "Mar"
                        CASE 4: out$ = out$ + "Apr"
                        CASE 5: out$ = out$ + "May"
                        CASE 6: out$ = out$ + "Jun"
                        CASE 7: out$ = out$ + "Jul"
                        CASE 8: out$ = out$ + "Aug"
                        CASE 9: out$ = out$ + "Sep"
                        CASE 10: out$ = out$ + "Oct"
                        CASE 11: out$ = out$ + "Nov"
                        CASE 12: out$ = out$ + "Dec"
                    END SELECT
                END IF
            CASE "m" 'short month
                temp$ = MID$(temp$, 2)
                IF NOT MonthSet THEN
                    MonthSet = -1
                    SELECT CASE VAL(m$)
                        CASE 1: out$ = out$ + "01"
                        CASE 2: out$ = out$ + "02"
                        CASE 3: out$ = out$ + "03"
                        CASE 4: out$ = out$ + "04"
                        CASE 5: out$ = out$ + "05"
                        CASE 6: out$ = out$ + "06"
                        CASE 7: out$ = out$ + "07"
                        CASE 8: out$ = out$ + "08"
                        CASE 9: out$ = out$ + "09"
                        CASE 10: out$ = out$ + "10"
                        CASE 11: out$ = out$ + "11"
                        CASE 12: out$ = out$ + "12"
                    END SELECT
                END IF
            CASE "D" 'long day
                temp$ = MID$(temp$, 2)
                IF NOT DaySet THEN
                    DaySet = -1
                    out$ = out$ + RIGHT$("00" + _TRIM$(d$), 2)
                    SELECT CASE VAL(d$)
                        CASE 1, 11, 21, 31: out$ = out$ + "st"
                        CASE 2, 22: out$ = out$ + "nd"
                        CASE 3, 23: out$ = out$ + "rd"
                        CASE ELSE: out$ = out$ + "th"
                    END SELECT
                END IF
            CASE "d" 'short day
                temp$ = MID$(temp$, 2)
                IF NOT DaySet THEN
                    DaySet = -1
                    out$ = out$ + RIGHT$("00" + _TRIM$(d$), 2)
                END IF

            CASE "W" 'long weekday
                temp$ = MID$(temp$, 2)
                IF NOT WeekdaySet THEN
                    GOSUB getday
                    SELECT CASE result
                        CASE 0: Day$ = "Saturday"
                        CASE 1: Day$ = "Sunday"
                        CASE 2: Day$ = "Monday"
                        CASE 3: Day$ = "Tuesday"
                        CASE 4: Day$ = "Wednesday"
                        CASE 5: Day$ = "Thursday"
                        CASE 6: Day$ = "Friday"
                    END SELECT
                    out$ = out$ + Day$
                END IF
            CASE "w" 'short weekday
                temp$ = MID$(temp$, 2)
                IF NOT WeekdaySet THEN
                    GOSUB getday
                    SELECT CASE result
                        CASE 0: Day$ = "Sat"
                        CASE 1: Day$ = "Sun"
                        CASE 2: Day$ = "Mon"
                        CASE 3: Day$ = "Tue"
                        CASE 4: Day$ = "Wed"
                        CASE 5: Day$ = "Thr"
                        CASE 6: Day$ = "Fri"
                    END SELECT
                    out$ = out$ + Day$
                END IF
            CASE "Y", "y" 'year
                IF NOT YearSet THEN
                    YearSet = -1
                    IF LEFT$(UCASE$(temp$), 4) = "YYYY" THEN
                        temp$ = MID$(temp$, 5)
                        out$ = out$ + y$
                    ELSEIF LEFT$(UCASE$(temp$), 2) = "YY" THEN
                        temp$ = MID$(temp$, 3)
                        out$ = out$ + RIGHT$(y$, 2)
                    ELSE
                        temp$ = MID$(temp$, 2)
                        out$ = out$ + y$
                    END IF
                ELSE
                    temp$ = MID$(temp$, 2)
                END IF
            CASE ELSE 'seperator
                temp$ = MID$(temp$, 2)
                out$ = out$ + firstchar$
        END SELECT
    LOOP UNTIL temp$ = ""
    UniDate$ = out$
    EXIT FUNCTION

    getday:
    WeekdaySet = -1
    'From Zeller's congruence: https://en.wikipedia.org/wiki/Zeller%27s_congruence
    mm = VAL(m$): dd = VAL(d$): yyyy = VAL(y$)
    IF mm < 3 THEN mm = mm + 12: yyyy = yyyy - 1
    century = yyyy MOD 100
    zerocentury = yyyy \ 100
    result = (dd + INT(13 * (mm + 1) / 5) + century + INT(century / 4) + INT(zerocentury / 4) + 5 * zerocentury) MOD 7
    RETURN
END FUNCTION


   


RE: UniDate - TerryRitchie - 02-09-2023

That's going into my bag of tricks. Thanks Smile


RE: UniDate - RhoSigma - 02-09-2023

As a "see also" in my Libraries Collection in the folder QB-StdLibs the qbtime.h/.bi/.bm triplet. It's a wrapper to the strftime() C-function.


RE: UniDate - SMcNeill - 02-10-2023

Edited to include some notes for documentation into the original post.  If any of you guys have copied this for your "toolbox", I'd suggest replacing what you already have with the latest version, as it's commented well enough to describe the custom formatting which one can use to generate a date in whatever format they'd like to view it in. 

If anyone has any questions, feel free to ask and I'll answer them for you.  Biggest thing to remember is:
1. We have "short" and "long" versions of everything except our year.  
2. Basic format is "M"onth, "D"ay, "Y"ear, "W"eekday.
3. Short versions are usually just the number, long versions are names or include strings.
         "d" is just the day.  "01" for the first day of the month.  "27" for the 27th day of the month.
         "D" is the day with the "st, nd, rd, th" to it.  "01st" or "27th".
4. For months, we actually have 3 codes -- "E"xtended months, long "M"onths, short "m"onths.
         "E" = "February"
         "M" = "Feb"
         "m" = "02"
5. Anything not a "WwEMmDdYy" is considered part of your custom formatting so you can add spaces, commas, dashes, or slashes to your hearts content to separate those elements.

"StarCount: mm.dd.yyyy" would process and return as "StarCount: 02.10.2023", though *why* you'd want it to return that, is beyond me.  I'm just saying that you could use it and get it back in that format.  Anything NOT "WwEMmDdYy" is just counted as spacer/formatting separators, so be aware of that in case you make a typo.  (IE you use "mn-dd-yyyy", you'll get results that look like "02n-10-2023".)

And that's more or less it.  Smile