Using PyXLL's cell formatting feature we can easily format dates returned from Python to Excel.
But, the date format is specified as an Excel "number format", for example "yyyy-mm-dd", and so is fixed and doesn't change based on the Excel user's system date/time settings or Excel locale settings.
To format a date that changes depending on the locale of the current user we need to use a "custom formatter" that will determine the correct number format that will show the date correctly for the user.
Writing a custom formatter
Writing a custom formatter simply needs us to declare a new class that derives from PyXLL's "Formatter" class.
Getting the right date format
We can get the date formatting information we need using Excel's Application.International property. To access this from Python we use PyXLL's "xl_app" function to get the Excel Application object.
Note: PyXLL's xl_app function can only be called from within an Excel macro. As the Formatter.apply method is called from an Excel macro it is safe to use it here.
The "International" property takes an argument, but in Python properties can never take an argument, so instead we use the "GetInternational" accessor method on the Python Application object.
The constants we need can be found in the win32com.client.constants package.
See https://www.pyxll.com/docs/userguide/vba.html for more information on these details about translating VBA code to Python.
Putting it all together
Now we know how to write a custom formatter, and how to get the number format string we need to format a cell as a date, we can put the two together:
Applying the custom formatter to a function
Our new custom formatter works in exactly the same way as the standard formatters and can be applied to a function using the "formatter" kwarg to the @xl_func decorator.
Formatters can also be combined by adding them together. For example, if you wanted to a formatter that would make the cell bold as well as applying date formatting you could do the following:
Extra Credit - caching the date format
We don't really need to create the date format each time the formatting is applied. An easy way to cache the result of our "get_date_format" function is to add the "functools.cache" decorator to it.
Now the format will be determined the first time this function is called, and subsequent calls with return the cached result.