PostgreSQLã§ã®ç¹°ãè¿ãã¹ã±ãžã¥ãŒã«ãšã¿ã€ã ãŸãŒã³: ãã¿ãŒã³
å®çšçãªä¿å圢åŒãåçºã«ãŒã«ãäŸå€ãããã³ã«ã¬ã³ããŒãæ£ããä¿ã€ã¯ãšãªãã¿ãŒã³ã䜿ã£ãŠãPostgreSQLã§ã®ç¹°ãè¿ãã¹ã±ãžã¥ãŒã«ãšã¿ã€ã ãŸãŒã³ãåŠã³ãŸãã

ã¿ã€ã ãŸãŒã³ãšç¹°ãè¿ãã€ãã³ããããŸããããªãçç±
å€ãã®ã«ã¬ã³ããŒãã°ã¯æ°åŠã®ééãã§ã¯ãªããæå³ã®ãºã¬ã§ããããªãã¯ãããã®ïŒæå»ã®ç¬éïŒãä¿åããŠãããããŠãŒã¶ãŒã¯å¥ã®ãã®ïŒç¹å®ã®å Žæã§ã®ããŒã«ã«ãªæèšæå»ïŒãæåŸ ããŸãããã®ã®ã£ããããç¹°ãè¿ãã¹ã±ãžã¥ãŒã«ãšã¿ã€ã ãŸãŒã³ããã¹ãã§ã¯æ£ããèŠããŠããå®éã®å©çšã§å£ããåå ã§ãã
倿éïŒDSTïŒã¯å žåçãªåŒãéã§ãããæ¯é±æ¥æ09:00ãã¯ãéå§ã¿ã€ã ã¹ã¿ã³ããã7æ¥ããšããšåãã§ã¯ãããŸããããªãã»ãããå€ãããšäž¡è ã¯1æéãããã«ã¬ã³ããŒã¯ãã€ã®ãŸã«ãééã£ãŠããŸããŸãã
æ è¡ãæ··åšã¿ã€ã ãŸãŒã³ã¯ããã«è€éåããŸããäºçŽãç©ççãªå ŽæïŒã·ã«ãŽã®ãµãã³ã®æ€ åïŒã«çµã³ã€ããŠããã®ã«ãé²èЧè ããã³ãã³ã«ãããšããŸããå ŽæããŒã¹ã®ã¹ã±ãžã¥ãŒã«ã人ããŒã¹ãšããŠæ±ããšãå°ãªããšãçæ¹ã«ééã£ãçŸå°æå»ã衚瀺ããŠããŸããŸãã
ãããã倱æãã¿ãŒã³:
- ä¿åããã¿ã€ã ã¹ã¿ã³ãã«ééãè¶³ããŠåçºçãçæããDST ãå€ããã
- ãŸãŒã³ã«ãŒã«ãªãã§ãããŒã«ã«æå»ããä¿åããæå³ããç¬éãåæ§ç¯ã§ããªãã
- DST å¢çããŸãããªãæ¥ä»ãããã¹ãããŠããªãã
- ã¯ãšãªå ã§ãã€ãã³ãã®ã¿ã€ã ãŸãŒã³ãããŠãŒã¶ãŒã®ã¿ã€ã ãŸãŒã³ãããµãŒããŒã®ã¿ã€ã ãŸãŒã³ããæ··åããŠããã
ã¹ããŒããéžã¶åã«ããæ£ããããšã¯äœãããããã¯ãã§æ±ºããŠãã ããã
äºçŽã®å Žåããæ£ãããã¯éåžžããã§ã: äŒå Žã®ã¿ã€ã ãŸãŒã³ã§æå³ããå£æèšæå»ã«ã¢ãã€ã³ãã¡ã³ããçºçããé²èЧè ã«ã¯æ£ãã倿ã衚瀺ãããããšã
ã·ããã®å Žåããæ£ãããã¯åºããšã«åºå®ã®çŸå°æå»ã§éå§ããããšïŒåŸæ¥å¡ãç§»åããŠããŠãåãïŒã§ããããšãå€ãã§ãã
ãã¹ã±ãžã¥ãŒã«ãå Žæã«çŽã¥ãããã人ã«çŽã¥ããããã®æ±ºå®ããä¿åããå 容ãåçºçã®çææ¹æ³ãã«ã¬ã³ããŒè¡šç€ºã®ã¯ãšãªèšèšãå·Šå³ããŸãã
æ£ããã¡ã³ã¿ã«ã¢ãã«ãéžã¶: ã€ã³ã¹ã¿ã³ã vs ããŒã«ã«æé
å€ãã®ãã°ã¯2ã€ã®ç°ãªãæéã®èãæ¹ãæ··åããããšããçããŸã:
- ã€ã³ã¹ã¿ã³ã: 絶察çãªç¬éã§ãäžåºŠã ãèµ·ããç¹ã
- ããŒã«ã«æéã«ãŒã«: ãããªã§æ¯é±ææ9:00ãã®ãããªå£æèšã®æå»ã
ã€ã³ã¹ã¿ã³ãã¯ã©ãã§ãåãã§ãã2026-03-10 14:00 UTC ã¯ã€ã³ã¹ã¿ã³ãã§ãããããªé話ããã©ã€ãã®åºçºãæ£ç¢ºãªç¬éã«éç¥ãéããšãã£ãçšéã¯éåžžã€ã³ã¹ã¿ã³ãã§ãã
ããŒã«ã«æéã¯å Žæã®æèšã§èªãæå»ã§ããEurope/Paris ã®æ¯å¹³æ¥ 9:00 ã®ãããªè¡šçŸã¯ããŒã«ã«æéã§ããåºèå¶æ¥æéã宿ã¯ã©ã¹ãã¹ã¿ããã·ããã¯éåžžãå Žæã®ã¿ã€ã ãŸãŒã³ã«çŽã¥ããŸããã¿ã€ã ãŸãŒã³ã¯è¡šç€ºã®å¥œã¿ã§ã¯ãªãæå³ã®äžéšã§ãã
åçŽãªã«ãŒã«:
- ã€ãã³ããäžçã§äžã€ã®å®éã®ç¬éãšããŠèµ·ããå¿
èŠããããªããéå§/çµäºã¯
timestamptzã§ä¿åããã - ã€ãã³ããããå Žæã®æèšã«åŸããªããããŒã«ã«ã®æ¥ä»ãšããŒã«ã«æå»ã«ãŸãŒã³IDãçµã¿åãããŠä¿åããã
- ãŠãŒã¶ãŒãç§»åãããªãã衚瀺æã«é²èЧè ã®ãŸãŒã³ã§èŠãã€ã€ãã¹ã±ãžã¥ãŒã«ã¯å ã®ãŸãŒã³ã«åºå®ããã
+02:00ã®ãããªãªãã»ãããããŸãŒã³ãæšæž¬ããªãããªãã»ãã㯠DST ã«ãŒã«ãå«ãŸãªãã
äŸ: ç
é¢ã®ã·ããã Mon-Fri 09:00-17:00 America/New_York ã§ããã°ãDST 倿Žé±ã§ãçŸå°ã§ã¯9æãã5æã®ãŸãŸã§ãUTC ã®ç¬éã1æéåãã®ã¯åé¡ã§ã¯ãããŸããã
PostgreSQL ã§éèŠãªåïŒé¿ããã¹ããã®å«ãïŒ
å€ãã®ã«ã¬ã³ããŒãã°ã¯èª€ã£ãã«ã©ã åããå§ãŸããŸããéèŠãªã®ã¯ãå®éã®ç¬éããšã壿èšã®æåŸ ããåé¢ããããšã§ãã
å®éã®ã€ã³ã¹ã¿ã³ãã«ã¯ timestamptz ã䜿ã£ãŠãã ãã: äºçŽãæå»ãéç¥ããŠãŒã¶ãŒãå°åãè¶ããŠæ¯èŒãããã®ã¯ããã§ããPostgreSQL ã¯ããã絶察æå»ãšããŠä¿åãã衚瀺æã«å€æãããããé åºãéè€ãã§ãã¯ãæåŸ
éãã«åããŸãã
ããŒã«ã«ãªå£æèšå€ã«ã¯ timestamp without time zone ã䜿ããŸãïŒåäœã§ã¯ã€ã³ã¹ã¿ã³ãã«ãªããªããã®ïŒãäŸ: ãæ¯é±ææ09:00ãããåºã¯10:00éåºãã®ãããªå€ãããã«ã¿ã€ã ãŸãŒã³èå¥åãçµã¿åãããçºçãçæãããšãã«å®éã®ã€ã³ã¹ã¿ã³ãã«å€æããŸãã
ç¹°ãè¿ããã¿ãŒã³ã§äŸ¿å©ãªåºæ¬å:
date: æ¥åäœã®äŸå€ïŒç¥æ¥ïŒtime: æ¥ããšã®éå§æå»interval: ç¶ç¶æéïŒäŸ: 6æéã·ããïŒ
ã¿ã€ã ãŸãŒã³ã¯ IANA åïŒäŸ: America/New_YorkïŒã text ã«ã©ã ïŒãŸãã¯å°ããªåç
§ããŒãã«ïŒã§ä¿åããŠãã ããã-0500 ã®ãããªãªãã»ããã ãã§ã¯ DST ã«ãŒã«ãå«ãŸãªãããäžååã§ãã
å€ãã®ã¢ããªã«ãšã£ãŠå®çšçãªã»ãã:
- äºçŽã®éå§/çµäºã€ã³ã¹ã¿ã³ã:
timestamptz - äŸå€æ¥ã¯
date - ç¹°ãè¿ãã®éå§æå»ã¯
time - ç¶ç¶æéã¯
interval - IANA ã¿ã€ã ãŸãŒã³IDã¯
text
äºçŽã»ã·ããã¢ããªåãã®ããŒã¿ã¢ãã«ãªãã·ã§ã³
æé©ãªã¹ããŒãã¯ã¹ã±ãžã¥ãŒã«ã®å€æŽé »åºŠãšãŠãŒã¶ãŒãã©ãã ãå ãåç §ãããã«ãããŸããäžè¬ã«ãäºåã«å€æ°ã®è¡ãæžã蟌ããã衚瀺æã«çæãããã®éžæã§ãã
ãªãã·ã§ã³ A: ãã¹ãŠã®çºçãä¿åãã
1è¡ã1ã·ããïŒ1äºçŽïŒå±éæžã¿ïŒã§æ¿å ¥ããŸããã¯ãšãªã¯ç°¡åã§èããããã§ãããã«ãŒã«å€æŽæã®æŽæ°ãå€ãæžã蟌ã¿ãå¢ããŸãã
ã€ãã³ããäžåºŠãããå€ãããŸãã¯å ã®æéãçãããçæããªãïŒäŸ: 次ã®30æ¥åïŒå Žåã«æå¹ã§ãã
ãªãã·ã§ã³ B: ã«ãŒã«ãä¿åããŠèªã¿åãæã«å±éãã
ãæ¯é±æã»æ°Ž09:00 America/New_Yorkãã®ãããªã¹ã±ãžã¥ãŒã«ã«ãŒã«ãä¿åããèŠæ±ãããç¯å²ã®çºçããªã³ããã³ãã§çæããŸãã
æè»ã§ã¹ãã¬ãŒãžå¹çã¯è¯ãã§ãããã¯ãšãªã¯è€éã«ãªãããããæè¡šç€ºãªã©ã¯ãã£ãã·ã¥ããªããšé ããªãåŸãŸãã
ãªãã·ã§ã³ C: ã«ãŒã«ïŒãã£ãã·ã¥ãããçºçïŒãã€ããªããïŒ
ã«ãŒã«ãçå®ã®ãœãŒã¹ãšããŠä¿æãã€ã€ãããŒãªã³ã°ãŠã£ã³ããŠïŒäŸ: 60ã90æ¥ïŒåã®çææžã¿çºçãä¿åããŸããã«ãŒã«ãå€ãã£ãããã£ãã·ã¥ãåçæããŸãã
ã·ããã¢ããªã®åŒ·åãªããã©ã«ãã§ã: æè¡šç€ºãéãããã¿ãŒã³ã®ç·šéã¯äžç®æã§æžã¿ãŸãã
å®è·µçãªããŒãã«çŸ€:
- schedule: owner/resourceãã¿ã€ã ãŸãŒã³ãããŒã«ã«éå§æå»ãç¶ç¶æéãåçºã«ãŒã«
- occurrence: å±éãããã€ã³ã¹ã¿ã³ã¹ã
start_at timestamptz,end_at timestamptzãã¹ããŒã¿ã¹ - exception: ããã®æ¥ã¯ã¹ãããããããã®æ¥ã¯ç°ãªããããŒã«ãŒ
- override: åã ã®çºçã«å¯Ÿããç·šéïŒéå§æå»å€æŽãã¹ã¿ããå ¥ãæ¿ãããã£ã³ã»ã«ãã©ã°ïŒ
- ïŒä»»æïŒschedule_cache_state: æåŸã«çæããç¯å²ãä¿æ
ã«ã¬ã³ããŒã¬ã³ãžã¯ãšãªã®ããã«ããã®ãŠã£ã³ããŠã®ãã¹ãŠãèŠãããçšéã§ã€ã³ããã¯ã¹ã貌ã:
- occurrence äž:
btree (resource_id, start_at)ãšéåžžbtree (resource_id, end_at) - ç¯å²éãªããããåãåããããªã:
tstzrange(start_at, end_at)ãçæåã«ããŠgistã€ã³ããã¯ã¹
è匱ã«ãªããªãåçºã«ãŒã«ã®è¡šçŸ
åçºã¹ã±ãžã¥ãŒã«ã¯ãã«ãŒã«ãå·§åŠããããæè»ãããããã¯ãšãªã§ããªããã€ããªã®å¡ïŒblobïŒãšããŠä¿åãããããããšå£ããŸããè¯ãã«ãŒã«åœ¢åŒã¯ããŒã ãæ€èšŒã§ãã説æã§ãããã®ã§ãã
2ã€ã®äžè¬çãªã¢ãããŒã:
- å®éã«ãµããŒããããã¿ãŒã³ã«éå®ãã ã·ã³ãã«ãªã«ã¹ã¿ã ãã£ãŒã«ãã
- ã«ã¬ã³ããŒã®ã€ã³ããŒã/ãšã¯ã¹ããŒãã倿§ãªçµã¿åãããæ±ãå¿ èŠãããå Žåã® iCalendar 颚ïŒRRULE çžåœïŒã
çŸå®çãªæè¡·æ¡: éããããªãã·ã§ã³ãåãšããŠä¿åããRRULE æååã¯äº€æãã©ãŒãããã®ã¿ãšããŠæ±ãã
äŸãšããŠãé±åäœã·ããã¯ä»¥äžã®ãããªãã£ãŒã«ãã§è¡šããŸã:
freqïŒdaily/weekly/monthlyïŒ ãšintervalïŒæ¯ NïŒbyweekdayïŒ0-6 ã®é åãŸãã¯ããããã¹ã¯ïŒ- ææ¯ã«ãŒã«ãªããªãã·ã§ã³ã®
bymonthdayïŒ1-31ïŒ starts_at_localïŒãŠãŒã¶ãŒãéžãã ããŒã«ã«æ¥æïŒãštzid- ãªãã·ã§ã³ã§
until_dateãŸãã¯countïŒäž¡æ¹ããµããŒãããã®ã¯é¿ããïŒ
å¢çã«ã€ããŠã¯ãåçºçã® end ãæ¯åä¿åããããã durationïŒäŸ: 8æéïŒãä¿åããæ¹ã奜ãŸããã§ããDST ãå€ãã£ãŠã duration ã¯å®å®ããŠãããçºçããšã®çµäºæå»ã¯ start + duration ã§èšç®ã§ããŸãã
ã«ãŒã«ãå±éãããšãã¯å®å šãã€éå®çã«:
window_startãšwindow_endã®ç¯å²å ã ãå±éããã- å€è·šãã€ãã³ãã®ããã«å°ããªãããã¡ïŒäŸ: 1æ¥ïŒã远å ããã
- æå€§ã€ã³ã¹ã¿ã³ã¹æ°ïŒäŸ: 500ïŒã§æã¡åãã
- çæåã«åè£ããã£ã«ã¿ããïŒ
tzid,freq, éå§æ¥ãªã©ïŒã
ã¹ããããã€ã¹ããã: DST ã«å®å šãªç¹°ãè¿ãã¹ã±ãžã¥ãŒã«ã®æ§ç¯
ä¿¡é Œã§ãããã¿ãŒã³ã¯: åçºçããŸãããŒã«ã«ãªã«ã¬ã³ããŒã®æå³ïŒæ¥ä» + ããŒã«ã«æå» + å Žæã®ã¿ã€ã ãŸãŒã³ïŒãšããŠæ±ãããœãŒããç«¶åãã§ãã¯ã衚瀺ãå¿ èŠãªãšãã«åããŠã€ã³ã¹ã¿ã³ãã«å€æããããšã§ãã
1) UTC æšæž¬ã§ã¯ãªãããŒã«ã«ã®æå³ãä¿åãã
ã¹ã±ãžã¥ãŒã«ã®å Žæã®ã¿ã€ã ãŸãŒã³ïŒIANA å äŸ: America/New_YorkïŒãšããŒã«ã«éå§æå»ïŒäŸ: 09:00ïŒãä¿åããŠãã ããããã®ããŒã«ã«æå»ãããžãã¹ã®æå³ãããšããã§ããDST ãå€ãã£ãŠããã®ããŒã«ã«æéãåºæºã«ãªããŸãã
ãŸãç¶ç¶æéãšæç¢ºãªå¢çïŒéå§æ¥ãšçµäºæ¥ãŸãã¯ç¹°ãè¿ãåæ°ïŒãä¿åããŠãã ãããå¢çã¯ãç¡éå±éããã°ãé²ããŸãã
2) äŸå€ãšãªãŒããŒã©ã€ãã¯å¥ã§ã¢ãã«åãã
ã¹ãããæ¥çšãšå€æŽçºççšã®2ã€ã®å°ããªããŒãã«ãçšæããschedule_id + local_date ã§ããŒãæããããšå
ã®åçºãšãããã«ãããã§ããŸãã
å®çšçãªåœ¢ã¯æ¬¡ã®éãã§ã:
-- core schedule
-- tz is the location time zone
-- start_time is local wall-clock time
schedule(id, tz text, start_date date, end_date date, start_time time, duration_mins int, by_dow int[])
schedule_skip(schedule_id, local_date date)
schedule_override(schedule_id, local_date date, new_start_time time, new_duration_mins int)
3) èŠæ±ãŠã£ã³ããŠå ã ããå±éãã
衚瀺ã¬ã³ãžïŒé±ãæïŒã«å¯ŸããŠåè£ã®ããŒã«ã«æ¥ãçæããææ¥ã§ãã£ã«ã¿ããŠããã¹ããããšãªãŒããŒã©ã€ããé©çšããŸãã
WITH days AS (
SELECT d::date AS local_date
FROM generate_series($1::date, $2::date, interval '1 day') d
), base AS (
SELECT s.id, s.tz, days.local_date,
make_timestamp(extract(year from days.local_date)::int,
extract(month from days.local_date)::int,
extract(day from days.local_date)::int,
extract(hour from s.start_time)::int,
extract(minute from s.start_time)::int, 0) AS local_start
FROM schedule s
JOIN days ON days.local_date BETWEEN s.start_date AND s.end_date
WHERE extract(dow from days.local_date)::int = ANY (s.by_dow)
)
SELECT b.id,
(b.local_start AT TIME ZONE b.tz) AS start_utc
FROM base b
LEFT JOIN schedule_skip sk
ON sk.schedule_id = b.id AND sk.local_date = b.local_date
WHERE sk.schedule_id IS NULL;
4) 衚瀺çšã®å€æã¯æåŸã«ãŸãšããŠè¡ã
start_utc ã timestamptz ãšããŠä¿æãããœãŒããè¡çªãã§ãã¯ãäºçŽåŠçã«äœ¿ããŸãã衚瀺æã«é²èЧè
ã®ã¿ã€ã ãŸãŒã³ãžå€æããããšã§ãDST ã«ããæå³ããªããããé²ããŸãã
æ£ããã«ã¬ã³ããŒè¡šç€ºãäœãããã®ã¯ãšãªãã¿ãŒã³
ã«ã¬ã³ããŒã¹ã¯ãªãŒã³ã¯éåžžãfrom_ts ãš to_ts ã®éãèŠããããšããç¯å²ã¯ãšãªã§ããå®å šãªãã¿ãŒã³ã¯:
- ãã®ãŠã£ã³ããŠå ã®åè£ã ããå±éããã
- äŸå€/ãªãŒããŒã©ã€ããé©çšããã
start_atãšend_atãtimestamptzãšããŠæçµåºåããã
generate_series ã䜿ã£ãæ¥æ¬¡ïŒé±æ¬¡ã®å±é
åçŽãªé±ã«ãŒã«ïŒäŸ: ãæ¯å¹³æ¥ããŒã«ã«09:00ãïŒã§ã¯ãã¹ã±ãžã¥ãŒã«ã®ã¿ã€ã ãŸãŒã³ã§ããŒã«ã«æ¥ãçæããåããŒã«ã«æ¥ + ããŒã«ã«æå»ãã€ã³ã¹ã¿ã³ãã«å€æããŸãã
-- Inputs: :from_ts, :to_ts are timestamptz
-- rule.tz is an IANA zone like 'America/New_York'
WITH bounds AS (
SELECT
(:from_ts AT TIME ZONE rule.tz)::date AS from_local_date,
(:to_ts AT TIME ZONE rule.tz)::date AS to_local_date
FROM rule
WHERE rule.id = :rule_id
), days AS (
SELECT d::date AS local_date
FROM bounds, generate_series(from_local_date, to_local_date, interval '1 day') AS g(d)
)
SELECT
(local_date + rule.start_local_time) AT TIME ZONE rule.tz AS start_at,
(local_date + rule.end_local_time) AT TIME ZONE rule.tz AS end_at
FROM rule
JOIN days ON true
WHERE EXTRACT(ISODOW FROM local_date) = ANY(rule.by_isodow);
ãã®æ¹æ³ã¯ãçºçããšã« timestamptz ã«å€æããããããã®æ¥ããšã® DST å€åãæ£ããé©çšãããŸãã
ãnçªç®ã®ææ¥ããã®ã£ããã®ããè€éãªã«ãŒã«ã«ã¯ååž°CTE
ã«ãŒã«ããnçªç®ã®ææ¥ããã®ã£ãããã«ã¹ã¿ã ééã«äŸåããå Žåãååž° CTE ã§æ¬¡ã®çºçãç¹°ãè¿ããŠçæããto_ts ãè¶
ãããæ¢ããŸãããŠã£ã³ããŠã«åºå®ããŠããã°ç¡éã«ãŒãã«ã¯ãªããŸããã
åè£è¡ãã§ããããäŸå€ã»ãã£ã³ã»ã«ã»ãªãŒããŒã©ã€ãã (rule_id, start_at) ãããŒã«ã«ã㌠(rule_id, local_date) ã§çµåããŠé©çšããŸãããã£ã³ã»ã«ãªãè¡ãèœãšãããªãŒããŒã©ã€ããããã° start_at/end_at ã眮ãæããŸãã
éèŠãªããã©ãŒãã³ã¹ãã¿ãŒã³:
- ç¯å²ã§æ©ãã«çµã: ãŸãã«ãŒã«ããã£ã«ã¿ãããã®åŸã§ç¯å²å ã ãå±éããã
- äŸå€/ãªãŒããŒã©ã€ãããŒãã«ã«
(rule_id, start_at)ã(rule_id, local_date)ã®ã€ã³ããã¯ã¹ã貌ãã - æè¡šç€ºã®ããã«å¹Žåäœãå±éããªãã
- ã«ãŒã«ãå€ãã£ããšãã«ç¢ºå®ã«ç¡å¹åã§ããå Žåã®ã¿çºçã®ãã£ãã·ã¥ã䜿ãã
äŸå€ãšãªãŒããŒã©ã€ãã®ããããªæ±ãæ¹
ç¹°ãè¿ãã¹ã±ãžã¥ãŒã«ã¯ãéäžã§å®å šã«å£ããããšãéèŠã§ããäºçŽãã·ããã®ã¢ããªã§ã¯ãæ®éã®é±ããåºæ¬ã«ãŒã«ã§ãäŒæ¥ããã£ã³ã»ã«ãç§»åãã¹ã¿ãã亀代ã¯ãã¹ãŠäŸå€ã§ããäŸå€ãåŸä»ããããšã«ã¬ã³ããŒè¡šç€ºãããããéè€ãçºçãããããŸãã
3ã€ã®æŠå¿µãåããŠãããŸããã:
- ããŒã¹ã¹ã±ãžã¥ãŒã«ïŒåçºã«ãŒã«ãšãã®ã¿ã€ã ãŸãŒã³ïŒ
- ã¹ãããïŒçºçããªãæ¥ãã€ã³ã¹ã¿ã³ã¹ïŒ
- ãªãŒããŒã©ã€ãïŒååšããã詳现ã倿ŽãããçºçïŒ
åºå®ã®åªå é äœã䜿ã
åªå é äœãäžã€æ±ºããŠäžè²«ãããŠãã ãããäžè¬çãªéžæ:
- ããŒã¹ã®åçºããåè£ãçæã
- ãªãŒããŒã©ã€ããé©çšïŒçæã眮ãæããïŒã
- ã¹ããããé©çšïŒé衚瀺ã«ããïŒã
ã«ãŒã«ã¯ãŠãŒã¶ãŒã«äžæã§èª¬æã§ããããã«ããŠãããšè¯ãã§ãã
ãªãŒããŒã©ã€ããå ã®ã€ã³ã¹ã¿ã³ã¹ã眮ãæãããšãã®éè€åé¿
éè€ã¯çæãããçºçãšãªãŒããŒã©ã€ãè¡ã®äž¡æ¹ãè¿ãããšã§èµ·ããŸããå®å®ããããŒã§é²ããŸã:
- åçæã€ã³ã¹ã¿ã³ã¹ã«
(schedule_id, local_date, start_time, tzid)ã®ãããªå®å®ããŒãä»äžããã - ãªãŒããŒã©ã€ãè¡ã«ãã®ããŒããå ã®çºçããŒããšããŠä¿åããã
- ããŒã¹çºçããšã«ãªãŒããŒã©ã€ãã¯äžã€ã ããšããäžæå¶çŽã远å ããã
ã¯ãšãªã§ã¯ããªãŒããŒã©ã€ããããçæçºçãé€å€ãããªãŒããŒã©ã€ãè¡ã UNION ã§å ããŸãã
ç£æ»æ§ãä¿ã€
äŸå€ã¯ã誰ã倿Žããããã®äºç¹ã«ãªããããã®ã§ãskips ãš overrides ã« created_by, created_at, updated_by, updated_atãããã³ä»»æã®çç±ãã£ãŒã«ãã远å ããŠãããšè¯ãã§ãã
1æéãºã¬ã®ãã°ãçããããããã¹
ã»ãšãã©ã®1æéãã°ã¯ãã€ã³ã¹ã¿ã³ãïŒUTC ã¿ã€ã ã©ã€ã³äžã®ç¹ïŒãšããŒã«ã«æèšïŒäŸãã°ãã¥ãŒãšãŒã¯ã®æ¯é±ææ09:00ïŒãšãã2ã€ã®æå³ãæ··åããããšããçããŸãã
å
žåçãªãã¹ã¯ãããŒã«ã«ã®å£æèšã«ãŒã«ã timestamptz ãšããŠä¿åããŠããŸãããšã§ãããããæ¯é±ææ09:00 America/New_Yorkããåäžã® timestamptz ãšããŠä¿åãããšãæ¢ã«å
·äœçãªæ¥ä»ïŒããã³ãã®æç¹ã® DST ç¶æ
ïŒãéžãã§ããŸã£ãããšã«ãªããå°æ¥ã®ææãçæãããšãã«ããã€ãããŒã«ã«09:00ããšããæå³ã倱ãããŸãã
ããäžã€ã®åå ã¯åºå®ã® UTC ãªãã»ããïŒ-05:00 ãªã©ïŒã«é Œãããšã§ãããªãã»ãã㯠DST ã«ãŒã«ãå«ãŸãªãã®ã§äžé©åã§ãããŸãŒã³IDïŒäŸ: America/New_YorkïŒãä¿åããŠãPostgreSQL ã«æ¥ä»ããšã®æ£ããã«ãŒã«ãé©çšãããŠãã ããã
倿ã®ã¿ã€ãã³ã°ã«æ³šæããŠãã ãããåçºçæã®éäžã§æ©ãã« UTC ã«å€æãããšããã DST ãªãã»ãããåºå®ãããŠå šçºçã«é©çšãããŠããŸãæãããããŸããå®å šãªãã¿ãŒã³ã¯: çºçãããŒã«ã«ã®ïŒdate + local time + zoneïŒã§çæããåçºçãåå¥ã«ã€ã³ã¹ã¿ã³ããžå€æããããšã§ãã
ç¹°ãè¿ãçŸãããã¹:
- ç¹°ãè¿ãã®ããŒã«ã«æå»ãä¿åãã¹ããšããã
timestamptzã«ããŠããŸãïŒæ¬æ¥ã¯time+tzid+ ã«ãŒã«ïŒã - ãªãã»ããã®ã¿ãä¿åããIANA ãŸãŒã³ãä¿åããŠããªãã
- åçºçæäžã«æ©ã段éã§ UTC ã«å€æããŠããŸãã
- ç¡å¶éã«ãæ°žé ã«ãå±éããŠããŸãã
- DST éå§é±ãšçµäºé±ããã¹ãããŠããªãã
ã»ãšãã©ã®åé¡ãæ€åºããç°¡åãªãã¹ã: DST ã®ãããŸãŒã³ãéžã³ãæ¯é±09:00ã®ã·ãããäœããDST 倿ŽããŸãã2ãæåã®ã«ã¬ã³ããŒãã¬ã³ããªã³ã°ããŠãåã€ã³ã¹ã¿ã³ã¹ãçŸå°ã§ã¯åžžã«09:00ã«ãªã£ãŠããããšã確èªããŠãã ããïŒåºç€ãšãªã UTC ã€ã³ã¹ã¿ã³ã¹ã¯ç°ãªã£ãŠããŠæ§ããŸããïŒã
åºè·åã®ã¯ã€ãã¯ãã§ãã¯ãªã¹ã
åºè·åã«åºæ¬ã確èªããŠãã ãã:
- ãã¹ãŠã®ã¹ã±ãžã¥ãŒã«ã¯æç€ºçã«ã¿ã€ã ãŸãŒã³ãçŽã¥ããŠãããã¹ã±ãžã¥ãŒã«èªèº«ã«ä¿åãããŠããã
- IANA ãŸãŒã³IDïŒäŸ:
America/New_YorkïŒãä¿åããŠããŠãçã®ãªãã»ããã¯ä¿åããŠããªãã - åçºå±éã¯èŠæ±ãããç¯å²å ã ãã§è¡ãããã
- äŸå€ãšãªãŒããŒã©ã€ãã¯åäžã®ãææžåãããåªå é ãæã€ã
- DST 倿Žé±ãšãã¹ã±ãžã¥ãŒã«ãšã¯å¥ã®ã¿ã€ã ãŸãŒã³ã«ããé²èЧè ã®ãã¹ããè¡ãã
çŸå®çãªãã©ã€ã©ã³ãäžã€: Europe/Berlin ã®åºãæ¯é±09:00ããŒã«ã«ã®ã·ãããæã¡ã管çè
ã America/Los_Angeles ããé²èЧãããæ¯é±ã®ã·ããã DST ã«å¿ããŠãåžžã«ãã«ãªã³ã®09:00ã«çãŸãããšã確èªããŠãã ããã
äŸ: ç¥æ¥ãš DST 倿Žãå«ã鱿¬¡ã¹ã¿ããã·ãã
å°ããªã¯ãªããã¯ãæ¯é±ææ09:00ã17:00ã§ America/New_York ã®ããŒã«ã«æéã«åºå®ãããç¹°ãè¿ãã·ãããéå¶ããŠãããšããŸããããææãç¥æ¥ã§äŒèšºã«ãªããã¹ã¿ããã®äžäººã¯2é±éãšãŒããããæ
è¡äžã§ãããã¯ãªããã¯ã®ã¹ã±ãžã¥ãŒã«ã¯ã¹ã¿ããã®çŸåšå°ã§ã¯ãªãã¯ãªããã¯ã®å£æèšã«çŽã¥ãããŸãŸã§ãªããã°ãªããŸããã
ãããæ£ããåããããã«:
- ããŒã«ã«æ¥ïŒææ¥=ææïŒãšããŒã«ã«æå»ïŒ09:00ã17:00ïŒã§ã¢ã³ã«ãŒãããåçºã«ãŒã«ãä¿åããã
- ã¹ã±ãžã¥ãŒã«ã®ã¿ã€ã ãŸãŒã³
America/New_Yorkãä¿åããã - ã«ãŒã«ã«æç¢ºãªèµ·ç¹ãšãªãéå§æ¥ãä¿åããŠããã
- ç¥æ¥ã®ãã®ææããã£ã³ã»ã«ããäŸå€ãšãåçºã®å€æŽã®ããã®ãªãŒããŒã©ã€ããä¿åããã
2é±éåã®ã«ã¬ã³ããŒã¬ã³ãžãã¬ã³ããªã³ã°ãããšããã¯ãšãªã¯ãã®ããŒã«ã«æ¥ç¯å²ã®ææãçæããã¯ãªããã¯ã®ããŒã«ã«æå»ãä»ããŠããåçºçã timestamptz ã«å€æããŸããçºçããšã«å€æãããããDST ã¯æ£ããæ¥ã«é©çšãããŸãã
ç°ãªãé²èЧè ã¯åãã€ã³ã¹ã¿ã³ãã«å¯ŸããŠç°ãªãçŸå°æèšæå»ãèŠãŸã:
- ããµã³ãŒã«ã¹ã®ç®¡çè ã¯ããæ©ãæèšæå»ã§èŠãã
- ãã«ãªã³ã®æ è¡äžã®ã¹ã¿ããã¯ããé ãæèšæå»ã§èŠãã
ãããã¯ãªããã¯ã¯åžžã«æãã éã: æ¯é±ã®ææã¯ New York æéã§09:00ã17:00ïŒãã£ã³ã»ã«ãããŠããæ¥ã¯é€ãïŒã«ãªããŸãã
次ã®ã¹ããã: å®è£ ããã¹ããä¿å®ãããããã
æéã®æ±ããæ©ãã«æ±ºããŠãã ãã: ã«ãŒã«ã®ã¿ãä¿åããã®ããçºçã®ã¿ãä¿åããã®ãããã€ããªããã«ããã®ããå€ãã®äºçŽã»ã·ãã補åã§ã¯ãã€ããªãããããŸãæ©èœããŸã: ã«ãŒã«ãçå®ã®ãœãŒã¹ã«ããŠããŒãªã³ã°ãã£ãã·ã¥ã眮ããäŸå€ãšãªãŒããŒã©ã€ããå ·è±¡ã®è¡ãšããŠä¿åããã
ãæéå¥çŽããäžç®æã«æžãæ®ããŠãã ãã: äœãã€ã³ã¹ã¿ã³ãã§äœãããŒã«ã«å£æèšããã©ã®ã«ã©ã ã«äœãä¿åããããããããããšããããšã³ããã€ã³ããããŒã«ã«æå»ãè¿ãå¥ã®ãšã³ããã€ã³ãã UTC ãè¿ããšãã£ããºã¬ãé²ããŸãã
åçºçæããžãã¯ã¯äžã€ã®ã¢ãžã¥ãŒã«ã«ãŸãšããæ£ãã°ã£ã SQL æçã«ããªãã§ãã ãããå°æ¥ãããŒã«ã«09:00ã®è§£éããå€ããå¿ èŠãåºããšããæŽæ°ç®æãäžç®æã§æžãããã«ããŸãã
æäœæ¥ã§å šãŠãå®è£ ããããªãå ŽåãAppMaster (appmaster.io) ã¯ããããäœæ¥ã«å®çšçã§ã: Data Designer ã§ããŒã¿ããŒã¹ãã¢ãã«åããããžãã¹ããã»ã¹ã§åçºãäŸå€ããžãã¯ãæ§ç¯ãã€ã€ãæ¬çªçšã®ããã¯ãšã³ããšã¢ããªã³ãŒããçæã§ããŸãã


