kitomis kalbomis - Scala, JavaScript, Python, Ruby • Kai neprogramuoju - dviračiai, snieglentė, roko muzika, šiuolaikinis menas, Vilnius JUG https://www.google.com/+VaidasPilkauskas
3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. Slides 10-62 are derived from The new JDK 1.8 Date and Time API – JSR-310 by Stephen Colebourne given at JAX 2013. All the other slides are based on various publicly available internet resources listed at the end in the reference list.
the fact that even brilliant programmers can screw up. java.util.Calendar, which Sun licensed to rectify the Date mess, is a testament to the fact that average programmers can screw up, too. http://stackoverflow.com/questions/1571265/why-is-the-java-date-api-java-util- date-calendar-such-a-mess
nepakankamas • new Date().getYear() //114 • Tinkamai nepalaiko laiko juostų • Nėra patogių priemonių dirbti su intervalais • Metai prasideda nuo 1900, mėnesio diena nuo 1, visa kita nuo 0) Date date = new Date(1L); date.toString(); //Thu Jan 01 02:00:00 EET 1970
pridėti naujus kalendorius • Trūksta getterių paprastai datų informacijai Calendar c = Calendar.getInstance(); int weekday = c.get(DAY_OF_WEEK); Date d = c.getTime();
Tai kodėl ne Joda-Time yra Java 8 Date/Time API? Nes nepakankamai tobula. “Well, there is one key reason - Joda-Time has design flaws.“ - Stephen Colebourne http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html
visiškai nuo pradžių • Įtakota Joda-Time, speco vienas iš vadovų - Stephen Colebourne • Tai atviro kodo JSR projektas (palyginimui Joda-Time - atviro kodo biblioteka) ◦ http://threeten.github.com/ ◦ Originalus kodas BSD (3 clause) licencija ◦ OpenJDK kodas GPL ◦ virš 20000 testų • Yra nuportintas JDK7
• Tipizavimas ◦ vengti primityvų, kai yra prasmė ◦ save dokumentuojantis ◦ draugiškas IDE • “Sutariantis” su egzistuojančiomis JDK datų/laiko klasėmis • Atsižvelgti į XML ir SQL poreikius
Įvykio Timestampas • Java class - Instant ◦ matuojamas nanosekundėmis nuo 1970-01-01 ◦ apima visatos amžiaus įvykius ◦ problema - nėra tinkamo primityvo - 96 bitų
būti skirtingi • Astronomai sako, kad Žemė lėtėja • Diena != (24 valandos * 60 minutės * 60 SI sekundės) • Realiai dienos ilgesnės nei 86400 SI sekundės • UTC įterpia keliamąją sekundę, kad pataisytų dienos ilgį • Kompiuteriai prastai palaiko keliamąsias sekundes
Ką tai reiškia? • Apibrėžimas netikslus, nes • UTC pradėtas tik 1972-01-01 ◦ 1970-01-01 taigi, pradžios taškas labai nepatogus • Apibrėžimas - 86400 sekundės per dieną ◦ kas atsitinka toje vietoje, kur įterpiama keliamoji sekundė?
civiliniu laiku • Vidurdienis tiksliai atitinka civilinį laiką • Visas kitas laikas kiek įmanoma tiksliau • Diena padalinta į 86400 daleles - “sekundes” • Java epocha prasideda 1970-01-01 • Tai reiškia, kad programuotojai gali ignoruoti keliamąsias sekundes • Nieko naujo, tai UTC-SLS • Tai tik apibrėžimas, viskas priklauso nuo OS
mėnuo, diena, minutė, sekundė ◦ 7 dienų savaitė, diena - 24 valandos • Reikalavimai ◦ Data ir laikas ◦ Data be laiko ◦ Laikas be datos ◦ Laiko juostos skirtumas nuo UTC ◦ Laiko zona
laiko zonos • pvz., parduotuvės atidarymo laikas • pvz., laikas sieniniame laikrodyje • Java klasė - LocalTime ◦ saugoma valanda-minutė-sekundė-nanosekundė // 20:30
UTC • Lietuva priekyje UTC - teigiama reikšmė • JAV atsilieka nuo UTC - neigiama reikšmė • Java klasė - ZoneOffset ◦ saugo sekundes -18:00 to +18:00 diapazone // +01:00
ir laikas su zonos poslinkiu • pvz., audito įrašo timestampas su laiko zona • Tas pats momentas - Instant, tik su papildoma poslinkio informacija • Java class - OffsetDateTime ◦ apjungia LocalDateTime & ZoneOffset // 2014-03-12T20:30+02:00
metodas vietoje ‘set’ ◦ nekeičiamas originalus objektas ◦ grąžinama nauja, patobulinta kopija ◦ norint toliau naudoti, reikia išsisaugoti LocalDate date = LocalDate.of(2010,Month.DECEMBER,3); LocalDate later = date.withYear(2011); LocalDate between = date.with(Month.MAY);
pagalba, pvz.: ◦ iš turimos datos gauti paskutinę mėnesio dieną ◦ iš turimos datos gauti kitą antrą trečiadienį (kada kitas JUGas?) public interface TemporalAdjuster { Temporal adjustInto(Temporal input); } LocalDate adjusted = date.with(lastDayOfMonth()); LocalDate adjusted = date.with(next2ndWednesday());
Vietovės laikas apibrėžiamas politinių taisyklių ◦ Sirija pakeičia vasaros laiką (DST) su 3 dienų perspėjimu ◦ Vakarų Australija turėjo 3 metų DST eksperimentą ◦ Brazilija keičia DST kasmet ◦ Egiptas turėjo du DST periodus 2010 • Taisyklės apibrėžia laiko zonos poslinkio pasikeitimą ◦ "Žiemą Lietuva bus 2 valandomis priekyje nuo UTC, o vasarą jau 3. Laikas persukamas viena valanda į priekį paskutinį kovo sekmadienį ir atsukamas atgal paskutinį spalio sekmadienį."
apie TZ taisykles ◦ IANA "Timezone database" (TZDB) ◦ Windows ◦ IATA - Tarptautinė oro transporto asociacija • Kiekviena grupė apibrėžia savo identifikatorių • TZDB naudoja 'Europe/Vilnius' Lietuvai • Taisyklės apibrėžia ilgalaikius DST pakeitimus • bei kada keičiasi poslinkis
time zone offset, and also figures out daylight savings” • JSR-310 atskiria atsakomybes ◦ ZoneOffset – nuo +14:00 iki -12:00 ◦ ZoneRules – poslinkių keitimo taisyklės ◦ ZoneId – zonos identifikatorius, identifikuoja vietą/valdžią • Tik viena papildoma datos/laiko klasė ◦ ZonedDateTime
Rudens DST “persidengimas” • JSR-310 nemeta exceptionų, o Joda-Time meta ◦ prasmingas datos interpretavimas ◦ Pagal nutylėjimą - vasaros laikas // one day before DST ends (overlap of one hour) ZoneId zone = ZoneId.of("Europe/London"); ZonedDateTime dt = ZonedDateTime.of(2010, 10, 27, 1, 30, 0, 0, zone); // dt = 2010-10-27 01:30 +01:00 dt = dt.plusDays(1); // dt = 2010-10-28 01:30 +01:00 // retains the offset where possible dt = dt.plusHours(1); // dt = 2010-10-28 01:30 +00:00 // offset changes, same time
◦ konvertavimo metodai į ir iš JSR-310 tipus ◦ ne deprecated :( • JSR-310 nepriklauso nuo senųjų klasių (teoriškai reiškia, kad kažkada galima bus išmesti senąsias klases)
Grigaliaus kalendoriumi • Nusako, kaip skaičiais atvaizduoti datas/laikus • Kitų internetinių standartų bazė, tokių kaip XML ◦ XML schema gerai atitinka JSR-310 klases
◦ LocalTime TIME WITHOUT TIME ZONE ◦ LocalDateTime TIMESTAMP WITHOUT TIMEZONE ◦ OffsetTime TIME WITH TIME ZONE ◦ OffsetDateTime TIMESTAMP WITH TIME ZONE • JDBC atnaujintas, kad atitiktų JSR-310
kalendorius ◦ istoriškai netikslus ▪ katalikai - 1582 ▪ britai - 1752 ▪ rusai - 1917? • Reikalavimai ◦ JDK turi palaikyti įprastus kalendorius ◦ kalendorių palaikymas neturi pasunkinti API naudojimo ◦ nedviprasmiškas API
Islamo, Japonų, Kinų, Budizmo ir kiti • Pasiekiami pagal pavadinimą • Pasiekiami pagal BCP-47 lokalės išplėtimą ◦ th-TH-u-ca-buddhist • Datos – era, metai, mėnuo, diena ◦ mėnesių ilgiai & tvarka skiriasi • Leidžiamos tik datos variacijos ◦ ignoruojami kalendoriai pradedantys dieną skirtingu metu (saulėtekis/saulėlydis)
See ChronoLocalDate Javadoc paaiškinimą • Nesaugokite kalendoriaus visoje sistemoje • Kalendorius naudotojo profilio dalis • Konvertuokite atvaizduodami UI
laukais ◦ 6 metai, 2 mėnesiai ir 12 dienų • Panaudojimo pvz.: ◦ konferencijos ilgis – 5 dienos ◦ nėštumas – 9 mėnesiai • Java klasė - Period ◦ laukeliai metams, mėnesiams, dienoms • galima atimti/pridėti prie datos/laiko • Duration klasė - laiko ekvivalentas
objektą ◦ vengti Singleton ◦ Inversion of Control • Galima implementuoti subklasę ◦ taigi - kontroliuoti laiką :) // system millis, default time zone Instant instant = Instant.now(Clock.system()); LocalDate date = LocalDate.now(Clock.system()); // system millis, specified time zone ZoneId zone = ZoneId.of("Europe/Moscow"); LocalDate date = LocalDate.now(Clock.system(zone));
◦ inject Clock ◦ galima turėti 'stop time' subklasę testavimui public class MyForm { @Inject private Clock clock; // inject with Spring/Guice public void validate(LocalDate date) { if (date.isBefore(LocalDate.now(clock))) { // error } } }
šablonus ◦ kaip kad SimpleDateFormat ◦ taip pat sudėtingesnius formatus • pagrindinė formatavimo klasė - DateTimeFormatter • Pateikia daug įprastų formaterių
Pagal vienetus • Arba visą periodą/trukmę (Period/Duration) LocalDate date1 = LocalDate.of(2012, 3, 4); LocalDate date2 = LocalDate.of(2013, 1, 26); // Duration long days = DAYS.between(date1, date2); // Period Period period = Period.between(date1, date2);