|
1 | 1 | """
|
2 | 2 | Test output formatting for Series/DataFrame, including to_string & reprs
|
3 | 3 | """
|
4 |
| -from datetime import datetime |
| 4 | +from contextlib import nullcontext |
| 5 | +from datetime import ( |
| 6 | + datetime, |
| 7 | + time, |
| 8 | +) |
5 | 9 | from io import StringIO
|
6 | 10 | import itertools
|
| 11 | +import locale |
7 | 12 | from operator import methodcaller
|
8 | 13 | import os
|
9 | 14 | from pathlib import Path
|
|
46 | 51 | use_32bit_repr = is_platform_windows() or not IS64
|
47 | 52 |
|
48 | 53 |
|
| 54 | +def get_local_am_pm(): |
| 55 | + """Return the AM and PM strings returned by strftime in current locale.""" |
| 56 | + am_local = time(1).strftime("%p") |
| 57 | + pm_local = time(13).strftime("%p") |
| 58 | + return am_local, pm_local |
| 59 | + |
| 60 | + |
49 | 61 | @pytest.fixture(params=["string", "pathlike", "buffer"])
|
50 | 62 | def filepath_or_buffer_id(request):
|
51 | 63 | """
|
@@ -3219,6 +3231,67 @@ def test_period_tz(self):
|
3219 | 3231 | per = dt.to_period(freq="H")
|
3220 | 3232 | assert per.format()[0] == "2013-01-01 00:00"
|
3221 | 3233 |
|
| 3234 | + @pytest.mark.parametrize( |
| 3235 | + "locale_str", |
| 3236 | + [ |
| 3237 | + pytest.param(None, id=str(locale.getlocale())), |
| 3238 | + "it_IT.utf8", |
| 3239 | + "it_IT", # Note: encoding will be 'ISO8859-1' |
| 3240 | + "zh_CN.utf8", |
| 3241 | + "zh_CN", # Note: encoding will be 'gb2312' |
| 3242 | + ], |
| 3243 | + ) |
| 3244 | + def test_period_non_ascii_fmt(self, locale_str): |
| 3245 | + # GH#46468 non-ascii char in input format string leads to wrong output |
| 3246 | + |
| 3247 | + # Skip if locale cannot be set |
| 3248 | + if locale_str is not None and not tm.can_set_locale(locale_str, locale.LC_ALL): |
| 3249 | + pytest.skip(f"Skipping as locale '{locale_str}' cannot be set on host.") |
| 3250 | + |
| 3251 | + # Change locale temporarily for this test. |
| 3252 | + with tm.set_locale(locale_str, locale.LC_ALL) if locale_str else nullcontext(): |
| 3253 | + # Scalar |
| 3254 | + per = pd.Period("2018-03-11 13:00", freq="H") |
| 3255 | + assert per.strftime("%y é") == "18 é" |
| 3256 | + |
| 3257 | + # Index |
| 3258 | + per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h") |
| 3259 | + formatted = per.format(date_format="%y é") |
| 3260 | + assert formatted[0] == "03 é" |
| 3261 | + assert formatted[1] == "03 é" |
| 3262 | + |
| 3263 | + @pytest.mark.parametrize( |
| 3264 | + "locale_str", |
| 3265 | + [ |
| 3266 | + pytest.param(None, id=str(locale.getlocale())), |
| 3267 | + "it_IT.utf8", |
| 3268 | + "it_IT", # Note: encoding will be 'ISO8859-1' |
| 3269 | + "zh_CN.utf8", |
| 3270 | + "zh_CN", # Note: encoding will be 'gb2312' |
| 3271 | + ], |
| 3272 | + ) |
| 3273 | + def test_period_custom_locale_directive(self, locale_str): |
| 3274 | + # GH#46319 locale-specific directive leads to non-utf8 c strftime char* result |
| 3275 | + |
| 3276 | + # Skip if locale cannot be set |
| 3277 | + if locale_str is not None and not tm.can_set_locale(locale_str, locale.LC_ALL): |
| 3278 | + pytest.skip(f"Skipping as locale '{locale_str}' cannot be set on host.") |
| 3279 | + |
| 3280 | + # Change locale temporarily for this test. |
| 3281 | + with tm.set_locale(locale_str, locale.LC_ALL) if locale_str else nullcontext(): |
| 3282 | + # Get locale-specific reference |
| 3283 | + am_local, pm_local = get_local_am_pm() |
| 3284 | + |
| 3285 | + # Scalar |
| 3286 | + per = pd.Period("2018-03-11 13:00", freq="H") |
| 3287 | + assert per.strftime("%p") == pm_local |
| 3288 | + |
| 3289 | + # Index |
| 3290 | + per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h") |
| 3291 | + formatted = per.format(date_format="%y %I:%M:%S%p") |
| 3292 | + assert formatted[0] == f"03 01:00:00{am_local}" |
| 3293 | + assert formatted[1] == f"03 01:00:00{pm_local}" |
| 3294 | + |
3222 | 3295 |
|
3223 | 3296 | class TestDatetimeIndexFormat:
|
3224 | 3297 | def test_datetime(self):
|
|
0 commit comments