Aki webáruházat üzemeltet és raktároz, befektet áruk raktározásába, biztosan folyamatosan követi a raktárkészlet (és egyúttal pénzügyei) alakulását különböző lekérdezésekkel. Aki online marketinggel foglalkozik, szintén mérheti/követheti/összevetheti egy-egy reklámkampány eszközeinek (Facebook hirdetés, Google Ads hirdetés, e-mail marketing, Instagram hirdetés, blog) eredményességét, hatékonyságát. Az adatok elemzése mindenképpen része a tervezésnek és folyamatosnak/periodikusnak kell lennie.
Tipikus felmerülő kérdések/problémák
- Hány offline és/vagy online vásárlás/tranzakció volt eddig az aktuális hónapban?
- Hogyan változott a raktárkészlet az előző hónapban? Miből kell utánrendelni? Mik a kifutó termékek?
- A bevétel milyen arányban érkezett offline vagy online vásárlásból az aktuális hónapban?
- Kik vásároltak az előző negyedévben nyomtatót? Küldjünk nekik e-mailt arról, most 10%-kal olcsóbban rendelhetnek tonert, ha kettőt vesznek!
- Milyen értékben adtak le rendelést a webáruházban két adott dátum által megadott napon? Például hogyan alakult az utóbbi két Black Friday? Esetleg GLAMOUR-napok, húsvét, hosszú hétvége…
- Kik azok a rendszeres visszatérő vásárlóink, akik nem vásároltak az előző hónapban?
- Hogyan alakultak „a számok” az előző két év 3. negyedévében!
Egy webáruház raktárkészletének és számláinak nyilvántartása biztosan adatbázisban tárolódik, így könnyen megfogalmazható SQL lekérdező parancsok segíthetik a fenti kérdésekre/problémákra való válaszadást. Természetesen ezeket a műveleteket okosan ki kell vezetni a felhasználói felületre, hogy könnyen paraméterezhetők legyenek.
Lássunk néhány megoldást! A Java forráskódokból azokat a részeket mutatjuk be, amelyek egy lekérdező parancsba beágyazható dátumokra vonatkozó feltételeket kiírják. A dátumok megjelenítésére rövid formátumot használunk konstansként: SimpleDateFormat SHORT_DATE=new SimpleDateFormat("yyyy-MM-dd");.
Aktuális hónap
Érdemes készíteni két túlterhelt metódust. A paraméter nélküli változat az aktuális napot, a paraméteres változat a megadott napot tekinti maximálisnak és ehhez adja meg az adott hónap első/minimális napját. A két dátumnál az év és hónap megegyezik, a nap többnyire különbözik (ritkán megegyezik). A maxDate nem lehet jövőbeli és teljesül a minDate<=maxDate feltétel.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private void previousMonth() { previousMonth(new GregorianCalendar()); } private void currentMonth(GregorianCalendar date) { String maxDate=SHORT_DATE.format(date.getTime()); System.out.print(maxDate+" -> "); int year=date.get(Calendar.YEAR); int month=date.get(Calendar.MONTH); int day=1; GregorianCalendar currentMonthStartDay= new GregorianCalendar(year, month, day); String minDate=SHORT_DATE.format(currentMonthStartDay.getTime()); System.out.println("DATE BETWEEN '"+minDate+"' AND '"+maxDate+"'"); } |
Előző hónap
Itt is érdemes készíteni két túlterhelt metódust. A paraméter nélküli változat az aktuális napot, a paraméteres változat a megadott napot tekinti kiinduló napnak, és ehhez adja meg az előző hónap első és utolsó napját. A két dátumnál az év és hónap megegyezik, a nap mindig különbözik. Mindkét dátum múltbeli és teljesül a minDate<maxDate feltétel. A megvalósítás kezeli az eltérő hosszúságú hónapokat és a szökőévet is. Ha a kiinduló dátum az adott év első hónapjába esik, akkor az előző hónap az előző év utolsó hónapja (ez most automatikusan teljesül, külön nem kell rá figyelni). Hasznos a dátumobjektum add() metódusa, ami az első paraméterében megadott dátummező alapján a második paraméterében megadott értékkel tudja változtatni a dátumot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
private void previousMonth() { previousMonth(new GregorianCalendar()); } private void previousMonth(GregorianCalendar date) { System.out.print(SHORT_DATE.format(date.getTime())+" -> "); date.add(Calendar.MONTH, -1); //előző hónap int year=date.get(Calendar.YEAR); int month=date.get(Calendar.MONTH); int minDay=1; int maxDay=date.getActualMaximum(Calendar.DAY_OF_MONTH); String minDate=SHORT_DATE.format( new GregorianCalendar(year, month, minDay).getTime()); String maxDate=SHORT_DATE.format( new GregorianCalendar(year, month, maxDay).getTime()); System.out.println("DATE BETWEEN '"+minDate+"' AND '"+maxDate+"'"); } |
Előző negyedév
Itt is hasznos lehet a két túlterhelt metódus. A paraméter nélküli változat az aktuális napot, a paraméteres változat a megadott napot tekinti kiinduló napnak, és ehhez adja meg az előző negyedév első hónapjának első napját és az előző negyedév utolsó hónapjának utolsó napját. A két dátumnál az év megegyezik, a hónap és a nap mindig különbözik. Mindkét dátum múltbeli és teljesül a minDate<maxDate feltétel. A megvalósítás kezeli az eltérő hosszúságú hónapokat. A szökőév most nem számít. Ha a kiinduló dátum az adott év első negyedévébe esik, akkor az előző negyedév az előző év utolsó negyedéve (erre most külön figyelni kell). A negyedév ( quarter) képletén látszik, hogy épít arra, hogy a dátumobjektumtól elkért hónap ( month) 0 bázisú.
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 |
private void previousQuarter() { previousQuarter(new GregorianCalendar()); } private void previousQuarter(GregorianCalendar date) { System.out.print(SHORT_DATE.format(date.getTime())+" -> "); int year=date.get(Calendar.YEAR); int month=date.get(Calendar.MONTH); //0-11 int quarter=month/3+1 if(quarter==1) { year--; quarter=4; } else quarter--; //negyedév első hónapjának 1. napja int minMonth=(quarter-1)*3; int minDay=1; GregorianCalendar min=new GregorianCalendar(year, minMonth, minDay); String minDate=SHORT_DATE.format(min.getTime()); //negyedév utolsó hónapjának utolsó napja int maxMonth=minMonth+2; min.add(Calendar.MONTH, 2); int maxDay=min.getActualMaximum(Calendar.DAY_OF_MONTH); GregorianCalendar max=new GregorianCalendar(year, maxMonth, maxDay); String maxDate=SHORT_DATE.format(max.getTime()); System.out.println("DATE BETWEEN '"+minDate+"' AND '"+maxDate+"'"); } |
Eredmény
A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.
A feladat a Java SE szoftverfejlesztő tanfolyam 21-24. óra: Objektumorientált programozás, 2. rész kapcsolódik alapvetően, de a két visszakapott dátum használható több programozási tétellel (kiválogatás, szétválogatás) tömbbel, lambda kifejezésekkel kollekciókkal, SQL lekérdező parancsban adatbázis-kezeléshez kötődően.
Véleményem szerint a dátumkezelésnél sok hiba lehetőség fent áll. Sok mindenre kell összpontosítani a programozás során. Alapos munkát igényel. Én Java nyelven leprogramoztam, sokat tanultam belőle.
Tesztelés szempontjából lehetne készíteni egy olyan metódust az előző hónap, vagy előző negyedév lekérdezéséhez, amely String típusú paramétert vár, és azt parsolja dátummá.
Ez a dátumkezelés összeépíthető a tagadós lekérdezésekkel:
https://it-tanfolyam.hu/tagados-lekerdezesek/
Például egy webáruház üzemeltetőjében július 1-jén felmerül a kérdés:
Mi azon ügyfeleink e-mailcíme, akik az elmúlt negyedévben nem rendeltek? Értesítsük őket hírlevélben az aktuális akciós termékekről! Ezzel növelhető a nyári, egyébként is uborkaszezonos forgalom.
Az órai Oracle gyakorlat után végigpróbálgattam ezeket a dátumos feladatokat Access-ben és MySQL-ben. Óriási győzelem volt megharcolni a különböző dátum formátumokkal. Most webes klienst írok, ami alatt AB van és azzal is megpróbálom összehozni. Megfogadom Péter tanácsát: figyelek a mindenféle beállítás együttállására.
András: köszi. Meg fog térülni, hogy hallgatsz rám.
Azért hibázz is, hogy jöjjön szembe néhány hiba, kivétel, hogy azért találkozz velük. 😉
Péter: időzónás dátumidőt hogyan érdemes kezelni?
Java 11-től ezeket is használhatod Dani:
Instant
,ZoneId
,ZonedDateTime
, vagy alkalmasak aorg.joda.time
csomag osztályai, interfészei, konstansai is.