Kurzusok
/
R
R
/
Feladatok
/
Időpontfoglalás szépségszalonba
Időpontfoglalás szépségszalonba

Időpontfoglalás szépségszalonba

Tanulófeladat

Bevezetés

„A dátumokat és időpontokat már kisgyerekeknek is megtanítjuk. Ugyan mi benne a nehéz?”

Sok programozó elkövette már ezt a hibát, és az ezt követő tapasztalat jellemzően rossz hatással van az egészségükre és a boldogságukra.

Aki nem triviális programozást végez dátumokkal és időkkel, az legalább legyen felkészülve arra, hogy megértse és mérsékelje a lehetséges problémákat.

Ez a dokumentum megpróbál áttekintést adni arról, hogyan kezeli az R a dátumokat és az időket, de a további részletekhez a teljes dokumentációt kell tanulmányoznod.

Adattudományi nyelvként az R-ben különös jelentőséggel bírnak a dátumok és az időpontok. Az adatok nagy része idősor formájában érkezik: a betegek napi száma egy járvány idején, a kormányok által jelentett havi foglalkoztatási adatok, madárpopulációk egy fészkelőtelepen, a jelentős gazdaságok éves GDP-je és végtelen sok további példa.

Ez azt jelenti, hogy az R egyszerűvé teszi a dátum- és időkezelést?

Sajnos nem!

A Base R dátum- és időkezelési funkcióinak rossz a hírük, és a legtöbbjüket ma már ritkán használják.

A lubridate csomag nagy előrelépés, de készülj fel egy nagy és bonyolult könyvtárra, amelyet problémák széles és bonyolult körének kezelésére terveztek.

A lubridate eredetileg önálló volt, ma már a tidyverse gyűjtemény része. Töltsd be a library(lubridate) vagy a library(tidyverse) utasítással.

Ha segítségre van szükséged a lubridate használatához, ezek a források segíthetnek:

Dátumok és dátum-idők

A date csupán egy nap, időinformáció nélkül.

Belsőleg a dátumokat az 1970-01-01 óta eltelt napok (előjeles) számaként tárolja.

today()
#> [1] "2026-04-22"

A datetime a dátumot, az időt és az időzónát egyesíti.

Belsőleg az 1970 eleje óta eltelt másodpercek számaként tárolja, UTC időzónában.

now()
#> [1] "2026-04-22 15:37:11 MST"  # mid-afternoon in Arizona

Talán meglepő, de az R-nek nincs belső reprezentációja a csak időt tartalmazó értékekre.

Munka date és datetime értékekkel

A leggyakoribb dátum- és időkezelési igények talán ezek:

  • Egy megfelelő bemeneti formátum beolvasása dátum vagy dátum-idő létrehozásához.
  • A szükséges numerikus vagy string formátum kinyerése egy dátumból vagy dátum-időből.
  • Eltolás alkalmazása egy dátumra vagy dátum-idő értékre.
  • Két ilyen érték közötti időtartam kiszámítása.
  • Az aktuális dátum (a today() segítségével) és/vagy dátum-idő (a now() segítségével) lekérdezése.

Beolvasás stringekből

Sokféleképpen írhatjuk le a dátumokat és időket, és ezek általában kultúrafüggők. A csupa számból álló dátumok, mint a „7/6/23”, kétértelműek, zavaróak, és számos költséges hibához vezettek multinacionális szervezeteknél (a szerző ezt keserű személyes tapasztalatból mondja).

A nemzetközi szabványt (y-m-d) az ISO 8601 definiálja, két fő előnnyel:

  • A beolvasás gyors és egyértelmű.
  • A rendezés egyszerű, mert a dátum-idő kezelhető normál szövegként és rendezhető ábécésorrendben.

Az adattudomány viszont arról szól, hogy bármilyen adattal dolgozunk, amit csak találunk, és gyakran értelmetlen azon panaszkodni, hogy mások hogyan formázzák.

A Base R rendelkezik konverziós függvényekkel, amelyek formátum stringet fogadnak (alapértelmezésben ISO 8601).

as.Date("2026-04-22")
#> [1] "2026-04-22"
as.Date("4/22/26", format = "%m/%d/%y")
#> [1] "2026-04-22"
as.POSIXct("2026-04-22 15:30:09 MST")
#> [1] "2026-04-22 15:30:09 MST"

A formátum stringek az évtizedek óta létező strptime() függvényre hasonlítanak, amelyet sok nyelv tartalmaz. Az e szintaxist ismerő programozók opcionálisan használhatják a lubridate fast_strptime() függvényét.

