Przyznaję, że ten wpis jest nieco wymuszony. Zasady Daj się poznać nakładają na mnie obowiązek wrzucania dwóch postów konkursowych tygodniowo. Tymczasem, choć informatycznie działo się u mnie sporo, projekt konkursowy w tym tygodniu leżał odłogiem. Dlaczego? Pomijając już przygody z nadgarstkiem – rozpoczęłam studia podyplomowe (przetwarzanie danych – big data)! Wczoraj, na moim dawnym wydziale, bawiłam się SQL-em, dzisiaj R. O R mam nawet anegdotę, ale na razie nie wymyśliłam pretekstu, żeby podciągnąć ją pod temat konkursowy.
Jeśli chodzi o moją aplikację Szafbook: nadal gnębi mnie kwestia dat. Pisałam już o tym, że HTML5 udostępnia pole wejściowe input
typu date
. Niektóre przeglądarki (Chrome!) wyświetlają przy nim elegancki widżet do wyboru daty z kalendarza. Inne nadal pozwalają/nakazują użytkownikowi samodzielne wpisanie wartości.
Nie byłam pewna, co z tym zrobić. Nie chcę rozbijać daty urodzenia na trzy osobne pola – za bardzo podoba mi się rozwiązanie z Chrome. Nie chcę wykrywać przeglądarki i podejmować decyzji w zależności od niej. Tak długo, jak będzie to możliwe, chcę się trzymać z dala od JavaScriptu.
Co tymczasowo wymyśliłam? Własny sposób tworzenia obiektu reprezentującego datę na podstawie danych wprowadzonych przez użytkownika, w którym pozwalam użytkownikowi na nieco większą elastyczność niż trzymanie się jednego sztywnego formatu daty.
Kod i uwagi do niego wklejam poniżej. Przy okazji zauważyłam kilka nowych (dla mnie) rzeczy w Javie. Najbardziej spodobały mi się grupy nazwane w wyrażeniach regularnych, wprowadzone w Javie 7. Dzięki ich istnieniu mogę wyciągnąć rok, miesiąc i dzień z tekstu dopasowanego do jednego z dwóch różnych wyrażeń regularnych. Bez nazw miałabym z tym większy problem, ponieważ numery grup (których trzeba było używać wcześniej) nie zgadzałyby się ze sobą (rok to grupa 1 w pierwszym wzorcu i grupa 3 w drugim).
W ogóle lubię wyrażenia regularne! 🙂 Na poprzednim blogu pojawił się kiedyś wpis o pułapkach regeksowych w Javie. Chyba przypomnę go w przyszłym tygodniu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
... @Controller public class UserController extends WebMvcConfigurerAdapter { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Calendar.class, new FlexibleCalendarEditor()); } ... } class FlexibleCalendarEditor extends PropertyEditorSupport { private static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); private static Pattern DATE_PATTERN_YMD = Pattern.compile("^(?<year>\\d{4})\\D(?<month>\\d{1,2})\\D(?<day>\\d{1,2})$"); private static Pattern DATE_PATTERN_DMY = Pattern.compile("^(?<day>\\d{1,2})\\D(?<month>\\d{1,2})\\D(?<year>\\d{4})$"); /** * Parse the calendar date from the given text. */ @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.length() == 0) { setValue(null); } else { Matcher matcherYMD = DATE_PATTERN_YMD.matcher(text); Matcher matcherDMY = DATE_PATTERN_DMY.matcher(text); Matcher m; if (matcherYMD.matches()) { m = matcherYMD; } else if (matcherDMY.matches()) { m = matcherDMY; } else { throw new IllegalArgumentException( "Could not parse date: " + text + ". Please use " + DATE_FORMAT.toPattern()); } int year = Integer.valueOf(m.group("year")).intValue(); int month = Integer.valueOf(m.group("month")).intValue(); int day = Integer.valueOf(m.group("day")).intValue(); if (year > 1900 && month < 13 && day < 32) { Calendar cal = Calendar.getInstance(); cal.set(year, month, day); setValue(cal); } else { throw new IllegalArgumentException( "Could not parse date: " + text + ". Please use " + DATE_FORMAT.toPattern()); } } } ... } |
- 8. Użycie mojego własnego kodu do zamiany wartości tekstowej na typ
Calendar
. - 17 i 18: Wyrażenia regularne mają umożliwić akceptację dat takich jak: 2016-04-10, 2016.04.10, 04/10/2014. Każde z wyrażeń definiuje 3 grupy nazwane:
year
,month
orazday
. - 39-41: Odwołuję się do grup, które są obecne niezależnie od tego, który z dwóch wzorców zadziałał.
- 43: Dość lekkie testy poprawności daty dopasowanej do wzorca. Zajrzałam do implementacji kalendarza. Podanie nieistniejącego dnia miesiąca nie powinno spowodować rzucenia wyjątku. Jeśli użytkownik będzie uparcie twierdził, że urodził się 30 lutego… Mało mnie interesuje, jaką datę ustawi mu system.
- 45: Ustawiam odpowiednią datę w moim kalendarzu. Początkowo chciałam mieć w tym miejscu obiekt typu
Date
, ale zorientowałam się, że tworzenie instancjiDate
w oparciu o rok, miesiąc i dzień od dawna nie jest zalecane.
Na koniec pozdrawiam z Warszawy! Przyjechałam z całą rodziną na konferencję 4Developers.
Możliwa inspiracja: http://orgmode.org/manual/The-date_002ftime-prompt.html#The-date_002ftime-prompt “The actions of the date/time prompt may seem complex, but I assure you they will grow on you, and you will start getting annoyed by pretty much any other way of entering a date/time out there” – i dokładnie tak jest!