Osaisiko joku viisampi antaa JavaScript esimerkkikoodin seuraavanlaiseen tarpeeseen:
Koodaan 8th pohjaisella ohjelmallani vuorokauden automaatio ohjaukset kanavalle bittitasolla siten, että luvun vähiten merkitsevä 0-bitti vastaa kellonaikaa 00:00:00, luvun seuraava enemmän merkitsevä bitti vastaa kellonaikaa 01:00:00 ja niin edelleen. Tästä lukuun tallennetusta "bittikartasta" pitäisi saada muodostettua kaikkien yhtenäisten bittiryhmien muodostamien jaksojen alku -ja loppuaika. Aikavyöhyke pitäisi ottaa huomioon siten, että näyttäisi oikean ajan myös kellojen siirron tapauksessa.
Tällä hetkellä joudun siirtämään webbi-asiakasohjelmalle ajat merkkijonona ja haluaisin mieluusti saada viestien koon pidettynä minimaalisena.
Siirrän nyt siis tiedon alla olevassa muodossa, mutta kun kaikki kanavan ohjaukset vuorokaudelle mahtuisivat neljä tavuiseen lukuun, niin tämä tapa tuntuu tuhlaukselta.
2023-11-19 04:00:00+02:00 PÄÄLLE;2023-11-19 07:00:00+02:00 POIS
Koodasin sinulle semmoisen. Aikavyöhyke osoittautui isoimmaksi ongelmaksi, koska JS osaa muotoilla aikaleiman joko UTC-vyöhykkeellä ISO-muodossa tai pyydetyllä vyöhykkeellä paikallisessa muodossa, ja lisäksi JS osaa antaa numeerisen aikavyöhyketiedon vain selaimen käyttämän paikallisen ajan osalta. Ratkaisin ongelman niin, että aikaleiman lokalisoidusta muotoilusta kaivetaan numeerinen vyöhyke (kuten GMT+02:00), minkä jälkeen muutetaan aikaleimaa tämän verran ja muotoillaan se sitten UTC-aikana ISO-muodossa.
Onko jokin syy, miksi käsittelet aikaleimoja vyöhykkeen kanssa? Yleensä pitäisin helpompana, että käsitellään kaikkea UTC-aikana ja näytetään vyöhyke vain käyttöliittymässä.
Oletan, että kaikesta huolimatta bitit kuvastavat UTC-aikaa. Jos bitit olisivat paikallista aikaa, olisi tietysti helpompi tuottaa suoraan oikeat paikalliset kellonajat, mutta sitten pitäisi vielä vääntää aikavyöhyke kohdalleen jollain muulla virityksellä.
// Funktio muuttaa 24-bittisen luvun listaksi ohjauskomentoja (päälle / pois). function getControlTimes(date, bits, oldState) { let controlTimes = []; let state = oldState; for (var hour = 0; hour < 24; hour++) { let newState = ((bits >> hour) & 1) == 1; if (newState !== state) { state = newState; controlTimes.push({ date, hour, state }); } } return controlTimes; } // Funktio luo päivämäärästä ja tunnista aikaleiman, oletuksena UTC-tunti. function getTimestampUTC(date, hour) { return new Date(date + "T" + hour.toString().padStart(2, "0") + ":00:00Z"); } // Funktio muuntaa aikaleiman tekstiksi UTC-ajassa. function formatTimestampUTC(timestamp) { return timestamp.toISOString().replace(/T|\.\d\d\dZ|Z/g, ""); } // Funktio muuntaa aikaleiman tekstiksi halutulla aikavyöhykkeellä. // Huomaa, että tuetut aikavyöhykkeet voivat riippua ympäristöstä. function formatTimestampLocal(timestamp, timeZone = "Europe/Helsinki") { // JS tuottaa joko ISO-muotoisen UTC-ajan tai lokalisoidun ajan vyöhykkeen kanssa. // Kaksi vaihtoehtoa: // a) Muotoillaan lokalisoidusta ajasta itse ISO-aika. // b) Poimitaan vyöhyke ja huijataan UTC-ajan kanssa. // Tässä käytetään vaihtoehtoa b. let tz = timestamp.toLocaleString('en-US', { timeZoneName: 'longOffset', timeZone }).match(/([-+])(\d+):(\d\d)/); let offset = tz ? (tz[1] == "-" ? 1 : -1) * (+tz[3] + +tz[2] * 60) * 60000 : 0; return formatTimestampUTC(new Date(timestamp.getTime() - offset)) + (tz ? tz[0] : "+00:00"); } // Esimerkkinä bitit päällä talviajan vaihtuessa yöaikaan. function example() { let controls = []; controls.push(...getControlTimes("2023-10-28", 0xfc0000, false)); controls.push(...getControlTimes("2023-10-29", 0xfe0003, controls[controls.length - 1].state)); controls.push(...getControlTimes("2023-10-30", 0x000007, controls[controls.length - 1].state)); controls.forEach(s => { s.timestamp = getTimestampUTC(s.date, s.hour); }); let lines = controls.map(s => `UTC ${formatTimestampUTC(s.timestamp)}, local ${formatTimestampLocal(s.timestamp)}; ${s.state ? "ON" : "OFF"}`); console.log(lines.join("\n")); /* UTC 2023-10-28 18:00:00, local 2023-10-28 21:00:00+03:00; ON UTC 2023-10-29 02:00:00, local 2023-10-29 04:00:00+02:00; OFF UTC 2023-10-29 17:00:00, local 2023-10-29 19:00:00+02:00; ON UTC 2023-10-30 03:00:00, local 2023-10-30 05:00:00+02:00; OFF */ } example();
Metabolix kirjoitti:
Onko jokin syy, miksi käsittelet aikaleimoja vyöhykkeen kanssa? Yleensä pitäisin helpompana, että käsitellään kaikkea UTC-aikana ja näytetään vyöhyke vain käyttöliittymässä.
Kiitos! Käsittelen 8th:lla muunnoksen bitin position mukaan päiväykseksi ja huomioin mahdollisen kellojen siirron vaikutuksen vuorokauden tuntien lukumäärään näin:
: n>datetime \ n dst-zone -- d swap "%02d:00:00" s:strfmt d:parse tuck d:dst-ofs d:tzadjust ; : zerotime \ d -- d d:>ymd d:ymd> ; : dayhours? \ d -- n zerotime dup>r d:year@ 10 31 d:ymd> d:Sun d:prev-dow zerotime d:= if 25 else r@ d:year@ 03 31 d:ymd> d:Sun d:prev-dow zerotime d:= if 23 else 24 then then rdrop ;
Vuorokauden tuntien eli bittien lukumäärän tarvitsen rakentaessani ohjaukset uusiksi seuraavan vuorokauden hintojen tullessa saataville. Tällä vältytään turhilta ohjauksilta mikäli tämän vuorokauden ohjaus menisi pois päältä puolen yön aikaan ja seuraavan vuorokauden ohjaus laittaisikin sen heti takaisin päälle.
Aihe on jo aika vanha, joten et voi enää vastata siihen.