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
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.
|