feat(prezentacja): strefa czasowa z lokalizacji — DST-świadomy offset (PRE-03)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m2s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m56s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 34s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 23s
build / build (push) Successful in 1m40s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m12s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m52s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m2s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m56s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 34s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 23s
build / build (push) Successful in 1m40s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m12s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m52s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Successful in 19s
„Logika dwóch lokalizacji": dotąd offset GMT był ręcznym polem (PRE-19) — trzeba
było go znać i samemu pamiętać o czasie letnim. Teraz liczymy go z lokalizacji.
Sedno wymagania: strefę ustalamy RAZ i trzymamy jako stałą liczbę, żeby drobna
zmiana współrzędnych nie przerzuciła DST i nie „przeskoczyła" Ascendenta na
sąsiedni znak. „Większa miejscowość z bazy" okazuje się zbędna — strefa IANA jest
i tak regionalna, więc wioska daje tę samą strefę co pobliskie miasto.
Jak:
- `timezone.py`: współrzędne → strefa IANA (tzfpy, OFFLINE — bez sieci), a z niej
offset DLA DATY URODZENIA. `zoneinfo`/`tzdata` znają reguły historyczne i DST:
Kraków 1984 to +1h zimą, +2h latem; Katmandu +5:45. Degraduje się do None (brak
biblioteki / punkt bez strefy / zła data) — wtedy zostaje ręczny offset.
- Endpoint `GET /timezone?lat&lon&date&time` → {tz, offset, dst, label}. 404, gdy
nie da się ustalić.
- `geo.js`: po wyborze miejsca (mapa / wyszukiwarka / „Tu i teraz") oraz przy
zmianie DATY (bo DST zależy od pory roku) pobiera offset i wypełnia pole
tz_offset, pokazując wykrytą strefę („Wykryto: Europe/Warsaw · +2:00 (czas
letni)"). Pole zostaje edytowalne. Na wejściu podpowiada tylko gdy offset
wygląda na nieustawiony — nie nadpisuje wartości ręcznie wpisanej i wysłanej.
Zależności (lekkie, offline): tzfpy (wheel Rust) + tzdata (dla zoneinfo w slim-obrazie).
Weryfikacja: żywy serwer — Kraków 1984-06 → +2:00 (czas letni), 1984-01 → +1:00,
Katmandu → +5:45. Testy: +12 strefa (moduł + endpoint), +5 JS. Prezentacja 187.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #43.
This commit is contained in:
@@ -23,6 +23,21 @@
|
||||
var resultsEl = document.getElementById('geoResults');
|
||||
var mapEl = document.getElementById('map');
|
||||
|
||||
// ---- strefa czasowa z lokalizacji (PRE-03) ----
|
||||
// Offset GMT liczymy ze współrzędnych + daty (DST-świadomie), żeby użytkownik
|
||||
// nie musiał go znać ani pamiętać o czasie letnim. Podpowiedź trafia do pola
|
||||
// tz_offset (PRE-19), które zostaje edytowalne — to pomoc, nie kaganiec.
|
||||
var tzEl = document.querySelector('input[name=tz_offset]');
|
||||
var dateEl = document.querySelector('input[name=date]');
|
||||
var timeEl = document.querySelector('input[name=time]');
|
||||
var tzNote = null;
|
||||
if (tzEl && tzEl.parentNode) {
|
||||
tzNote = document.createElement('span');
|
||||
tzNote.className = 'muted small';
|
||||
tzNote.id = 'tzNote';
|
||||
tzEl.parentNode.appendChild(tzNote);
|
||||
}
|
||||
|
||||
var num = function (el) { var v = parseFloat(el.value); return isNaN(v) ? 0 : v; };
|
||||
var curLat = function () { return num(latEl); };
|
||||
var curLon = function () { return num(lonEl); };
|
||||
@@ -53,6 +68,28 @@
|
||||
marker.setLatLng([lat, lon]);
|
||||
if (!fromMap) map.setView([lat, lon], Math.max(map.getZoom(), 12));
|
||||
if (fromMap) reverseName(lat, lon);
|
||||
resolveTz(); // nowe współrzędne → odśwież strefę/offset
|
||||
}
|
||||
|
||||
// Współrzędne + data → offset GMT (DST-świadomy). Wypełnia tz_offset i pokazuje,
|
||||
// jaką strefę wykryto. Bez pola/daty/biblioteki po cichu pasuje — zostaje
|
||||
// ręczny offset. Offset trzymamy potem jako stałą liczbę: to on decyduje przy
|
||||
// przeliczaniu, więc dokładne współrzędne nie przerzucą już czasu letniego.
|
||||
function resolveTz() {
|
||||
if (!tzEl || !dateEl || !dateEl.value) return;
|
||||
var lat = curLat(), lon = curLon();
|
||||
if (!lat && !lon) return; // 0,0 = brak lokalizacji
|
||||
var url = '/timezone?lat=' + lat + '&lon=' + lon +
|
||||
'&date=' + encodeURIComponent(dateEl.value) +
|
||||
'&time=' + encodeURIComponent((timeEl && timeEl.value) || '12:00');
|
||||
fetch(url)
|
||||
.then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (d) {
|
||||
if (!d) { if (tzNote) tzNote.textContent = ''; return; }
|
||||
setVal(tzEl, d.offset); // change → formsync podłapie
|
||||
if (tzNote) tzNote.textContent = 'Wykryto: ' + d.label;
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function reverseName(lat, lon) {
|
||||
@@ -130,6 +167,16 @@
|
||||
marker.setLatLng([curLat(), curLon()]);
|
||||
map.setView([curLat(), curLon()], Math.max(map.getZoom(), 12));
|
||||
reverseName(curLat(), curLon());
|
||||
resolveTz(); // „Tu i teraz" → nowe miejsce → nowa strefa
|
||||
});
|
||||
|
||||
// Zmiana daty przelicza offset — czas letni zależy od daty (inny w czerwcu
|
||||
// niż w styczniu), więc bez tego offset zostałby z poprzedniej pory roku.
|
||||
if (dateEl) dateEl.addEventListener('change', resolveTz);
|
||||
|
||||
// Na wejściu podpowiadamy strefę TYLKO gdy offset wygląda na nieustawiony
|
||||
// (0 lub pusto) — żeby nie nadpisać wartości, którą użytkownik wpisał ręcznie
|
||||
// i wysłał. Przy każdej późniejszej zmianie miejsca/daty już aktualizujemy.
|
||||
if (tzEl && (tzEl.value === '' || parseFloat(tzEl.value) === 0)) resolveTz();
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user