Még hasznosabb, hogy a lubridate rengeteg segédfüggvényt kínál, amelyeknek a neve a mezők sorrendjét tükrözi. Amint a függvények tudják, mely értékeket keressék és milyen sorrendben, a beolvasás lenyűgözően rugalmas.

mdy("4/22/26")
#> [1] "2026-04-22"
mdy("April 22nd 26")
#> [1] "2026-04-22"
mdy("Wednesday, April 22nd 2026")
#> [1] "2026-04-22"
mdy_hm("Wednesday, April 22nd 2026, 4:14 pm")
#> [1] "2026-04-22 16:14:00 UTC"  # defaults to your OS timezone

Létrehozás numerikus értékekből

Ha a programodban egy dátum/dátum-idő összetevői külön számokként vannak jelen, akkor azokat a make_date() vagy make_datetime() függvénnyel állíthatod össze.

Ezek azok az összetevők, amelyek megadhatók, a sorrendjükkel és az alapértelmezett értékeikkel:

make_datetime(
  year = 1970L,
  month = 1L,
  day = 1L,
  hour = 0L,
  min = 0L,
  sec = 0,
  tz = "UTC"
)
#> [1] "1970-01-01 UTC"


make_datetime(2026, 4, 22, 17)
#> [1] "2026-04-22 17:00:00 UTC"

Természetesen a make_date() csak év, hónap és nap argumentumokat fogad.

Kiírás ember által olvasható formában

Az R konzol a dátumokat/dátum-időket automatikusan string reprezentációként jeleníti meg. Ez általában kényelmes, de néha megtévesztő.

Belsőleg a dátumok és dátum-idők számok (néhány attribútummal kiegészítve), nem stringek. Ha dátumot (vagy dátum-időt) adunk vissza ott, ahol stringet várnak, az problémákat okoz, ezért tudnunk kell, hogyan végezzük el az átalakítást.

Egy egyszerű megközelítés a Base R as.character() függvényének használata, amely ISO 8601 formátumú stringet ad vissza.

Van továbbá egy format_ISO8601() függvény a dátum-időkhöz, amely lehetőséget kínál a kívánt pontosságra való kerekítésre.

today() |> as.character()  # a date
#> [1] "2026-04-23"
now() |> as.character()  # a datetime
#> [1] "2026-04-23 09:07:09.779319"
now() |> format_ISO8601() # defaults to nearest second
#> [1] "2026-04-23T09:07:38"

Kevés nem programozó akar ISO 8601 formátumú kimenetet látni, ezért elengedhetetlen a kultúraspecifikus dátum- és időformátumok kezelése.

A Base R biztosítja a format() függvényt, amely a sok más nyelvben megtalálható, tiszteletreméltó strftime() függvényekhez hasonló formátum stringeket használ.

format(today(), "%A, %d %B %Y")
#> [1] "Thursday, 23 April 2026"

Ez a Base R-es megközelítés csúnya, de megbízható. Íme néhány a leggyakoribb kódból:

Kód Eredmény
%d A hónap napjának száma (5, 17, 28, stb.)
%a A hét napjának rövidítése (Mon, Tue, Wed, stb.)
%A A hét napjának teljes neve (Monday, Tuesday, stb.)
%w A hét napjának száma (0-6, vasárnap a 0)
%u A hét napjának száma (1-7, hétfő az 1)
%b A hónap rövidítése (Jan, Feb, stb.)
%B A hónap teljes neve (January, February, stb.)
%y 2 jegyű év (pl. 89)
%Y 4 jegyű év (pl. 1989)
%h óra (24 órás formátum)
%m perc
%s másodperc
%z eltolás az UTC-től
%Z Időzóna (karakter)

A Lubridate egy emberbarátabb alternatívát kíván nyújtani a stamp() függvénnyel, valamint a szűkebb stamp_date() és stamp_time() függvényekkel.

Ezek egy sablon stringet fogadnak, amely a kívánt kimenet példája, és egy egyedi függvényt hoznak létre az adott formátum előállításához.

A Lubridate megpróbálja kitalálni a formátumot, de gyakran kétértelműségekbe ütközik és rossz eredményt ad. Légy felkészülve arra, hogy formátum stringeket (például "dmy") adj meg az egyértelműsítéshez.

Az Exercism-ön hasznos lehet a locale = "C" megadása is, hogy megkerüld a rendszer helyi beállításait és angolul dolgozz (ahogy a tesztek elvárják). A helyi beállítások bonyolultak!

sf <- stamp("Saturday, June 27, 2026 at 14:45", locale = "C")
#> Multiple formats matched: "%A, %B %d, %Y at %H:%M"(1), "Saturday, %Om %d, %Y at %H:%M"(1), "Saturday, %B %d, %Y at %H:%M"(1), "%A, %Om %d, %Y at %H:%M"(0)
#> Using: "%A, %B %d, %Y at %H:%M"

