Use AM/PM in timectrl.TimeCtrl (Windows)

The TimeCtrl example in the wxPython Demo has several instances of 12hr clock, do they show correctly on your windows machine?

I don’t know how they should look like but this is what the demo code looks like, I had to append the run.py module by the way.

EDIT: Well, if I am not mistaken, the 12-hour one is not displayed correctly.

Here’s what it looks like on my Linux PC:

Edit: replaced screen dump with one using time ‘now’ to make the differences a bit clearer:

1 Like

Well, evidently the same code behaves differently on the two platforms. Without needing to configure anything, in the 12 hour clock the AM is shown automatically and goes up to 12, as you could see in windows it had the same value as the 24 hour field.

Is there any important difference between TimeCtrl and TimePickerCtrl? I was looking at it and the am/pm displays and adjusts correctly, I would like to know if there is a workaround for TimeCtrl, but I think I will consider using TimePickerCtrl.

It is pretty unlikely that the “self.locale =” part is necessary.

Just “wx.Locale(wx.LANGUAGE_DEFAULT)” is likely going to init “the system”
to a default locale, and the date picker will pick that up.

(not that I recommend using wx.Locale(), but there…)

Karsten

I just tried using wx.Locale() without assigning it to an instance attribute and the date controls went back to using MM/DD/YYYY.

Hi, thanks for the clarification. Just for the record, I removed the variable assignment and put it in both __init__ and OnInit and nothing.

Yes, I had tried something like that in Ubuntu, but apparently (I don’t know) Windows doesn’t listen to wx.Locale

I have used print(locale.getlocale()) and get ('es_VE', 'ISO8859-1'), So I think the locale is well assigned.

Now that is very strange – the date controls are unlikely to
pick up a random instance attribute.

The theory would be that as long as the app holds on to the
attribute the wx.Locale() won’t get __del__eted … and if the
del contains a switch back to the “previous” locale …

One might test that theory by doing for once:

self.__some_random_123456 = wx.Locale(....)

and for another run doing

self.__some_random_123456 = wx.Locale(....)
del self.__some_random_123456

and see what happens in each case.

Karsten

Tried, nothing diferent happened.

class App(wx.App):
    def OnInit(self):
        self.__some_random_123456 = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA)
        del self.__some_random_123456
        frame = TimeFrame()
        frame.Show(True)
        return True

and

class App(wx.App):
    def OnInit(self):
        self.__some_random_123456 = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA)
        frame = TimeFrame()
        frame.Show(True)
        return True
class App(wx.App):
    def OnInit(self):
        self.__some_random_123456 = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA)
        del self.__some_random_123456
        frame = TimeFrame()
        frame.Show(True)
        return True

and

class App(wx.App):
    def OnInit(self):
        self.__some_random_123456 = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA)
        frame = TimeFrame()
        frame.Show(True)
        return True

That is what I suggested but

Tried, nothing diferent happened.

this does not sufficiently describe what happened in order to
test the theory I offered.

Karsten

I understand, but I don’t know what I can show, at the graphic level the control does not change and at the code level there is no error or warning.

Well, we’ve got 3 (4 (5)) ways the code can look

1
wx.Locale(…)

2
self.locale = wx.Locale(…)

3
self.__random_something = wx.Locale(…)

4
self.__random_something = wx.Locale(…)
del self.__random_something

Version 1 does not work, which rules out the
init-the-system-for-magic-pickup-later theory (much like it
used to be with InitAllImageFormats()).

Version 2 does work but we don’t know why.

So:
Version 3 and 4 do “the same” – but what ?

And, try this:

5
self.locale = wx.Locale(…)
del self.locale

Does it still work ?

This is 2 and 4 combined to find out whether self.locale is
either a magic attribute being picked up later or else is
being passed to the picker control down the line :wink:

(the latter assumption could be checked by perusing the code,
and it might throw a NameError – unless self.locale is
being initialzed to, say, None elsewhere…)

Karsten

When the last reference to the wx.Locale object is gone, and it’s destroyed, then the locale reverts to the setting that was in effect before the object was created.

Thus the self.locale = part is necessary, by design.

1 Like

Hi, Jalkhov

I tested your code on Windows 10 (JP) with Python 3.8.6 & wx 4.1.1 and It works on my PC if I added a few lines as follows (Please ignore check_locale):

import wx
import locale
from wx.lib.masked import TimeCtrl

## locale.setlocale(locale.LC_ALL, 'es_VE')
def check_locale():
    import time
    print(wx.GetLocale().Name)
    print(locale.getlocale(locale.LC_TIME))
    print(time.strftime('Now, %B %d %a %p %I:%M:%S'))
    try:
        wxdt = wx.DateTime.FromDMY(1, 0, 1970)
        print(wxdt.Format('%p'))
    except Exception:
        print('no support for am/pm')

class TimeFrame(wx.Frame):
    def __init__(self):
        
        wx.Frame.__init__(self, None, -1, 'TimeCtrl', wx.DefaultPosition, (200, 100))
        
        self.wxloc = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA) # keep refs
        ## locale.setlocale(locale.LC_ALL, 'es_VE') # a.m./p.m. doesn't work.
        locale.setlocale(locale.LC_ALL, 'C') # %p must be formatted as 'AM/PM'
        check_locale()
        
        self.time_ctrl = TimeCtrl(self, -1,
                                  displaySeconds=False,
                                  size=wx.DefaultSize,
                                  fmt24hr=False,
                                  validator=wx.DefaultValidator,
                                  style=wx.TE_PROCESS_TAB)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.time_ctrl, 0, 0, 0)
        self.SetSizer(sizer)
        self.Layout()

class App(wx.App):
    def OnInit(self):
        frame = TimeFrame()
        frame.Show(True)
        return True
        
if __name__ == "__main__":
    app = App(0)
    app.MainLoop()

Clipboard20

Reading the original code of wx.lib.masked.timectrl.TimeCtrl, the fmt24hr seems to be set True if wx.DateTime object doesn’t format ‘%p’ as ‘AM’ or ‘PM’. Thus, ‘C’ (CPython’s default?) or ‘en_US’ should be used for the locale.

1 Like

Excelent, this works perectly. One doubt, does it also matter where the lines are added?:

self.wxloc = wx.Locale(wx.LANGUAGE_SPANISH_VENEZUELA)
locale.setlocale(locale.LC_ALL, 'C')

In this case you have done it in the __init__ and not in the OnInit.

The point is before the TimeCtrl object is created.
Normally, wx.App.InitLocale is a better place.

see also:

2 Likes

Yes, I understand. Thank you very much, and thanks to the others who also contributed n.n Issue resolved.