Cariboudjan wrote: ↑January 17th, 2021, 6:56 pm
%D doesn't appear to format correctly for different regions. January 17, 2021 formats as
17/01/21 despite the US being the only actual place that formats MONTH/DAY/YEAR. Japan for example, formats YEAR/MONTH/DAY, and most areas of Europe format DAY/MONTH/YEAR.
Btw, Canada formats DAY/MONTH/YEAR despite what Wikipedia says. No one in Canada uses YEAR/MONTH/DAY, yet that's what it says Canada uses on Wikipedia for some reason.
This might be a Windows thing, but if it isn't, this probably requires a fix. Maybe changing the formatting in Windows fixes this. I don't know, but it's strange that FormatLocale doesn't override the Windows setting.
Sorry to interject here at this late point, but if proper date and time formatting is important to your skin, I would suggest considering an alternate approach. It requires a little more work, but it's almost guaranteed (but not 100% guaranteed) to give the exact results your end-user wants to see.
The problem is that while Rainmeter (and Lua) do support formatting by locale, you've discovered that not all locales are correct. There are cases where the Y/M/D order is off, cases where the
separator is off, and cases where both are off. Not only that, maybe the formatting is perfect, but the user has decided he prefers something else that is non-standard for that locale.
It turns out that the Windows registry contains the exact formatting strings needed to properly format the date and time the way the locale and/or user wants to see it. The problem is that Windows uses a format style that is completely different than Rainmeter/Lua, so you need to do a little substitution work to translate the format string from Windows-style to Rainmeter-style. But once you do the work, you'll have a format string that will almost always be exactly what the user wants to see, regardless of any locale.
Code: Select all
[Rainmeter]
AccurateText=1
DynamicWindowSize=1
Update=1000
[Variables]
; set default values; these are dynamic so no need to change them here
MyLongDateFormat=""
MyShortDateFormat=""
MyLongTimeFormat=""
MyShortTimeFormat=""
; -----------------------------------------------------------------------------
; Measures
; -----------------------------------------------------------------------------
; sLongDate = "dddd, MMMM d, yyyy" (example)
; yyyyy = 5-digit year (00001-99999) = no equivalent in Rainmeter, use %Y
; yyyy = 4-digit year (0001-9999) = %Y
; yyy = 3-digit year (001-999) = no equivalent in Rainmeter, use %#Y
; yy = 2-digit year (01-99) = %y
; y = 1-digit year (1-99) = no equivalent in Rainmeter, use %#y
; MMMM = month name ("August") = %B
; MMM = abbreviated month name ("Aug") = %b
; MM = month number, leading zero (01-12) = %m
; M = month number, no leading zero (1-12) = %#m
; dddd = day name ("Friday") = %A
; ddd = abbreviated day name ("Fri") = %a
; dd = day number, leading zero (01-31) = %d
; d = day number, no leading zero (1-31) = %#d
;
[MeasureLongDateFormat]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=Control Panel\International
RegValue=sLongDate
Substitute="y":"@","@@@@@":"%Y","@@@@":"%Y","@@@":"%#Y","@@":"%y","@":"%#y","M":"@","@@@@":"%B","@@@":"%b","@@":"%m","@":"%#m","d":"@","@@@@":"%A","@@@":"%a","@@":"%d","@":"%#d"
IfMatch="^#MyLongDateFormat#$"
IfNotMatchAction=[!SetVariable MyLongDateFormat "[MeasureLongDateFormat]"][!UpdateMeasure MeasureLongDate][!Redraw]
DynamicVariables=1
; use UpdateDivider=-1 so measures run once on load/refresh; remove if you want skin to react to format changes
UpdateDivider=-1
; sShortDate = "M/d/yyyy" (example)
[MeasureShortDateFormat]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=Control Panel\International
RegValue=sShortDate
Substitute="y":"@","@@@@@":"%Y","@@@@":"%Y","@@@":"%#Y","@@":"%y","@":"%#y","M":"@","@@@@":"%B","@@@":"%b","@@":"%m","@":"%#m","d":"@","@@@@":"%A","@@@":"%a","@@":"%d","@":"%#d"
IfMatch="^#MyShortDateFormat#$"
IfNotMatchAction=[!SetVariable MyShortDateFormat "[MeasureShortDateFormat]"][!UpdateMeasure MeasureShortDate][!Redraw]
DynamicVariables=1
UpdateDivider=-1
; sTimeFormat = "h:mm:ss tt" (example)
; HH = hour, zero-based 24-hour, leading zero (00-23) = %H
; H = hour, zero-based 24-hour, no leading zero (0-23) = %#H
; hh = hour, 12-hour, leading zero (01-12) = %I
; h = hour, 12-hour, no leading zero (1-12) = %#I
; mm = minute, leading zero (00-59) = %M
; m = minute, no leading zero (0-59) = %#M
; ss = seconds, leading zero (00-59) = %S
; s = seconds, no leading zero (0-59) = %#S
; tt = AM/PM designator = %p
; t = abbreviated AM/PM designator (A/P) = no equivalent in Rainmeter, use %p
;
[MeasureLongTimeFormat]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=Control Panel\International
RegValue=sTimeFormat
Substitute="H":"@","@@":"%H","@":"%#H","h":"@","@@":"%I","@":"%#I","m":"@","@@":"%M","@":"%#M","s":"@","@@":"%S","@":"%#S","t":"@","@@":"%p","@":"%p"
IfMatch="^#MyLongTimeFormat#$"
IfNotMatchAction=[!SetVariable MyLongTimeFormat "[MeasureLongTimeFormat]"][!UpdateMeasure MeasureLongTime][!Redraw]
DynamicVariables=1
UpdateDivider=-1
; sShortTime = "h:mm tt" (example)
[MeasureShortTimeFormat]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=Control Panel\International
RegValue=sShortTime
Substitute="H":"@","@@":"%H","@":"%#H","h":"@","@@":"%I","@":"%#I","m":"@","@@":"%M","@":"%#M","s":"@","@@":"%S","@":"%#S","t":"@","@@":"%p","@":"%p"
IfMatch="^#MyShortTimeFormat#$"
IfNotMatchAction=[!SetVariable MyShortTimeFormat "[MeasureShortTimeFormat]"][!UpdateMeasure MeasureShortTime][!Redraw]
DynamicVariables=1
UpdateDivider=-1
[MeasureLongDate]
Measure=Time
; the two Format options are equivalent; use whichever you prefer
Format=[MeasureLongDateFormat]
;Format=#MyLongDateFormat#
FormatLocale=Local
DynamicVariables=1
[MeasureShortDate]
Measure=Time
Format=[MeasureShortDateFormat]
;Format=#MyShortDateFormat#
DynamicVariables=1
[MeasureLongTime]
Measure=Time
Format=[MeasureLongTimeFormat]
;Format=#MyLongTimeFormat#
DynamicVariables=1
[MeasureShortTime]
Measure=Time
Format=[MeasureShortTimeFormat]
;Format=#MyShortTimeFormat#
DynamicVariables=1
; -----------------------------------------------------------------------------
; Meters
; -----------------------------------------------------------------------------
[MeterTest]
Meter=String
MeasureName=MeasureLongTime
MeasureName2=MeasureLongDate
FontColor=255,255,255
SolidColor=0,0,0
Text="It is %1 on %2."
I threw extra code in the example if you prefer using variables instead of measures, but the result is equivalent. (If you are wondering about the weird "@" substitutions, you can get into cases where the substitutions don't work properly if you try straight-up replacements, so I first change the values to an unused character [I chose "@"], then do substitutions on that character.)
Note that I said "almost guaranteed (but not 100% guaranteed)"... Turns out that some of the registry formatting settings might not be correct if the user decides to override the formats with something odd, like using "~" or something goofy as a separator. If you care enough to want to handle edge cases, then you can grab the registry key values for "iDate" and "iTime" which are integer values that describe the format, along with "sDate" and "sTime" which are the separators, and "iLZero" which tells you if the user wants leading zeros, then use all these values to reconstruct the entire format string yourself, ignoring the formatting strings in the registry. It's additional work, but you only have to do it once...