sf(make_datetime(2023, 3, 29, 15, 0, 0))
#> [1] "Wednesday, March 29, 2023 at 15:00"

Összetevők beállítása és kinyerése

A Lubridate számos függvényt kínál egy dátum vagy dátum-idő elemeinek lekérdezéséhez vagy beállításához: kézenfekvőket, mint a year() és a second(), de specialisabbakat is, mint a quarter() és az epiweek().

Mindegyik ilyen függvény használható érték lekérdezéséhez, és a legtöbbjük érték beállításához is.

dt <- now()
dt
#> [1] "2026-04-23 15:47:11 MST"

# get
month(dt)
#> [1] 4

# set
month(dt) <- 11
dt
#> [1] "2026-11-23 15:47:11 MST"

A wday() (a hét napja) és a month() esetében az alapértelmezett kimenet egész szám, de:

  • A labels = TRUE beállítása az aktuális helyi beállításnak megfelelő rövidített karakter stringet ad vissza.
  • Az abbr = FALSE beállítása ezenfelül a teljes nevet adja vissza.
d <- today()
d
#> [1] "2026-04-23"
wday(d)
#> [1] 5
wday(d, label = TRUE)
#> [1] Thu
#> Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat
wday(d, label = TRUE, abbr = FALSE)
#> [1] Thursday
#> Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < Friday < Saturday

A címkék categorical variables (kategorikus változók), amelyek egy másik fogalom témáját képezik majd. Az értékek a felsorolt Levels értékeire korlátozódnak, amelyek a rendezési sorrendet is mutatják.

A hét alapértelmezésben vasárnappal kezdődik, de ez a week_start argumentummal módosítható (használj 1-et a hétfőhöz).

dt <- make_datetime(2026, 4, 23)

# default behavior
wday(dt)
#> [1] 5
wday(dt, label = T)
#> [1] Thu

# set week_start to Monday
wday(dt, week_start = 1)
#> [1] 4

Néhány segédfüggvény TRUE/FALSE értéket ad vissza, például a leap_year() és a dst() (aktív-e a nyári időszámítás?).

A hónapok hossza változó, ezért a days_in_month() egész számként adja meg az értéket.

Időtartamok

A date és a datetime értékek egyaránt egy pillanatot jelölnek az idővonalon.

Hogyan kezeljük az olyan fogalmakat, mint „tegnap ilyenkor” vagy „egy hét múlva”?

A más, tudományos irányultságú nyelveket ismerő tanulók találkozhattak már a Python datetime.timedelta típusával vagy a Julia Period típusával.

Ezzel szemben az R-nek nem kevesebb, mint három módja van az időtartamok ábrázolására, eltérő erősségekkel és korlátokkal. Mint mindig, most is azt válaszd, amelyik a legjobban illik a helyzetedhez.

A különféle időtartamok könnyen átalakíthatók egymásba az as.period(), az as_duration() és az as.interval() függvénnyel.

Az időtartamtípusok lekérdezhetők az is.period() és hasonló függvényekkel.

Periódusok

Egy period, például a hours(3), 3 órával növelheti az óraidőt.

A szabálytalanságokat, például a nyári időszámítást (DST), nagyrészt figyelmen kívül hagyja.

Minden period egy egység többes számú neve: years, weeks, stb.

d <- today()
d
#> [1] "2026-04-25"

d + weeks(2)
#> [1] "2026-05-09"

# dates are coerced to datetimes at midnight if necessary
d - hours(20)
#> [1] "2026-04-24 04:00:00 UTC"

hours(3)
#> [1] "3H 0M 0S"

Durációk

Egy duration, például a dhours(3), 3 órával növeli a fizikai időt, figyelembe véve az olyan szabálytalanságokat, mint a DST, amelyek miatt az óraidő eltér a fizikai időtől.

Minden duration egy d előtagot ad a megfelelő period elé: dyears, dweeks, stb.

dhours(3)
#> [1] "10800s (~3 hours)"

Intervallumok

Egy interval egy kezdő- és egy záróidő kombinációja, amelyet akár az interval() függvénnyel, akár a %--% infix operátorral hozhatsz létre.

# the next 2 lines were run about 33s apart, so now() is different
dt1 <- now()
dt2 <- now() + hours(1)

# interval(0 function)
ivl <- interval(dt1, dt2)
ivl
#> [1] 2026-04-24 16:24:54 MST--2026-04-24 17:25:27 MST

