úterý 10. dubna 2012

Hosting v cloudu a problém s časy

Dnes jsem se poprvé setkal s problémem různých časových pásem. Používám cloud platformu od CloudFoundry, který má servery nevím kde (asi v cloudu). Moje aplikace (stále ve vývoji) je jednoduchý rezervační systém. Zákazník si může kliknout na datum a zarezervovat si určitý druh procedury.
Když už jsem si myslel, že aplikace je jakž takž hotová, při ručním testování jsem si všiml, že časy jsou vždy posunuté o 2 hodiny.Problém byl v tom, že server má nastavený čas Coordinated Universal Time, což je čas v Greenwich a.k.a. GMT. Já jako testovací zákazník klikám v ČR (GMT +2:00).
Prozatím jsem tento problém vyřešil následně:

1. Rezervace ukládám do databáze v čase GMT (což je čas Prahy mínus 2 hodiny kvůli letnímu času).

TimeZone serverTimeZone = TimeZone.getDefault()
long serverTimezoneOffset = serverTimeZone.getOffset(new Date().time)
reservation.visitTime.setTime(reservation.visitTime.getTime() - serverTimezoneOffset)   // GMT čas

2.  Klient při vytváření rezervace nepotřebuje posílat svůj časový, protože se čas posílá v milisekundách od r. 1970, který bere ohled na časové zóny (což jsem nikdy předtím nevěnoval pozornost). Server tento čas pak jen převede do GMT.

3. Při zobrazení existují rezervace klientovi server musí znát časový posun klienta, aby správně vygenerovalo odpověď. Btw. lze to udělat i na straně klienta, kdy server pošle čas v GMT.
/show?reservationId=" + event.id + "&timezoneOffset=" + new Date().getTimezoneOffset()
Zde je menší problém s jinými čas. formáty v Javascript (JS) a Javou. getTimezoneOffset() v JS (strana klienta) vrací posun v minutách a tento posun je odvozen jako klientovo čas + posun = GMT. V Javě (strana serveru) získáme čas. posun takto: TimeZone.getDefault().getOffset(new Date().time). Skoro stejné, jen Java vrací rozdíl v milisekundách a čas je brán jako server čas - posun = GMT.

4. Když klient chce rezervovat proceduru, musím zkontrolovat, kteří z pracovníků jsou v uvedený čas dostupní. Z toho důvodu chci získat čas, na který klikl klient, na serveru.

Calendar clientTimeCal = new Date(params.long("date")).toCalendar() // převod na původní čas u klienta
int clientTimezoneOffset = -params.int("timezoneOffset") // v minutách
TimeZone serverTimeZone = TimeZone.getDefault()
long serverTimezoneOffset = serverTimeZone.getOffset(new Date().time)
clientTimeCal.setTimeInMillis(clientTimeCal.timeInMillis - serverTimezoneOffset)    // GMT čas
clientTimeCal.add(Calendar.MINUTE, clientTimezoneOffset)  // čas klienta
Klient pošle spolu s časem v ms i jeho časový posun ("timezoneOffset"). Na serveru prvně vytvořím instanci Calendar pomocí času v ms. Tato nová instance je však v času serveru, proto ho potřebuju převést prvně na GMT čas. To provedu pomocí zjištěného časového posunu serveru. Pak stačí jen dosadit do vzorce server čas - posun serveru = GMT. Čas v GMT musím pak převést na čas klienta. Jen tohle je trochu jiný vzorec GMT - posun klienta = klientovo čas. Proto mínus znaménko u -params.int("timezoneOffset") .


Žádné komentáře:

Okomentovat