Ha dátumokkal és időpontokkal kell dolgozni, akkor igénybe vehetjük a szabványos könyvtár datetime modulját. Feladat lehet olykor, hogy a dátum és időpontokat vagy azok bizonyos részeit egy előre meghatározott struktúrájú karakterláncban kell megjeleníteni. Ilyenkor a datetime modul date, time vagy datetime osztálypéldányokra meghívott strftime() metódussal célt érhetünk. A karakterláncban az egyes dátum- és időkomponenseket formátumkódok elhelyezésével jeleníthetjük meg a kívánt pozíciókban. Az érvényes formátumkódok és jelentésük a Python hivatalos dokumentációjában a datetime modul leírásában megtalálhatók. Azonban a gyakorlatban általában fordított módon merül fel a kérdés: egy megjelenítendő időkomponenshez milyen formátumkód tartozik. Az így rendezett táblázatot a Python tudásépítés lépésről lépésre című e-könyv „Mikor, hol hány óra? – dátum, napi idő és időzónák” alfejezetének „Dátum és idő egyéni formátumú karakterlánc reprezentációja” címe alatt találjuk.
Meglehetősen sok formátumkód áll rendelkezésre az egyedi karakterlánc kialakításához, ami hasznos, viszont a % jelet követő, egykarakteres, többségében kis- vagy nagybetűt tartalmazó kódokból sok esetben nem vagy csak nehezen lehet következtetni az általuk képviselt dátum- vagy időkomponensre. Ez azt jelenti, hogy – ha csak nem mindennapos gyakorlatunk e kódok alkalmazása – a használatuk nehézkes lehet, és később az ilyen kódokkal teletűzdelt karakterlánc olvasása és értelmezése sem lesz egyszerű.
Ezen a kényelmetlenségen úgy lehetne segíteni, ha a kódok helyett a dátum- vagy időkomponensre utaló kifejező nevekkel tudnánk dolgozni. Például ahelyett, hogy ki kellene keresni, vagy megjegyezni, hogy a %B a hónap teljes nevét a %b a hónap rövidített nevét fogja eredményezni, írhatnánk, hogy „month_name_full”, illetve „month_name_abbrev”, vagy például a %x és %X helyett, amelyek az aktuális nyelvterületi beállításnak megfelelő dátum és idő reprezentációkat jelentik, írhatnánk a sokkal kifejezőbb „date”, illetve „time” neveket.
Ezt a célt nem is olyan nehéz megvalósítani, ráadásul több módon is megtehetjük.
Először is, készítsünk egy olyan szótárt, amelyben az egyes dátum- és időkomponensekre utaló kifejező nevek a kulcsok, és a hozzájuk tartozó értékek a megfelelő formátumkódok:
|
1 2 3 4 5 6 7 8 9 |
names_formatcodes = {'year_2d': '%y', 'year_4d': '%Y', 'year_4d_iso': '%G', 'month_name_full': '%B', 'month_name_abbrev': '%b', 'month_2d': '%m', 'week_2d_sun': '%U', 'week_2d_mon': '%W', 'week_2d_iso': '%V', 'day_1d_sun': '%w', 'day_1d_mon': '%u', 'day_name_full': '%A', 'day_name_abbrev': '%a', 'day_of_the_month_2d': '%d', 'day_of_the_year_3d': '%j', 'hour_2d_12': '%I', 'hour_2d_24': '%H', 'minute_2d': '%M', 'second_2d': '%S', 'microsecond_6d': '%f', 'am_pm': '%p', 'percent': '%%', 'date': '%x', 'time': '%X', 'date_and_time': '%c', 'utc_offset': '%z', 'timezone_name': '%Z'} |
A nevekben olykor szereplő 2d, 3d, 4d és 6d jelöli, hogy hány decimális számjeggyel van az adott érték megjelenítve. Pl. a year_4d azt jelenti, hogy az évszám 4 jeggyel lesz látható. Természetesen az itt látható nevek helyett másokat is alkothatunk magunknak; olyanokat, amelyek számunkra a legjobban kifejezők.
Bár már ezt a szótárt is használhatnánk pl. formázott karakterlánc-literálban (f-string), de még elég sokat kellene gépelni egy-egy komponens beszúrásához, így ez még nem adja a várt kényelmet. E helyett alakítsuk át a nevek és formátumkódok megfeleltetését mezőnevekké, illetve attribútumnevekké, amit namedtuple vagy adatosztály (dataclass) alkalmazásával érhetünk el. Elvben az Enum felsorolástípus is szóba jöhet még mint megoldás, de ennek hátránya, hogy a szimbolikus név után, még a value attribútumot is ki kell írni, hiszen csak akkor kapjuk meg a felsorolástag mögöttes értékét. Viszont a Python 3.11 verziótól rendelkezésre áll a StrEnum felsorolástípus is, amely használata esetén nem kell a value attribútum értékét kikérni. A típusok létrehozásánál az előbb készített szótárunkat fel tudjuk használni a konstruktorkifejezésekben.
Az egyes megoldásokat és használatukat mutatják a következő kódsorok.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
from collections import namedtuple from dataclasses import make_dataclass from enum import Enum, StrEnum import locale from datetime import date, time, datetime names_formatcodes = {'year_2d': '%y', 'year_4d': '%Y', 'year_4d_iso': '%G', 'month_name_full': '%B', 'month_name_abbrev': '%b', 'month_2d': '%m', 'week_2d_sun': '%U', 'week_2d_mon': '%W', 'week_2d_iso': '%V', 'day_1d_sun': '%w', 'day_1d_mon': '%u', 'day_name_full': '%A', 'day_name_abbrev': '%a', 'day_of_the_month_2d': '%d', 'day_of_the_year_3d': '%j', 'hour_2d_12': '%I', 'hour_2d_24': '%H', 'minute_2d': '%M', 'second_2d': '%S', 'microsecond_6d': '%f', 'am_pm': '%p', 'percent': '%%', 'date': '%x', 'time': '%X', 'date_and_time': '%c', 'utc_offset': '%z', 'timezone_name': '%Z'} # Megoldás namedtuple létrehozásával. FormatCodes1 = namedtuple('FormatCodes1', names_formatcodes.keys(), defaults=names_formatcodes.values()) fc1 = FormatCodes1() # Megoldás adatosztály létrehozásával. FormatCodes2 = make_dataclass('FormatCodes2', names_formatcodes.keys(), namespace=names_formatcodes) fc2 = FormatCodes2() # Megoldás Enum felsorolástípus létrehozásával. FormatCodes3 = Enum('FormatCodes3', names_formatcodes) fc3 = FormatCodes3 # Megoldás StrEnum felsorolástípus létrehozásával. Python 3.11+ szükséges. FormatCodes4 = StrEnum('FormatCodes4', names_formatcodes) fc4 = FormatCodes4 # TESZT # A nyelvterület szerinti dátum és idő megjelenítés beállítása. locale.setlocale(locale.LC_TIME, 'hu_HU') # Dátumot és időpontot leíró objektum létrehozása. dati = datetime(2019, 6, 17, 10, 45, 11, 789) print(dati) # Eredmény: 2019-06-17 10:45:11.000789 # A dátum és idő bizonyos komponenseinek megjelenítése egy adott felépítésű karakterláncban formátumkódokkal. txt0 = 'A találka időpontja %Y. %B %d. %A %p %I óra.' print(dati.strftime(txt0)) # Eredmény: A találka időpontja 2019. június 17. hétfő de. 10 óra. # Megjelenítés namedtuple mezőnevekkel. txt1 = f'A találka időpontja {fc1.year_4d}. {fc1.month_name_full} {fc1.day_of_the_month_2d}. {fc1.day_name_full} {fc1.am_pm} {fc1.hour_2d_12} óra.' print(dati.strftime(txt1)) # Eredmény: A találka időpontja 2019. június 17. hétfő de. 10 óra. # Megjelenítés adatosztály attribútumneveivel. txt2 = 'A találka időpontja {0.year_4d}. {0.month_name_full} {0.day_of_the_month_2d}. {0.day_name_full} {0.am_pm} {0.hour_2d_12} óra.'.format(fc2) print(dati.strftime(txt2)) # Eredmény: A találka időpontja 2019. június 17. hétfő de. 10 óra. # Megjelenítés az Enum felsorolás tagjainak értékeivel. txt3 = f'A találka időpontja {fc3.year_4d.value}. {fc3.month_name_full.value} {fc3.day_of_the_month_2d.value}. {fc3.day_name_full.value} ' \ f'{fc3.am_pm.value} {fc3.hour_2d_12.value} óra.' print(dati.strftime(txt3)) # Eredmény: A találka időpontja 2019. június 17. hétfő de. 10 óra. # Megjelenítés a StrEnum felsorolás tagjainak értékeivel. Python 3.11+ szükséges. txt4 = f'A találka időpontja {fc4.year_4d}. {fc4.month_name_full} {fc4.day_of_the_month_2d}. {fc4.day_name_full} ' \ f'{fc4.am_pm} {fc4.hour_2d_12} óra.' print(dati.strftime(txt4)) # Eredmény: A találka időpontja 2019. június 17. hétfő de. 10 óra. |
Az egyedi kialakítású karakterláncban a dátum- és időkomponensekre utaló kifejező neveket kevés gépeléssel, attribútumhivatkozásként, azaz a . (pont) operátort használva, tudjuk beilleszteni, aminek előnye még, hogy a fejlettebb kódszerkesztők automatikus kód kiegészítő funkciója (code completion) a lehetséges neveket fel is tudja kínálni.
Itt azt is összevethetjük, hogy mennyivel változott a kód olvashatósága ahhoz képest, mint amikor a karakterláncban expliciten a formátumkódokat illesztettük be.
E bejegyzésben szereplő nyelvi elemekről a Python tudásépítés lépésről lépésre című e-könyv következő részeiben olvashatunk részleteiben: „Készétel fogyasztás – a szabványos könyvtár moduljainak használata” fejezet „Mikor, hol hány óra? – dátum, napi idő és időzónák”, „Nemzetközi vizeken – helyben szokásos adatformátumok kezelése” és „Speciális konténer típusok” alfejezetek, valamint a „Különleges osztálydefiníciók” fejezet „Felsorolástípus” és „Adatosztályok” alfejezete.