# infix operator
iv2 <- dt1 %--% dt2
iv2 == iv1
#> [1] TRUE

Időzónák

Az időzónák kezelése kihívást jelenthet. Az alábbi idézet a Python dokumentációjából származik, de ugyanúgy érvényes az R-re is:

„Az időigazítás szabályai világszerte inkább politikaiak, mint racionálisak, gyakran változnak, és az UTC-n kívül nincs minden alkalmazáshoz megfelelő szabvány.”

Néhány általános megjegyzés az időzónákról:

  • A datetime mindig tartalmaz időzónát (tz); a date nem időzóna-tudatos.
  • A dátum-idő konstruktorok általában az UTC értéket használják alapértelmezésként.
  • A now() függvény kivétel: a rendszeróráról szerzi be a helyi idődet, a tz-t is beleértve. Alapértelmezésben a helyi tz-t használja, de megadhatók mások is, például now("UTC").
# timezone defaults to UTC
local <- ymd_hm("2026-04-25 10:32")
local
#> [1] "2026-04-25 10:32:00 UTC"

# timezone can be specified
AZ <- ymd_hm("2026-04-25 10:32", tz = "America/Phoenix")
AZ
#> [1] "2026-04-25 10:32:00 MST"

# same clocktime, different tz
local - AZ
#> Time difference of -7 hours

Az időzónákkal kapcsolatos aritmetika megbízhatóbb duration értékekkel, mint period értékekkel.

Összefoglalás

A dátumokkal és dátum-időkkel való munka általában sokkal könnyebb a lubridate-tel, mint a Base R-rel.

Ez a fogalom megpróbált áttekintést adni, de elkerülhetetlenül nagyon sok részletet kihagy.

Ismétlés kockázatát vállalva: a dokumentáció a barátod, használd bátran.

Utasítások

Ebben a feladatban egy New York-i szépségszalon időpont-ütemezőjén fogsz dolgozni, amely 2012. szeptember 15-én nyílt meg.

Öt részfeladat vár rád, és mindegyik az időpontok dátumaival foglalkozik. A időpontok 24 órás formátumban vannak (nincs AM/PM). Hogy az időzónákkal kapcsolatos problémák a lehető legegyszerűbbek legyenek, feltételezd, hogy minden UTC-t használ.

1. A csupa számból álló időpont értelmezése

Valósítsd meg a schedule_appointment() függvényt, amely egy időpont szöveges reprezentációját alakítja át a megfelelő DateTime formátumra.

Ügyelj arra, hogy a bemenet az amerikai hónap/nap/év sorrendet követi.

julia> schedule_appointment("07/25/2023 13:45:00")
2023-07-25T13:45:00

2. Annak ellenőrzése, hogy egy időpont már elmúlt-e

Valósítsd meg a has_passed() függvényt, amely egy időpontot kap, és ellenőrzi, hogy az időpont a múltban van-e:

julia> has_passed(DateTime(1999, 12, 31, 9, 0, 0))
true

3. Annak ellenőrzése, hogy az időpont délutánra esik-e

Valósítsd meg az is_afternoon_appointment() függvényt, amely egy időpontot kap, és ellenőrzi, hogy az délutánra esik-e (>= 12:00 és < 18:00):

julia> is_afternoon_appointment(DateTime(2023, 3, 29, 15, 0, 0))
true

4. Egy időpont hét napjának ellenőrzése

Valósítsd meg a day_of_week() függvényt, amely a hét napjának sorszámát adja vissza. A szalon vasárnap zárva tart, ezért a hétfő az 1. nap, a szombat pedig a 6.

# a Friday
day_of_week(make_datetime(2026, 06, 05, 12, 30, 00))
#> [1] 5

5. Időpont átütemezése

Ha egy vendég át szeretné tenni az időpontját, az automatikusan a következő péntekre kerül, ugyanabban az időpontban (mivel ez a hét leglassabb napja).

Valósítsd meg a reschedule() függvényt, amely az eredeti időpontot kapja meg (szöveges formában, hónap/nap/év sorrendben), és visszaadja az átütemezett időpontot.

# a Saturday
reschedule("06/13/2026 12:30:00")
#> [1] "2026-06-19 12:30:00 UTC"

Ha az eredeti időpont hétfő és csütörtök közé esett, akkor ezen a héten péntekre ütemezd át. Pénteki vagy szombati időpontok esetén a következő hét péntekjére ütemezd át.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
R Exercism

Készen állsz elkezdeni a(z) Időpontfoglalás szépségszalonba feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) R nyelvet 21 fogalom111 feladat segítségével, valódi emberi mentorálással, mindez ingyen.