Generato con assistenza AI (Claude Opus 4.8, 1M context). Documento di handoff per una sessione dedicata (deciso con l'utente). Stato repo all'apertura: steps 0–34 DONE, 624 test, HEAD su main, clippy pulito. Workflow standard [[legacy-port]] + TDD. Oracle PHP 8.5.7 in
/tmp/php-src/sapi/cli/php.
Lo step 34 ha costruito l'API OOP di data/ora (DateTime,
DateTimeImmutable, DateInterval come classi del prelude + builtin puri
date/mktime/strtotime/…). PHP espone anche l'API procedurale
equivalente (date_create, date_format, date_diff, date_add, …), che è in
larghissima parte zucchero sintattico sopra l'OOP. Implementarla:
- sblocca molti test del corpus
ext/date/testsche usano lo stile procedurale; - è a basso rischio (wrapper sottili su metodi già verificati);
- richiede un solo pezzo di infrastruttura nuovo: funzioni globali nel prelude (vedi D-PD1).
Tutto con date_default_timezone_set('UTC'). Valori verificati:
date_create('2024-06-15 12:30:45') → DateTime ; date_format(...,'Y-m-d H:i:s') = 2024-06-15 12:30:45
date_create_immutable('2024-01-01') → DateTimeImmutable
date_diff(date_create('…06-15'),date_create('…06-20')) → ->days=5 ; date_interval_format(iv,'%d days')='5 days'
date_add($a, date_interval_create_from_date_string('1 day')) → +1 giorno (muta $a, ritorna $a)
date_sub($a, new DateInterval('P1M')) → -1 mese
date_time_set($a,8,30,0); date_date_set($a,2020,2,29) → 2020-02-29 08:30:00
date_timestamp_set($a,1718452845); date_timestamp_get($a) → 1718452845
date_modify($a,'+2 hours') → +2h
date_create_from_format('!d/m/Y','15/06/2024')→ DateTime 2024-06-15 00:00:00
getdate(1718452845) → [seconds=45,minutes=0,hours=12,mday=15,wday=6,mon=6,year=2024,yday=166,
weekday='Saturday',month='June', 0=1718452845]
localtime(1718452845) → [45,0,12,15,5,124,6,166,0] (sec,min,hour,mday,mon0,year-1900,wday,yday,isdst)
localtime(1718452845,true) → assoc keys tm_sec/tm_min/tm_hour/tm_mday/tm_mon(0)/tm_year(-1900)/tm_wday/tm_yday/tm_isdst
Note: mktime/gmmktime/checkdate/strtotime/date_default_timezone_set|get
già fatti allo step 34. date_interval_create_from_date_string('1 day')
parsa una stringa relativa (non ISO) → componenti interval.
I wrapper (date_create, date_format, date_diff, date_add, …) chiamano
new/metodi → un builtin puro NON può (ha solo Ctx, non l'evaluator).
Raccomandazione: funzioni globali del PRELUDE (PHP puro in PRELUDE_SRC),
coerente con la scelta dello step 34 (classi nel prelude). Es.:
function date_create($datetime = "now") { return new DateTime($datetime); }
function date_format($object, $format) { return $object->format($format); }
function date_diff($base, $target, $absolute = false) { return $base->diff($target); }
function date_add($object, $interval) { return $object->add($interval); }
// … ecc.Infra da costruire: oggi lower_prelude() (lower.rs:328) ritorna SOLO
classes + class_index; funzioni/closure/static vengono scartate (commento
esplicito riga 326-327). Va esteso per:
- far girare anche
hoist_function/lowering delle funzioni del prelude; - ritornare
functions: Vec<FnDecl>+fn_indexdel prelude; - mergiarle in testa a
Program.functionscon lo stesso accorgimento dihoist_classesper le classi (offset degli indici: le funzioni si risolvono per nome→indice viafn_index, vedi lower.rs:794-796 — verificare che le chiamate-per-indice interne restino coerenti dopo il merge, esattamente come gli id di classe del prelude vengono offsettati).
- Alternativa scartata: intercettare ogni funzione nell'evaluator (come
json_decode/get_class). Più invasiva, ~14 funzioni, meno idiomatica del prelude PHP. Usarla solo se il merge delle funzioni-prelude si rivelasse troppo costoso (improbabile).
Builtin PURI in php-builtins/src/date.rs (non toccano oggetti, ritornano
array). Riusano decompose/gli accessor time. getdate = array assoc + chiave
0=ts; localtime = array indicizzato stile C struct tm (mon 0-based,
year-1900), con $associative=true → chiavi tm_*.
Parsa una stringa relativa ("1 day", "2 weeks 3 hours", "1 year") →
componenti DateInterval. Aggiungere un helper Rust __interval_from_date_string
(sottoinsieme: riusa la logica di parse_relative dello step 34-3, ma senza
base e producendo l'array componenti y/m/d/h/i/s invece di un epoch).
La funzione-prelude costruisce un DateInterval e ne imposta le prop (come fa
DateTime::diff: $iv = new DateInterval('PT0S'); $iv->d = …;).
Terzo parametro $absolute (default false): se true, l'intervallo ha invert=0.
Onorarlo nel wrapper (if ($absolute) $r->invert = 0;). Minore.
- 35-1 INFRA + primi wrapper: estendere il prelude alle funzioni globali
(D-PD1) e provarlo con
date_create/date_create_immutable/date_format/date_timestamp_get. È il sotto-step di rischio: una volta verde, il resto è meccanico. Test inphp-builtins/tests/builtins.rsout()(registry COMPLETA). - 35-2 mutatori/diff:
date_diff(+$absolute),date_add,date_sub,date_modify,date_date_set,date_time_set,date_timestamp_set. - 35-3 format/interval:
date_create_from_format,date_create_immutable_from_format,date_interval_format,date_interval_create_from_date_string(+ helper__interval_from_date_string). - 35-4 getdate/localtime: builtin puri (D-PD2).
- 35-5 corpus + rifiniture: ri-girare
ext/date/tests(ora molti test procedurali diventano runnable) — contare i nuovi pass, classificare i fail come scope-out. Aggiornarediary/metrics.md+04-divergences.md.
(Granularità rivedibile dal Decider: 35-2 e 35-3 si possono accorpare.)
- Test harness: i wrapper-prelude chiamano builtin (
date/mktime) → testabili solo con la registry completa (php-builtins/tests/builtins.rsout()), non ineval.rs::out()(registry vuota). Come step 34. - Redefinizione: PHP darebbe fatal se l'utente ridefinisce
date_create; raro, ignorare (il prelude vince/coesiste — verificare il comportamento del merge sul conflitto nome). date_add/date_subsuDateTimemutano e ritornano l'oggetto; suDateTimeImmutableritornano una nuova istanza — i metodiadd/subdello step 34 già lo fanno, quindi i wrapper sonoreturn $o->add($i);punto.getdate()/localtime()senza argomento usanotime()(non-det, D-DT5) → testare solo con ts esplicito.
date_sun_info/date_sunrise/date_sunset(astronomia).- Funzioni timezone procedurali (
timezone_open,date_timezone_get/set,timezone_*) → dipendono daDateTimeZone/tz-db (scope-out step 34, D-DT3). date_get_last_errors,date_parse,date_parse_from_format(ritornano array diagnostici dettagliati del parser nativo).strftime/gmstrftime(deprecate in PHP 8.1).date_interval_create_from_date_stringsu stringhe relative esotiche (subset come strtotime, D-DT4).
- Leggere questo file + la coda di
diary/metrics.md(sezione Macro-step 34) + il resume di memoriaphp-rust-next-step7.md. - Decidere D-PD1..D-PD4 col Decider (default consigliati sopra).
- Partire da 35-1: estendere
lower_preludealle funzioni globali (modello =hoist_classesper l'offset prelude) in TDD (RED condate_create).